Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17d13635 authored by Alexei Avshalom Lazar's avatar Alexei Avshalom Lazar Committed by Maya Erez
Browse files

wil6210: publish/receive WMI events/commands through nl



For general debug purposes added functionality for sending WMI
events and receiving WMI commands to/from user-space through vendor
commands.

Change-Id: I889d30bf1f060f75d7ae933735d1d959e53e513e
Signed-off-by: default avatarAlexei Avshalom Lazar <ailizaro@codeaurora.org>
parent e174bb43
Loading
Loading
Loading
Loading
+235 −0
Original line number Diff line number Diff line
@@ -64,6 +64,49 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
/* channel 4 not supported yet */
};

enum wil_nl_60g_cmd_type {
	NL_60G_CMD_FW_WMI,
	NL_60G_CMD_DEBUG,
	NL_60G_CMD_STATISTICS,
	NL_60G_CMD_REGISTER,
};

enum wil_nl_60g_evt_type {
	NL_60G_EVT_DRIVER_ERROR,
	NL_60G_EVT_FW_ERROR,
	NL_60G_EVT_FW_WMI,
	NL_60G_EVT_DRIVER_SHUTOWN,
	NL_60G_EVT_DRIVER_DEBUG_EVENT,
};

enum wil_nl_60g_debug_cmd {
	NL_60G_DBG_FORCE_WMI_SEND,
};

struct wil_nl_60g_send_receive_wmi {
	u32 cmd_id; /* enum wmi_command_id or enum wmi_event_id */
	u8 reserved[2];
	u8 dev_id; /* mid */
	u16 buf_len;
	u8 buf[0];
} __packed;

struct wil_nl_60g_event {
	u32 evt_type; /* wil_nl_60g_evt_type */
	u32 buf_len;
	u8 reserved[9];
	u8 buf[0];
} __packed;

struct wil_nl_60g_debug { /* NL_60G_CMD_DEBUG */
	u32 cmd_id; /* wil_nl_60g_debug_cmd */
} __packed;

struct wil_nl_60g_debug_force_wmi {
	struct wil_nl_60g_debug hdr;
	u32 enable;
} __packed;

/* Vendor id to be used in vendor specific command and events
 * to user space.
 * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
@@ -79,6 +122,8 @@ static struct ieee80211_channel wil_60ghz_channels[] = {

enum qca_wlan_vendor_attr_wil {
	QCA_ATTR_MAC_ADDR = 6,
	QCA_ATTR_FEATURE_FLAGS = 7,
	QCA_ATTR_TEST = 8,
	QCA_ATTR_PAD = 13,
	QCA_ATTR_TSF = 29,
	QCA_ATTR_DMG_RF_SECTOR_INDEX = 30,
@@ -90,6 +135,9 @@ enum qca_wlan_vendor_attr_wil {
	QCA_ATTR_WIL_MAX,
};

#define WIL_ATTR_60G_CMD_TYPE QCA_ATTR_FEATURE_FLAGS
#define WIL_ATTR_60G_BUF QCA_ATTR_TEST

enum qca_wlan_vendor_attr_dmg_rf_sector_type {
	QCA_ATTR_DMG_RF_SECTOR_TYPE_RX,
	QCA_ATTR_DMG_RF_SECTOR_TYPE_TX,
@@ -146,7 +194,14 @@ nla_policy wil_rf_sector_cfg_policy[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1] = {
	[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16] = { .type = NLA_U32 },
};

static const struct
nla_policy wil_nl_60g_policy[QCA_ATTR_WIL_MAX + 1] = {
	[WIL_ATTR_60G_CMD_TYPE] = { .type = NLA_U32 },
	[WIL_ATTR_60G_BUF] = { .type = NLA_BINARY },
};

enum qca_nl80211_vendor_subcmds {
	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
	QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
	QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
	QCA_NL80211_VENDOR_SUBCMD_FTM_ABORT_SESSION = 130,
@@ -178,6 +233,8 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
static int wil_brp_set_ant_limit(struct wiphy *wiphy, struct wireless_dev *wdev,
				 const void *data, int data_len);

static int wil_nl_60g_handle_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
				 const void *data, int data_len);
/* vendor specific commands */
static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
	{
@@ -259,6 +316,13 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
			 WIPHY_VENDOR_CMD_NEED_RUNNING,
		.doit = wil_brp_set_ant_limit
	},
	{
		.info.vendor_id = QCA_NL80211_VENDOR_ID,
		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_UNSPEC,
		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
			 WIPHY_VENDOR_CMD_NEED_NETDEV,
		.doit = wil_nl_60g_handle_cmd
	},
};

/* vendor specific events */
@@ -275,6 +339,10 @@ static const struct nl80211_vendor_cmd_info wil_nl80211_vendor_events[] = {
			.vendor_id = QCA_NL80211_VENDOR_ID,
			.subcmd = QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT
	},
	[QCA_NL80211_VENDOR_EVENT_UNSPEC_INDEX] = {
			.vendor_id = QCA_NL80211_VENDOR_ID,
			.subcmd = QCA_NL80211_VENDOR_SUBCMD_UNSPEC
	},
};

static struct ieee80211_supported_band wil_band_60ghz = {
@@ -2941,3 +3009,170 @@ static int wil_brp_set_ant_limit(struct wiphy *wiphy, struct wireless_dev *wdev,
	return wil_brp_wmi_set_ant_limit(wil, vif->mid, cid, limit_mode,
					 antenna_num_limit);
}

static int wil_nl_60g_handle_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
				 const void *data, int data_len)
{
	struct wil6210_priv *wil = wdev_to_wil(wdev);
	struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
	struct wil_nl_60g_send_receive_wmi *cmd;
	struct wil_nl_60g_debug_force_wmi debug_force_wmi;
	int rc, len;
	u32 wil_nl_60g_cmd_type, publish;

	rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
		       wil_nl_60g_policy, NULL);
	if (rc) {
		wil_err(wil, "Invalid nl_60g_cmd ATTR\n");
		return rc;
	}

	if (!tb[WIL_ATTR_60G_CMD_TYPE]) {
		wil_err(wil, "Invalid nl_60g_cmd type\n");
		return -EINVAL;
	}

	wil_nl_60g_cmd_type = nla_get_u32(tb[WIL_ATTR_60G_CMD_TYPE]);

	switch (wil_nl_60g_cmd_type) {
	case NL_60G_CMD_REGISTER:
		if (!tb[WIL_ATTR_60G_BUF]) {
			wil_err(wil, "Invalid nl_60g_cmd spec\n");
			return -EINVAL;
		}

		len = nla_len(tb[WIL_ATTR_60G_BUF]);
		if (len != sizeof(publish)) {
			wil_err(wil, "cmd buffer wrong len %d\n", len);
			return -EINVAL;
		}
		memcpy(&publish, nla_data(tb[WIL_ATTR_60G_BUF]), len);
		wil->publish_nl_evt = publish;

		wil_dbg_wmi(wil, "Publish wmi event %s\n",
			    publish ? "enabled" : "disabled");
		break;
	case NL_60G_CMD_DEBUG:
		if (!tb[WIL_ATTR_60G_BUF]) {
			wil_err(wil, "Invalid nl_60g_cmd spec\n");
			return -EINVAL;
		}

		len = nla_len(tb[WIL_ATTR_60G_BUF]);
		if (len < sizeof(struct wil_nl_60g_debug)) {
			wil_err(wil, "cmd buffer too short %d\n", len);
			return -EINVAL;
		}

		memcpy(&debug_force_wmi, nla_data(tb[WIL_ATTR_60G_BUF]),
		       sizeof(struct wil_nl_60g_debug));

		switch (debug_force_wmi.hdr.cmd_id) {
		case NL_60G_DBG_FORCE_WMI_SEND:
			if (len != sizeof(debug_force_wmi)) {
				wil_err(wil, "cmd buffer wrong len %d\n", len);
				return -EINVAL;
			}

			memcpy(&debug_force_wmi, nla_data(tb[WIL_ATTR_60G_BUF]),
			       sizeof(debug_force_wmi));
			wil->force_wmi_send = debug_force_wmi.enable;

			wil_dbg_wmi(wil, "force sending wmi commands %d\n",
				    wil->force_wmi_send);
			break;
		default:
			rc = -EINVAL;
			wil_err(wil, "invalid debug_cmd id %d",
				debug_force_wmi.hdr.cmd_id);
		}
		break;
	case NL_60G_CMD_FW_WMI:
		if (!tb[WIL_ATTR_60G_BUF]) {
			wil_err(wil, "Invalid nl_60g_cmd spec\n");
			return -EINVAL;
		}

		len = nla_len(tb[WIL_ATTR_60G_BUF]);
		if (len < offsetof(struct wil_nl_60g_send_receive_wmi, buf)) {
			wil_err(wil, "wmi cmd buffer too small\n");
			return -EINVAL;
		}

		cmd = kmalloc(len, GFP_KERNEL);
		if (!cmd)
			return -ENOMEM;

		memcpy(cmd, nla_data(tb[WIL_ATTR_60G_BUF]), (unsigned int)len);

		wil_dbg_wmi(wil, "sending user-space command (0x%04x) [%d]\n",
			    cmd->cmd_id, cmd->buf_len);

		if (wil->force_wmi_send)
			rc = wmi_force_send(wil, cmd->cmd_id, cmd->dev_id,
					    cmd->buf, cmd->buf_len);
		else
			rc = wmi_send(wil, cmd->cmd_id, cmd->dev_id,
				      cmd->buf, cmd->buf_len);

		kfree(cmd);
		break;
	default:
		rc = -EINVAL;
		wil_err(wil, "invalid nl_60g_cmd type %d", wil_nl_60g_cmd_type);
	}

	return rc;
}

void wil_nl_60g_receive_wmi_evt(struct wil6210_priv *wil, u8 *cmd, int len)
{
	struct sk_buff *vendor_event = NULL;
	struct wil_nl_60g_event *evt;
	struct wil_nl_60g_send_receive_wmi *wmi_buf;
	struct wmi_cmd_hdr *wmi_hdr = (struct wmi_cmd_hdr *)cmd;
	int data_len;

	if (!wil->publish_nl_evt)
		return;

	wil_dbg_wmi(wil, "report wmi event to user-space (0x%04x) [%d]\n",
		    le16_to_cpu(wmi_hdr->command_id), len);

	data_len = len - sizeof(struct wmi_cmd_hdr);

	evt = kzalloc(sizeof(*evt) + sizeof(*wmi_buf) + data_len, GFP_KERNEL);
	if (!evt)
		return;

	evt->evt_type = NL_60G_EVT_FW_WMI;
	evt->buf_len = sizeof(*wmi_buf) + data_len;

	wmi_buf = (struct wil_nl_60g_send_receive_wmi *)evt->buf;

	wmi_buf->cmd_id = le16_to_cpu(wmi_hdr->command_id);
	wmi_buf->dev_id = wmi_hdr->mid;
	wmi_buf->buf_len = data_len;
	memcpy(wmi_buf->buf, cmd + sizeof(struct wmi_cmd_hdr), data_len);

	vendor_event = cfg80211_vendor_event_alloc(
				wil_to_wiphy(wil),
				NULL,
				data_len + 4 + NLMSG_HDRLEN +
				sizeof(*evt) + sizeof(*wmi_buf),
				QCA_NL80211_VENDOR_EVENT_UNSPEC_INDEX,
				GFP_KERNEL);
	if (!vendor_event)
		goto out;

	if (nla_put(vendor_event, WIL_ATTR_60G_BUF,
		    sizeof(*evt) + sizeof(*wmi_buf) + data_len, evt)) {
		wil_err(wil, "failed to fill WIL_ATTR_60G_BUF\n");
		goto out;
	}

	cfg80211_vendor_event(vendor_event, GFP_KERNEL);

out:
	kfree(evt);
}
+2 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
@@ -417,6 +417,7 @@ enum qca_nl80211_vendor_events_index {
	QCA_NL80211_VENDOR_EVENT_FTM_MEAS_RESULT_INDEX,
	QCA_NL80211_VENDOR_EVENT_FTM_SESSION_DONE_INDEX,
	QCA_NL80211_VENDOR_EVENT_AOA_MEAS_RESULT_INDEX,
	QCA_NL80211_VENDOR_EVENT_UNSPEC_INDEX,
};

/* measurement parameters. Specified for each peer as part
+2 −0
Original line number Diff line number Diff line
@@ -1528,6 +1528,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)

	wmi_event_flush(wil);

	wil->force_wmi_send = false;

	flush_workqueue(wil->wq_service);
	flush_workqueue(wil->wmi_wq);

+6 −0
Original line number Diff line number Diff line
@@ -996,6 +996,9 @@ struct wil6210_priv {
	bool secured_boot;
	u8 boot_config;

	bool publish_nl_evt; /* deliver WMI events to user space */
	bool force_wmi_send; /* allow WMI command while FW in sysassert */

	/* relevant only for eDMA */
	bool amsdu_en;
};
@@ -1163,6 +1166,8 @@ void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
		 struct wil6210_mbox_hdr *hdr);
int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len);
int wmi_force_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf,
		   u16 len);
void wmi_recv_cmd(struct wil6210_priv *wil);
int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
	     u16 reply_id, void *reply, u16 reply_size, int to_msec);
@@ -1343,6 +1348,7 @@ void wil_ftm_evt_per_dest_res(struct wil6210_vif *vif,
void wil_aoa_evt_meas(struct wil6210_vif *vif,
		      struct wmi_aoa_meas_event *evt,
		      int len);
void wil_nl_60g_receive_wmi_evt(struct wil6210_priv *wil, u8 *cmd, int len);
/* link loss */
int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
				const u8 *addr,
+18 −5
Original line number Diff line number Diff line
@@ -605,7 +605,7 @@ static const char *eventid2name(u16 eventid)
}

static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid,
		      void *buf, u16 len)
		      void *buf, u16 len, bool force_send)
{
	struct {
		struct wil6210_mbox_hdr hdr;
@@ -637,7 +637,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid,

	might_sleep();

	if (!test_bit(wil_status_fwready, wil->status)) {
	if (!test_bit(wil_status_fwready, wil->status) && !force_send) {
		wil_err(wil, "WMI: cannot send command while FW not ready\n");
		return -EAGAIN;
	}
@@ -676,7 +676,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid,
	wil_dbg_wmi(wil, "Head 0x%08x -> 0x%08x\n", r->head, next_head);
	/* wait till FW finish with previous command */
	for (retry = 5; retry > 0; retry--) {
		if (!test_bit(wil_status_fwready, wil->status)) {
		if (!test_bit(wil_status_fwready, wil->status) && !force_send) {
			wil_err(wil, "WMI: cannot send command while FW not ready\n");
			rc = -EAGAIN;
			goto out;
@@ -731,7 +731,19 @@ int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len)
	int rc;

	mutex_lock(&wil->wmi_mutex);
	rc = __wmi_send(wil, cmdid, mid, buf, len);
	rc = __wmi_send(wil, cmdid, mid, buf, len, false);
	mutex_unlock(&wil->wmi_mutex);

	return rc;
}

int wmi_force_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf,
		   u16 len)
{
	int rc;

	mutex_lock(&wil->wmi_mutex);
	rc = __wmi_send(wil, cmdid, mid, buf, len, true);
	mutex_unlock(&wil->wmi_mutex);

	return rc;
@@ -1471,6 +1483,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
			u16 id = le16_to_cpu(wmi->command_id);
			u8 mid = wmi->mid;
			u32 tstamp = le32_to_cpu(wmi->fw_timestamp);
			wil_nl_60g_receive_wmi_evt(wil, cmd, len);
			if (test_bit(wil_status_resuming, wil->status)) {
				if (id == WMI_TRAFFIC_RESUME_EVENTID)
					clear_bit(wil_status_resuming,
@@ -1546,7 +1559,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
	reinit_completion(&wil->wmi_call);
	spin_unlock(&wil->wmi_ev_lock);

	rc = __wmi_send(wil, cmdid, mid, buf, len);
	rc = __wmi_send(wil, cmdid, mid, buf, len, false);
	if (rc)
		goto out;