Merge "wil6210: publish/receive WMI events/commands through nl"

This commit is contained in:
qctecmdr 2019-12-17 02:42:51 -08:00 • committed by Gerrit - the friendly Code Review server
commit 334e2939d9
6 changed files with 531 additions and 22 deletions

View file

@ -14,6 +14,7 @@
#include "fw.h"
#define WIL_MAX_ROC_DURATION_MS 5000
#define CTRY_CHINA "CN"
#define WIL_EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1))
#define WIL_EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2))
@ -41,6 +42,10 @@ static struct wiphy_wowlan_support wil_wowlan_support = {
};
#endif
static bool country_specific_board_file;
module_param(country_specific_board_file, bool, 0444);
MODULE_PARM_DESC(country_specific_board_file, " switch board file upon regulatory domain change (Default: false)");
static bool ignore_reg_hints = true;
module_param(ignore_reg_hints, bool, 0444);
MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)");
@ -54,6 +59,9 @@ MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)
.max_power = 40, \
}
#define WIL_BRP_ANT_LIMIT_MIN (1)
#define WIL_BRP_ANT_LIMIT_MAX (27)
static struct ieee80211_channel wil_60ghz_channels[] = {
CHAN60G(1, 0),
CHAN60G(2, 0),
@ -94,6 +102,49 @@ static int wil_tx_cb_mode_to_n_bonded(u8 cb_mode)
}
}
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;
static void
wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len)
{
@ -147,17 +198,24 @@ void update_supported_bands(struct wil6210_priv *wil)
#define WIL_MAX_RF_SECTORS (128)
#define WIL_CID_ALL (0xff)
enum qca_wlan_vendor_attr_rf_sector {
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,
QCA_ATTR_DMG_RF_SECTOR_TYPE = 31,
QCA_ATTR_DMG_RF_MODULE_MASK = 32,
QCA_ATTR_DMG_RF_SECTOR_CFG = 33,
QCA_ATTR_DMG_RF_SECTOR_MAX,
QCA_ATTR_BRP_ANT_LIMIT_MODE = 38,
QCA_ATTR_BRP_ANT_NUM_LIMIT = 39,
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,
@ -180,8 +238,22 @@ enum qca_wlan_vendor_attr_dmg_rf_sector_cfg {
QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1
};
enum qca_wlan_vendor_attr_brp_ant_limit_mode {
QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE,
QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_EFFECTIVE,
QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_FORCE,
QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODES_NUM
};
static const struct
nla_policy wil_rf_sector_policy[QCA_ATTR_DMG_RF_SECTOR_MAX + 1] = {
nla_policy wil_brp_ant_limit_policy[QCA_ATTR_WIL_MAX + 1] = {
[QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN },
[QCA_ATTR_BRP_ANT_NUM_LIMIT] = { .type = NLA_U8 },
[QCA_ATTR_BRP_ANT_LIMIT_MODE] = { .type = NLA_U8 },
};
static const struct
nla_policy wil_rf_sector_policy[QCA_ATTR_WIL_MAX + 1] = {
[QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN },
[QCA_ATTR_DMG_RF_SECTOR_INDEX] = { .type = NLA_U16 },
[QCA_ATTR_DMG_RF_SECTOR_TYPE] = { .type = NLA_U8 },
@ -200,7 +272,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,
@ -214,6 +293,7 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140,
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT = 153,
};
static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
@ -228,7 +308,11 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
static int wil_rf_sector_set_selected(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data, int data_len);
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[] = {
{
@ -307,6 +391,20 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
.policy = wil_rf_sector_policy,
.doit = wil_rf_sector_set_selected
},
{
.info.vendor_id = QCA_NL80211_VENDOR_ID,
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BRP_SET_ANT_LIMIT,
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
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 */
@ -323,6 +421,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_EVENT_UNSPEC_INDEX] = {
.vendor_id = QCA_NL80211_VENDOR_ID,
.subcmd = QCA_NL80211_VENDOR_SUBCMD_UNSPEC
},
};
static struct ieee80211_supported_band wil_band_60ghz = {
@ -2604,6 +2706,65 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
static int wil_switch_board_file(struct wil6210_priv *wil,
const u8 *new_regdomain)
{
int rc = 0;
if (!country_specific_board_file)
return 0;
if (memcmp(wil->regdomain, CTRY_CHINA, 2) == 0) {
wil_info(wil, "moving out of China reg domain, use default board file\n");
wil->board_file_country[0] = '\0';
} else if (memcmp(new_regdomain, CTRY_CHINA, 2) == 0) {
wil_info(wil, "moving into China reg domain, use country specific board file\n");
strlcpy(wil->board_file_country, CTRY_CHINA,
sizeof(wil->board_file_country));
} else {
return 0;
}
/* need to switch board file - reset the device */
mutex_lock(&wil->mutex);
if (!wil_has_active_ifaces(wil, true, false) ||
wil_is_recovery_blocked(wil))
/* new board file will be used in next FW load */
goto out;
__wil_down(wil);
rc = __wil_up(wil);
out:
mutex_unlock(&wil->mutex);
return rc;
}
static void wil_cfg80211_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
int rc;
wil_info(wil, "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n",
request->alpha2[0], request->alpha2[1],
request->intersect ? " intersect" : "",
request->processed ? " processed" : "",
request->initiator, request->user_reg_hint_type);
if (memcmp(wil->regdomain, request->alpha2, 2) == 0)
/* reg domain did not change */
return;
rc = wil_switch_board_file(wil, request->alpha2);
if (rc)
wil_err(wil, "switch board file failed %d\n", rc);
memcpy(wil->regdomain, request->alpha2, 2);
}
static int
wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie)
@ -2724,6 +2885,8 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->mgmt_stypes = wil_mgmt_stypes;
wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
wiphy->reg_notifier = wil_cfg80211_reg_notify;
wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands);
wiphy->vendor_commands = wil_nl80211_vendor_commands;
wiphy->vendor_events = wil_nl80211_vendor_events;
@ -2894,7 +3057,7 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
struct wil6210_priv *wil = wdev_to_wil(wdev);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u16 sector_index;
u8 sector_type;
u32 rf_modules_vec;
@ -2913,7 +3076,7 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
rc = nla_parse_deprecated(tb, QCA_ATTR_WIL_MAX, data,
data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@ -3015,7 +3178,7 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
struct wil6210_priv *wil = wdev_to_wil(wdev);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc, tmp;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1];
u16 sector_index, rf_module_index;
u8 sector_type;
@ -3033,7 +3196,7 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
rc = nla_parse_deprecated(tb, QCA_ATTR_WIL_MAX, data,
data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@ -3127,7 +3290,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
struct wil6210_priv *wil = wdev_to_wil(wdev);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u8 sector_type, mac_addr[ETH_ALEN];
int cid = 0;
struct wmi_get_selected_rf_sector_index_cmd cmd;
@ -3142,7 +3305,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
rc = nla_parse_deprecated(tb, QCA_ATTR_WIL_MAX, data,
data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@ -3242,7 +3405,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
struct wil6210_priv *wil = wdev_to_wil(wdev);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
int rc;
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u16 sector_index;
u8 sector_type, mac_addr[ETH_ALEN], i;
int cid = 0;
@ -3250,7 +3413,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -EOPNOTSUPP;
rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data,
rc = nla_parse_deprecated(tb, QCA_ATTR_WIL_MAX, data,
data_len, wil_rf_sector_policy, NULL);
if (rc) {
wil_err(wil, "Invalid rf sector ATTR\n");
@ -3332,3 +3495,261 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
return rc;
}
static int
wil_brp_wmi_set_ant_limit(struct wil6210_priv *wil, u8 mid, u8 cid,
u8 limit_mode, u8 antenna_num_limit)
{
int rc;
struct wmi_brp_set_ant_limit_cmd cmd = {
.cid = cid,
.limit_mode = limit_mode,
.ant_limit = antenna_num_limit,
};
struct {
struct wmi_cmd_hdr wmi;
struct wmi_brp_set_ant_limit_event evt;
} __packed reply;
reply.evt.status = WMI_FW_STATUS_FAILURE;
rc = wmi_call(wil, WMI_BRP_SET_ANT_LIMIT_CMDID, mid, &cmd, sizeof(cmd),
WMI_BRP_SET_ANT_LIMIT_EVENTID, &reply,
sizeof(reply), 250);
if (rc)
return rc;
if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "brp set antenna limit failed with status %d\n",
reply.evt.status);
rc = -EINVAL;
}
return rc;
}
static int wil_brp_set_ant_limit(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int data_len)
{
struct wil6210_priv *wil = wdev_to_wil(wdev);
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
struct nlattr *tb[QCA_ATTR_WIL_MAX + 1];
u8 mac_addr[ETH_ALEN];
u8 antenna_num_limit = 0;
u8 limit_mode;
int cid = 0;
int rc;
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
return -ENOTSUPP;
rc = nla_parse(tb, QCA_ATTR_WIL_MAX, data, data_len,
wil_brp_ant_limit_policy, NULL);
if (rc) {
wil_err(wil, "Invalid ant limit ATTR\n");
return rc;
}
if (!tb[QCA_ATTR_BRP_ANT_LIMIT_MODE] || !tb[QCA_ATTR_MAC_ADDR]) {
wil_err(wil, "Invalid antenna limit spec\n");
return -EINVAL;
}
limit_mode = nla_get_u8(tb[QCA_ATTR_BRP_ANT_LIMIT_MODE]);
if (limit_mode >= QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODES_NUM) {
wil_err(wil, "Invalid limit mode %d\n", limit_mode);
return -EINVAL;
}
if (limit_mode != QCA_WLAN_VENDOR_ATTR_BRP_ANT_LIMIT_MODE_DISABLE) {
if (!tb[QCA_ATTR_BRP_ANT_NUM_LIMIT]) {
wil_err(wil, "Invalid limit number\n");
return -EINVAL;
}
antenna_num_limit = nla_get_u8(tb[QCA_ATTR_BRP_ANT_NUM_LIMIT]);
if (antenna_num_limit > WIL_BRP_ANT_LIMIT_MAX ||
antenna_num_limit < WIL_BRP_ANT_LIMIT_MIN) {
wil_err(wil, "Invalid number of antenna limit: %d\n",
antenna_num_limit);
return -EINVAL;
}
}
ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
cid = wil_find_cid(wil, vif->mid, mac_addr);
if (cid < 0) {
wil_err(wil, "invalid MAC address %pM\n", mac_addr);
return -ENOENT;
}
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_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);
}

View file

@ -401,6 +401,7 @@ enum qca_events_index {
QCA_EVENT_FTM_MEAS_RESULT_INDEX,
QCA_EVENT_FTM_SESSION_DONE_INDEX,
QCA_EVENT_AOA_MEAS_RESULT_INDEX,
QCA_EVENT_UNSPEC_INDEX,
};
/* measurement parameters. Specified for each peer as part

View file

@ -832,6 +832,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
wmi_event_flush(wil);
destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq);
kfree(wil->board_file);
kfree(wil->brd_info);
}
@ -1291,6 +1292,8 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len)
{
const char *board_file;
const char *ext;
int prefix_len;
const char *wil_talyn_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
WIL_FW_NAME_TALYN;
@ -1306,7 +1309,21 @@ void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len)
board_file = WIL_BOARD_FILE_NAME;
}
strlcpy(buf, board_file, len);
if (wil->board_file_country[0] == '\0') {
strlcpy(buf, board_file, len);
return;
}
/* use country specific board file */
if (len < strlen(board_file) + 4 /* for _XX and terminating null */)
return;
ext = strrchr(board_file, '.');
prefix_len = (ext ? ext - board_file : strlen(board_file));
snprintf(buf, len, "%.*s_%.2s",
prefix_len, board_file, wil->board_file_country);
if (ext)
strlcat(buf, ext, len);
}
static int wil_get_bl_info(struct wil6210_priv *wil)
@ -1674,6 +1691,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);
@ -1707,16 +1726,16 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
if (load_fw) {
char board_file[WIL_BOARD_FILE_MAX_NAMELEN];
if (wil->secured_boot) {
wil_err(wil, "secured boot is not supported\n");
return -ENOTSUPP;
}
board_file[0] = '\0';
wil_get_board_file(wil, board_file, sizeof(board_file));
wil_info(wil, "Use firmware <%s> + board <%s>\n",
wil->wil_fw_name, board_file);
if (wil->secured_boot) {
wil_err(wil, "secured boot is not supported\n");
return -ENOTSUPP;
}
if (!no_flash)
wil_bl_prepare_halt(wil);

View file

@ -81,6 +81,50 @@ ftm_txrx_offset_store(struct device *dev,
static DEVICE_ATTR_RW(ftm_txrx_offset);
static ssize_t
board_file_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wil6210_priv *wil = dev_get_drvdata(dev);
wil_get_board_file(wil, buf, PAGE_SIZE);
strlcat(buf, "\n", PAGE_SIZE);
return strlen(buf);
}
static ssize_t
board_file_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct wil6210_priv *wil = dev_get_drvdata(dev);
size_t len;
mutex_lock(&wil->mutex);
kfree(wil->board_file);
wil->board_file = NULL;
len = count;
if (buf[count - 1] == '\n')
len--;
len = strnlen(buf, len);
if (len > 0) {
wil->board_file = kmalloc(len + 1, GFP_KERNEL);
if (!wil->board_file) {
mutex_unlock(&wil->mutex);
return -ENOMEM;
}
strlcpy(wil->board_file, buf, len + 1);
}
mutex_unlock(&wil->mutex);
return count;
}
static DEVICE_ATTR_RW(board_file);
static ssize_t
thermal_throttling_show(struct device *dev, struct device_attribute *attr,
char *buf)
@ -291,6 +335,7 @@ static DEVICE_ATTR_RW(snr_thresh);
static struct attribute *wil6210_sysfs_entries[] = {
&dev_attr_ftm_txrx_offset.attr,
&dev_attr_board_file.attr,
&dev_attr_thermal_throttling.attr,
&dev_attr_fst_link_loss.attr,
&dev_attr_snr_thresh.attr,

View file

@ -934,6 +934,7 @@ struct wil6210_priv {
const char *hw_name;
const char *wil_fw_name;
char *board_file;
char board_file_country[3]; /* alpha2 */
u32 num_of_brd_entries;
struct wil_brd_info *brd_info;
DECLARE_BITMAP(hw_capa, hw_capa_last);
@ -1045,6 +1046,9 @@ struct wil6210_priv {
short direct;
} snr_thresh;
/* current reg domain configured in kernel */
char regdomain[3]; /* alpha2 */
struct notifier_block pm_notify;
bool suspend_resp_rcvd;
@ -1056,6 +1060,9 @@ struct wil6210_priv {
u32 rgf_ucode_assert_code_addr;
u32 iccm_base;
u8 publish_nl_evt; /* deliver WMI events to user space */
u8 force_wmi_send; /* allow WMI command while FW in sysassert */
/* relevant only for eDMA */
bool use_compressed_rx_status;
u32 rx_status_ring_order;
@ -1247,6 +1254,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);
@ -1440,6 +1449,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,

View file

@ -631,7 +631,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;
@ -663,7 +663,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;
}
@ -702,7 +702,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;
@ -757,7 +757,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;
@ -1988,6 +2000,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,
@ -2064,7 +2077,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
reinit_completion(&wil->wmi_call);
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
rc = __wmi_send(wil, cmdid, mid, buf, len);
rc = __wmi_send(wil, cmdid, mid, buf, len, false);
if (rc)
goto out;