Merge "wil6210: support devices with different PCIe bar size"
This commit is contained in:
commit
1d0af2abf0
5 changed files with 566 additions and 11 deletions
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <net/netlink.h>
|
||||
#include "wil6210.h"
|
||||
#include "wmi.h"
|
||||
#include "ftm.h"
|
||||
|
@ -56,6 +57,62 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
|
|||
|
||||
#define QCA_NL80211_VENDOR_ID 0x001374
|
||||
|
||||
#define WIL_MAX_RF_SECTORS (128)
|
||||
#define WIL_CID_ALL (0xff)
|
||||
|
||||
enum qca_wlan_vendor_attr_rf_sector {
|
||||
QCA_ATTR_MAC_ADDR = 6,
|
||||
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,
|
||||
};
|
||||
|
||||
enum qca_wlan_vendor_attr_dmg_rf_sector_type {
|
||||
QCA_ATTR_DMG_RF_SECTOR_TYPE_RX,
|
||||
QCA_ATTR_DMG_RF_SECTOR_TYPE_TX,
|
||||
QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX
|
||||
};
|
||||
|
||||
enum qca_wlan_vendor_attr_dmg_rf_sector_cfg {
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_INVALID = 0,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16,
|
||||
|
||||
/* keep last */
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST,
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_MAX =
|
||||
QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1
|
||||
};
|
||||
|
||||
static const struct
|
||||
nla_policy wil_rf_sector_policy[QCA_ATTR_DMG_RF_SECTOR_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 },
|
||||
[QCA_ATTR_DMG_RF_MODULE_MASK] = { .type = NLA_U32 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static const struct
|
||||
nla_policy wil_rf_sector_cfg_policy[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1] = {
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] = { .type = NLA_U8 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] = { .type = NLA_U32 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] = { .type = NLA_U32 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] = { .type = NLA_U32 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] = { .type = NLA_U32 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] = { .type = NLA_U32 },
|
||||
[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
enum qca_nl80211_vendor_subcmds {
|
||||
QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
|
||||
QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
|
||||
|
@ -66,8 +123,25 @@ enum qca_nl80211_vendor_subcmds {
|
|||
QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
|
||||
QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
|
||||
QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
|
||||
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139,
|
||||
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,
|
||||
};
|
||||
|
||||
static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
static int wil_rf_sector_get_selected(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len);
|
||||
static int wil_rf_sector_set_selected(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[] = {
|
||||
{
|
||||
|
@ -112,6 +186,36 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
|
|||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_aoa_abort_measurement
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_rf_sector_get_cfg
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_rf_sector_set_cfg
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd =
|
||||
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_rf_sector_get_selected
|
||||
},
|
||||
{
|
||||
.info.vendor_id = QCA_NL80211_VENDOR_ID,
|
||||
.info.subcmd =
|
||||
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR,
|
||||
.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
|
||||
WIPHY_VENDOR_CMD_NEED_RUNNING,
|
||||
.doit = wil_rf_sector_set_selected
|
||||
},
|
||||
};
|
||||
|
||||
/* vendor specific events */
|
||||
|
@ -1838,3 +1942,449 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
|
|||
kfree(p2p_wdev);
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_rf_sector_status_to_rc(u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case WMI_RF_SECTOR_STATUS_SUCCESS:
|
||||
return 0;
|
||||
case WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR:
|
||||
return -EINVAL;
|
||||
case WMI_RF_SECTOR_STATUS_BUSY_ERROR:
|
||||
return -EAGAIN;
|
||||
case WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR:
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wdev_to_wil(wdev);
|
||||
int rc;
|
||||
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
|
||||
u16 sector_index;
|
||||
u8 sector_type;
|
||||
u32 rf_modules_vec;
|
||||
struct wmi_get_rf_sector_params_cmd cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_get_rf_sector_params_done_event evt;
|
||||
} __packed reply;
|
||||
struct sk_buff *msg;
|
||||
struct nlattr *nl_cfgs, *nl_cfg;
|
||||
u32 i;
|
||||
struct wmi_rf_sector_info *si;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
|
||||
wil_rf_sector_policy);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid rf sector ATTR\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] ||
|
||||
!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] ||
|
||||
!tb[QCA_ATTR_DMG_RF_MODULE_MASK]) {
|
||||
wil_err(wil, "Invalid rf sector spec\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_index = nla_get_u16(
|
||||
tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]);
|
||||
if (sector_index >= WIL_MAX_RF_SECTORS) {
|
||||
wil_err(wil, "Invalid sector index %d\n", sector_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
|
||||
if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
|
||||
wil_err(wil, "Invalid sector type %d\n", sector_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rf_modules_vec = nla_get_u32(
|
||||
tb[QCA_ATTR_DMG_RF_MODULE_MASK]);
|
||||
if (rf_modules_vec >= BIT(WMI_MAX_RF_MODULES_NUM)) {
|
||||
wil_err(wil, "Invalid rf module mask 0x%x\n", rf_modules_vec);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd.sector_idx = cpu_to_le16(sector_index);
|
||||
cmd.sector_type = sector_type;
|
||||
cmd.rf_modules_vec = rf_modules_vec & 0xFF;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID,
|
||||
&reply, sizeof(reply),
|
||||
500);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (reply.evt.status) {
|
||||
wil_err(wil, "get rf sector cfg failed with status %d\n",
|
||||
reply.evt.status);
|
||||
return wil_rf_sector_status_to_rc(reply.evt.status);
|
||||
}
|
||||
|
||||
msg = cfg80211_vendor_cmd_alloc_reply_skb(
|
||||
wiphy, 64 * WMI_MAX_RF_MODULES_NUM);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nla_put_u64(msg, QCA_ATTR_TSF,
|
||||
le64_to_cpu(reply.evt.tsf)))
|
||||
goto nla_put_failure;
|
||||
|
||||
nl_cfgs = nla_nest_start(msg, QCA_ATTR_DMG_RF_SECTOR_CFG);
|
||||
if (!nl_cfgs)
|
||||
goto nla_put_failure;
|
||||
for (i = 0; i < WMI_MAX_RF_MODULES_NUM; i++) {
|
||||
if (!(rf_modules_vec & BIT(i)))
|
||||
continue;
|
||||
nl_cfg = nla_nest_start(msg, i);
|
||||
if (!nl_cfg)
|
||||
goto nla_put_failure;
|
||||
si = &reply.evt.sectors_info[i];
|
||||
if (nla_put_u8(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX,
|
||||
i) ||
|
||||
nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0,
|
||||
le32_to_cpu(si->etype0)) ||
|
||||
nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1,
|
||||
le32_to_cpu(si->etype1)) ||
|
||||
nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2,
|
||||
le32_to_cpu(si->etype2)) ||
|
||||
nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI,
|
||||
le32_to_cpu(si->psh_hi)) ||
|
||||
nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO,
|
||||
le32_to_cpu(si->psh_lo)) ||
|
||||
nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16,
|
||||
le32_to_cpu(si->dtype_swch_off)))
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(msg, nl_cfg);
|
||||
}
|
||||
|
||||
nla_nest_end(msg, nl_cfgs);
|
||||
rc = cfg80211_vendor_cmd_reply(msg);
|
||||
return rc;
|
||||
nla_put_failure:
|
||||
kfree_skb(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wdev_to_wil(wdev);
|
||||
int rc, tmp;
|
||||
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
|
||||
struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1];
|
||||
u16 sector_index, rf_module_index;
|
||||
u8 sector_type;
|
||||
u32 rf_modules_vec = 0;
|
||||
struct wmi_set_rf_sector_params_cmd cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_set_rf_sector_params_done_event evt;
|
||||
} __packed reply;
|
||||
struct nlattr *nl_cfg;
|
||||
struct wmi_rf_sector_info *si;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
|
||||
wil_rf_sector_policy);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid rf sector ATTR\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] ||
|
||||
!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] ||
|
||||
!tb[QCA_ATTR_DMG_RF_SECTOR_CFG]) {
|
||||
wil_err(wil, "Invalid rf sector spec\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_index = nla_get_u16(
|
||||
tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]);
|
||||
if (sector_index >= WIL_MAX_RF_SECTORS) {
|
||||
wil_err(wil, "Invalid sector index %d\n", sector_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
|
||||
if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
|
||||
wil_err(wil, "Invalid sector type %d\n", sector_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
cmd.sector_idx = cpu_to_le16(sector_index);
|
||||
cmd.sector_type = sector_type;
|
||||
nla_for_each_nested(nl_cfg, tb[QCA_ATTR_DMG_RF_SECTOR_CFG],
|
||||
tmp) {
|
||||
rc = nla_parse_nested(tb2, QCA_ATTR_DMG_RF_SECTOR_CFG_MAX,
|
||||
nl_cfg, wil_rf_sector_cfg_policy);
|
||||
if (rc) {
|
||||
wil_err(wil, "invalid sector cfg\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] ||
|
||||
!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] ||
|
||||
!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] ||
|
||||
!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] ||
|
||||
!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] ||
|
||||
!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] ||
|
||||
!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16]) {
|
||||
wil_err(wil, "missing cfg params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rf_module_index = nla_get_u8(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX]);
|
||||
if (rf_module_index >= WMI_MAX_RF_MODULES_NUM) {
|
||||
wil_err(wil, "invalid RF module index %d\n",
|
||||
rf_module_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
rf_modules_vec |= BIT(rf_module_index);
|
||||
si = &cmd.sectors_info[rf_module_index];
|
||||
si->etype0 = cpu_to_le32(nla_get_u32(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0]));
|
||||
si->etype1 = cpu_to_le32(nla_get_u32(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1]));
|
||||
si->etype2 = cpu_to_le32(nla_get_u32(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2]));
|
||||
si->psh_hi = cpu_to_le32(nla_get_u32(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI]));
|
||||
si->psh_lo = cpu_to_le32(nla_get_u32(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO]));
|
||||
si->dtype_swch_off = cpu_to_le32(nla_get_u32(
|
||||
tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16]));
|
||||
}
|
||||
|
||||
cmd.rf_modules_vec = rf_modules_vec & 0xFF;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd),
|
||||
WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID,
|
||||
&reply, sizeof(reply),
|
||||
500);
|
||||
if (rc)
|
||||
return rc;
|
||||
return wil_rf_sector_status_to_rc(reply.evt.status);
|
||||
}
|
||||
|
||||
static int wil_rf_sector_get_selected(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wdev_to_wil(wdev);
|
||||
int rc;
|
||||
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
|
||||
u8 sector_type, mac_addr[ETH_ALEN];
|
||||
int cid = 0;
|
||||
struct wmi_get_selected_rf_sector_index_cmd cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_get_selected_rf_sector_index_done_event evt;
|
||||
} __packed reply;
|
||||
struct sk_buff *msg;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
|
||||
wil_rf_sector_policy);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid rf sector ATTR\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) {
|
||||
wil_err(wil, "Invalid rf sector spec\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
|
||||
if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
|
||||
wil_err(wil, "Invalid sector type %d\n", sector_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[QCA_ATTR_MAC_ADDR]) {
|
||||
ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
|
||||
cid = wil_find_cid(wil, mac_addr);
|
||||
if (cid < 0) {
|
||||
wil_err(wil, "invalid MAC address %pM\n", mac_addr);
|
||||
return -ENOENT;
|
||||
}
|
||||
} else {
|
||||
if (test_bit(wil_status_fwconnected, wil->status)) {
|
||||
wil_err(wil, "must specify MAC address when connected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.cid = (u8)cid;
|
||||
cmd.sector_type = sector_type;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID,
|
||||
&cmd, sizeof(cmd),
|
||||
WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID,
|
||||
&reply, sizeof(reply),
|
||||
500);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (reply.evt.status) {
|
||||
wil_err(wil, "get rf selected sector cfg failed with status %d\n",
|
||||
reply.evt.status);
|
||||
return wil_rf_sector_status_to_rc(reply.evt.status);
|
||||
}
|
||||
|
||||
msg = cfg80211_vendor_cmd_alloc_reply_skb(
|
||||
wiphy, 64 * WMI_MAX_RF_MODULES_NUM);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (nla_put_u64(msg, QCA_ATTR_TSF,
|
||||
le64_to_cpu(reply.evt.tsf)) ||
|
||||
nla_put_u16(msg, QCA_ATTR_DMG_RF_SECTOR_INDEX,
|
||||
le16_to_cpu(reply.evt.sector_idx)))
|
||||
goto nla_put_failure;
|
||||
|
||||
rc = cfg80211_vendor_cmd_reply(msg);
|
||||
return rc;
|
||||
nla_put_failure:
|
||||
kfree_skb(msg);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil,
|
||||
u16 sector_index,
|
||||
u8 sector_type, u8 cid)
|
||||
{
|
||||
struct wmi_set_selected_rf_sector_index_cmd cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_set_selected_rf_sector_index_done_event evt;
|
||||
} __packed reply;
|
||||
int rc;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.sector_idx = cpu_to_le16(sector_index);
|
||||
cmd.sector_type = sector_type;
|
||||
cmd.cid = (u8)cid;
|
||||
memset(&reply, 0, sizeof(reply));
|
||||
rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID,
|
||||
&cmd, sizeof(cmd),
|
||||
WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID,
|
||||
&reply, sizeof(reply),
|
||||
500);
|
||||
if (rc)
|
||||
return rc;
|
||||
return wil_rf_sector_status_to_rc(reply.evt.status);
|
||||
}
|
||||
|
||||
static int wil_rf_sector_set_selected(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
const void *data, int data_len)
|
||||
{
|
||||
struct wil6210_priv *wil = wdev_to_wil(wdev);
|
||||
int rc;
|
||||
struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
|
||||
u16 sector_index;
|
||||
u8 sector_type, mac_addr[ETH_ALEN], i;
|
||||
int cid = 0;
|
||||
|
||||
if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
|
||||
wil_rf_sector_policy);
|
||||
if (rc) {
|
||||
wil_err(wil, "Invalid rf sector ATTR\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] ||
|
||||
!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) {
|
||||
wil_err(wil, "Invalid rf sector spec\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_index = nla_get_u16(
|
||||
tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]);
|
||||
if (sector_index >= WIL_MAX_RF_SECTORS &&
|
||||
sector_index != WMI_INVALID_RF_SECTOR_INDEX) {
|
||||
wil_err(wil, "Invalid sector index %d\n", sector_index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
|
||||
if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
|
||||
wil_err(wil, "Invalid sector type %d\n", sector_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb[QCA_ATTR_MAC_ADDR]) {
|
||||
ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
|
||||
if (!is_broadcast_ether_addr(mac_addr)) {
|
||||
cid = wil_find_cid(wil, mac_addr);
|
||||
if (cid < 0) {
|
||||
wil_err(wil, "invalid MAC address %pM\n",
|
||||
mac_addr);
|
||||
return -ENOENT;
|
||||
}
|
||||
} else {
|
||||
if (sector_index != WMI_INVALID_RF_SECTOR_INDEX) {
|
||||
wil_err(wil, "broadcast MAC valid only with unlocking\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
cid = -1;
|
||||
}
|
||||
} else {
|
||||
if (test_bit(wil_status_fwconnected, wil->status)) {
|
||||
wil_err(wil, "must specify MAC address when connected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* otherwise, using cid=0 for unassociated station */
|
||||
}
|
||||
|
||||
if (cid >= 0) {
|
||||
rc = wil_rf_sector_wmi_set_selected(wil, sector_index,
|
||||
sector_type, cid);
|
||||
} else {
|
||||
/* unlock all cids */
|
||||
rc = wil_rf_sector_wmi_set_selected(
|
||||
wil, WMI_INVALID_RF_SECTOR_INDEX, sector_type,
|
||||
WIL_CID_ALL);
|
||||
if (rc == -EINVAL) {
|
||||
for (i = 0; i < WIL6210_MAX_CID; i++) {
|
||||
rc = wil_rf_sector_wmi_set_selected(
|
||||
wil, WMI_INVALID_RF_SECTOR_INDEX,
|
||||
sector_type, i);
|
||||
/* the FW will silently ignore and return
|
||||
* success for unused cid, so abort the loop
|
||||
* on any other error
|
||||
*/
|
||||
if (rc) {
|
||||
wil_err(wil, "unlock cid %d failed with status %d\n",
|
||||
i, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -54,7 +54,7 @@ static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
|
|||
}
|
||||
|
||||
off = a - wil->csr;
|
||||
if (size >= WIL6210_MEM_SIZE - off) {
|
||||
if (size >= wil->bar_size - off) {
|
||||
wil_err(wil, "Requested block does not fit into memory: "
|
||||
"off = 0x%08x size = 0x%08x\n", off, size);
|
||||
return NULL;
|
||||
|
|
|
@ -198,16 +198,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
.ramdump = wil_platform_rop_ramdump,
|
||||
.fw_recovery = wil_platform_rop_fw_recovery,
|
||||
};
|
||||
u32 bar_size = pci_resource_len(pdev, 0);
|
||||
|
||||
/* check HW */
|
||||
dev_info(&pdev->dev, WIL_NAME
|
||||
" device found [%04x:%04x] (rev %x)\n",
|
||||
(int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
|
||||
" device found [%04x:%04x] (rev %x) bar size 0x%x\n",
|
||||
(int)pdev->vendor, (int)pdev->device, (int)pdev->revision,
|
||||
bar_size);
|
||||
|
||||
if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
|
||||
dev_err(&pdev->dev, "Not " WIL_NAME "? "
|
||||
"BAR0 size is %lu while expecting %lu\n",
|
||||
(ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
|
||||
if ((bar_size < WIL6210_MIN_MEM_SIZE) ||
|
||||
(bar_size > WIL6210_MAX_MEM_SIZE)) {
|
||||
dev_err(&pdev->dev, "Unexpected BAR0 size 0x%x\n",
|
||||
bar_size);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -220,6 +222,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
wil->pdev = pdev;
|
||||
pci_set_drvdata(pdev, wil);
|
||||
wil->bar_size = bar_size;
|
||||
/* rollback to if_free */
|
||||
|
||||
wil->platform_handle =
|
||||
|
|
|
@ -59,7 +59,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
|
|||
return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1);
|
||||
}
|
||||
|
||||
#define WIL6210_MEM_SIZE (2*1024*1024UL)
|
||||
#define WIL6210_MIN_MEM_SIZE (2 * 1024 * 1024UL)
|
||||
#define WIL6210_MAX_MEM_SIZE (4 * 1024 * 1024UL)
|
||||
|
||||
#define WIL_TX_Q_LEN_DEFAULT (4000)
|
||||
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
|
||||
|
@ -620,6 +621,7 @@ extern u8 led_polarity;
|
|||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
u32 bar_size;
|
||||
struct wireless_dev *wdev;
|
||||
void __iomem *csr;
|
||||
DECLARE_BITMAP(status, wil_status_last);
|
||||
|
|
|
@ -160,7 +160,7 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
|
|||
return NULL;
|
||||
|
||||
off = HOSTADDR(ptr);
|
||||
if (off > WIL6210_MEM_SIZE - 4)
|
||||
if (off > wil->bar_size - 4)
|
||||
return NULL;
|
||||
|
||||
return wil->csr + off;
|
||||
|
@ -180,7 +180,7 @@ void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
|
|||
return NULL;
|
||||
|
||||
off = HOSTADDR(ptr);
|
||||
if (off > WIL6210_MEM_SIZE - 4)
|
||||
if (off > wil->bar_size - 4)
|
||||
return NULL;
|
||||
|
||||
return wil->csr + off;
|
||||
|
|
Loading…
Add table
Reference in a new issue