diff options
Diffstat (limited to 'drivers/net/wireless/ath/wil6210')
31 files changed, 1629 insertions, 823 deletions
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 3548e8d5e18e..0d1a8dab30ed 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: ISC config WIL6210 tristate "Wilocity 60g WiFi card wil6210 support" select WANT_DEV_COREDUMP diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index d3d61ae459e2..53a0d995ddb0 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: ISC obj-$(CONFIG_WIL6210) += wil6210.o wil6210-y := main.o diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h index d32c1f4e533a..a8a43c25f843 100644 --- a/drivers/net/wireless/ath/wil6210/boot_loader.h +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* Copyright (c) 2015 Qualcomm Atheros, Inc. * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file contains the definitions for the boot loader diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index a1e226652b4a..7d6f14420855 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/etherdevice.h> @@ -25,6 +14,22 @@ #define WIL_MAX_ROC_DURATION_MS 5000 +#define WIL_EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1)) +#define WIL_EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2)) +#define WIL_EDMG_CHANNEL_11_SUBCHANNELS (BIT(2) | BIT(3)) + +/* WIL_EDMG_BW_CONFIGURATION define the allowed channel bandwidth + * configurations as defined by IEEE 802.11 section 9.4.2.251, Table 13. + * The value 5 allowing CB1 and CB2 of adjacent channels. + */ +#define WIL_EDMG_BW_CONFIGURATION 5 + +/* WIL_EDMG_CHANNELS is a bitmap that indicates the 2.16 GHz channel(s) that + * are allowed to be used for EDMG transmissions in the BSS as defined by + * IEEE 802.11 section 9.4.2.251. + */ +#define WIL_EDMG_CHANNELS (BIT(0) | BIT(1) | BIT(2) | BIT(3)) + bool disable_ap_sme; module_param(disable_ap_sme, bool, 0444); MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME"); @@ -51,6 +56,39 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(4, 0), }; +/* Rx channel bonding mode */ +enum wil_rx_cb_mode { + WIL_RX_CB_MODE_DMG, + WIL_RX_CB_MODE_EDMG, + WIL_RX_CB_MODE_WIDE, +}; + +static int wil_rx_cb_mode_to_n_bonded(u8 cb_mode) +{ + switch (cb_mode) { + case WIL_RX_CB_MODE_DMG: + case WIL_RX_CB_MODE_EDMG: + return 1; + case WIL_RX_CB_MODE_WIDE: + return 2; + default: + return 1; + } +} + +static int wil_tx_cb_mode_to_n_bonded(u8 cb_mode) +{ + switch (cb_mode) { + case WMI_TX_MODE_DMG: + case WMI_TX_MODE_EDMG_CB1: + return 1; + case WMI_TX_MODE_EDMG_CB2: + return 2; + default: + return 1; + } +} + static void wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len) { @@ -82,6 +120,13 @@ void update_supported_bands(struct wil6210_priv *wil) wiphy->bands[NL80211_BAND_60GHZ]->n_channels = wil_num_supported_channels(wil); + + if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) { + wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.channels = + WIL_EDMG_CHANNELS; + wiphy->bands[NL80211_BAND_60GHZ]->edmg_cap.bw_config = + WIL_EDMG_BW_CONFIGURATION; + } } /* Vendor id to be used in vendor specific command and events @@ -177,6 +222,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = { .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .policy = wil_rf_sector_policy, .doit = wil_rf_sector_get_cfg }, { @@ -184,6 +230,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = { .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .policy = wil_rf_sector_policy, .doit = wil_rf_sector_set_cfg }, { @@ -192,6 +239,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = { QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .policy = wil_rf_sector_policy, .doit = wil_rf_sector_get_selected }, { @@ -200,6 +248,7 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = { QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR, .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .policy = wil_rf_sector_policy, .doit = wil_rf_sector_set_selected }, }; @@ -271,6 +320,8 @@ static const char * const key_usage_str[] = { [WMI_KEY_USE_PAIRWISE] = "PTK", [WMI_KEY_USE_RX_GROUP] = "RX_GTK", [WMI_KEY_USE_TX_GROUP] = "TX_GTK", + [WMI_KEY_USE_STORE_PTK] = "STORE_PTK", + [WMI_KEY_USE_APPLY_PTK] = "APPLY_PTK", }; int wil_iftype_nl2wmi(enum nl80211_iftype type) @@ -296,6 +347,86 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } +int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch) +{ + switch (spec_ch) { + case 1: + *wmi_ch = WMI_CHANNEL_1; + break; + case 2: + *wmi_ch = WMI_CHANNEL_2; + break; + case 3: + *wmi_ch = WMI_CHANNEL_3; + break; + case 4: + *wmi_ch = WMI_CHANNEL_4; + break; + case 5: + *wmi_ch = WMI_CHANNEL_5; + break; + case 6: + *wmi_ch = WMI_CHANNEL_6; + break; + case 9: + *wmi_ch = WMI_CHANNEL_9; + break; + case 10: + *wmi_ch = WMI_CHANNEL_10; + break; + case 11: + *wmi_ch = WMI_CHANNEL_11; + break; + case 12: + *wmi_ch = WMI_CHANNEL_12; + break; + default: + return -EINVAL; + } + + return 0; +} + +int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch) +{ + switch (wmi_ch) { + case WMI_CHANNEL_1: + *spec_ch = 1; + break; + case WMI_CHANNEL_2: + *spec_ch = 2; + break; + case WMI_CHANNEL_3: + *spec_ch = 3; + break; + case WMI_CHANNEL_4: + *spec_ch = 4; + break; + case WMI_CHANNEL_5: + *spec_ch = 5; + break; + case WMI_CHANNEL_6: + *spec_ch = 6; + break; + case WMI_CHANNEL_9: + *spec_ch = 9; + break; + case WMI_CHANNEL_10: + *spec_ch = 10; + break; + case WMI_CHANNEL_11: + *spec_ch = 11; + break; + case WMI_CHANNEL_12: + *spec_ch = 12; + break; + default: + return -EINVAL; + } + + return 0; +} + int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, struct station_info *sinfo) { @@ -310,11 +441,13 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, } __packed reply; struct wil_net_stats *stats = &wil->sta[cid].stats; int rc; + u8 txflag = RATE_INFO_FLAGS_DMG; memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd), - WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); + WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -322,7 +455,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, " MCS %d TSF 0x%016llx\n" " BF status 0x%08x RSSI %d SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" - " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", + " Sectors(rx:tx) my %d:%d peer %d:%d\n" + " Tx mode %d}\n", cid, vif->mid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, reply.evt.rssi, @@ -333,7 +467,8 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, le16_to_cpu(reply.evt.my_rx_sector), le16_to_cpu(reply.evt.my_tx_sector), le16_to_cpu(reply.evt.other_rx_sector), - le16_to_cpu(reply.evt.other_tx_sector)); + le16_to_cpu(reply.evt.other_tx_sector), + reply.evt.tx_mode); sinfo->generation = wil->sinfo_gen; @@ -346,9 +481,16 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC) | BIT_ULL(NL80211_STA_INFO_TX_FAILED); - sinfo->txrate.flags = RATE_INFO_FLAGS_60G; + if (wil->use_enhanced_dma_hw && reply.evt.tx_mode != WMI_TX_MODE_DMG) + txflag = RATE_INFO_FLAGS_EDMG; + + sinfo->txrate.flags = txflag; sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs); sinfo->rxrate.mcs = stats->last_mcs_rx; + sinfo->txrate.n_bonded_ch = + wil_tx_cb_mode_to_n_bonded(reply.evt.tx_mode); + sinfo->rxrate.n_bonded_ch = + wil_rx_cb_mode_to_n_bonded(stats->last_cb_mode_rx); sinfo->rx_bytes = stats->rx_bytes; sinfo->rx_packets = stats->rx_packets; sinfo->rx_dropped_misc = stats->rx_dropped; @@ -380,8 +522,8 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, wil_dbg_misc(wil, "get_station: %pM CID %d MID %d\n", mac, cid, vif->mid); - if (cid < 0) - return cid; + if (!wil_cid_valid(wil, cid)) + return -ENOENT; rc = wil_cid_fill_sinfo(vif, cid, sinfo); @@ -391,11 +533,11 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, /* * Find @idx-th active STA for specific MID for station dump. */ -static int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx) +int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx) { int i; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { if (wil->sta[i].status == wil_sta_unused) continue; if (wil->sta[i].mid != mid) @@ -417,7 +559,7 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, int rc; int cid = wil_find_cid_by_idx(wil, vif->mid, idx); - if (cid < 0) + if (!wil_cid_valid(wil, cid)) return -ENOENT; ether_addr_copy(mac, wil->sta[cid].addr); @@ -465,7 +607,7 @@ static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil, .num_different_channels = 1, }; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { if (wil->vifs[i]) { wdev = vif_to_wdev(wil->vifs[i]); params.iftype_num[wdev->iftype]++; @@ -486,7 +628,7 @@ static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil, }; bool check_combos = false; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { struct wil6210_vif *vif_pos = wil->vifs[i]; if (vif_pos && vif != vif_pos) { @@ -643,6 +785,16 @@ out: return rc; } +static bool wil_is_safe_switch(enum nl80211_iftype from, + enum nl80211_iftype to) +{ + if (from == NL80211_IFTYPE_STATION && + to == NL80211_IFTYPE_P2P_CLIENT) + return true; + + return false; +} + static int wil_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type, @@ -668,7 +820,8 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, * because it can cause significant disruption */ if (!wil_has_other_active_ifaces(wil, ndev, true, false) && - netif_running(ndev) && !wil_is_recovery_blocked(wil)) { + netif_running(ndev) && !wil_is_recovery_blocked(wil) && + !wil_is_safe_switch(wdev->iftype, type)) { wil_dbg_misc(wil, "interface is up. resetting...\n"); mutex_lock(&wil->mutex); __wil_down(wil); @@ -1006,6 +1159,33 @@ static int wil_ft_connect(struct wiphy *wiphy, return rc; } +static int wil_get_wmi_edmg_channel(struct wil6210_priv *wil, u8 edmg_bw_config, + u8 edmg_channels, u8 *wmi_ch) +{ + if (!edmg_bw_config) { + *wmi_ch = 0; + return 0; + } else if (edmg_bw_config == WIL_EDMG_BW_CONFIGURATION) { + /* convert from edmg channel bitmap into edmg channel number */ + switch (edmg_channels) { + case WIL_EDMG_CHANNEL_9_SUBCHANNELS: + return wil_spec2wmi_ch(9, wmi_ch); + case WIL_EDMG_CHANNEL_10_SUBCHANNELS: + return wil_spec2wmi_ch(10, wmi_ch); + case WIL_EDMG_CHANNEL_11_SUBCHANNELS: + return wil_spec2wmi_ch(11, wmi_ch); + default: + wil_err(wil, "Unsupported edmg channel bitmap 0x%x\n", + edmg_channels); + return -EINVAL; + } + } else { + wil_err(wil, "Unsupported EDMG BW configuration %d\n", + edmg_bw_config); + return -EINVAL; + } +} + static int wil_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) @@ -1151,6 +1331,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); conn.channel = ch - 1; + rc = wil_get_wmi_edmg_channel(wil, sme->edmg.bw_config, + sme->edmg.channels, &conn.edmg_channel); + if (rc < 0) + return rc; + ether_addr_copy(conn.bssid, bss->bssid); ether_addr_copy(conn.dst_mac, bss->bssid); @@ -1274,7 +1459,12 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, params->wait); out: + /* when the sent packet was not acked by receiver(ACK=0), rc will + * be -EAGAIN. In this case this function needs to return success, + * the ACK=0 will be reflected in tx_status. + */ tx_status = (rc == 0); + rc = (rc == -EAGAIN) ? 0 : rc; cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len, tx_status, GFP_KERNEL); @@ -1355,6 +1545,7 @@ void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, return; switch (key_usage) { + case WMI_KEY_USE_STORE_PTK: case WMI_KEY_USE_PAIRWISE: for (tid = 0; tid < WIL_STA_TID_NUM; tid++) { cc = &cs->tid_crypto_rx[tid].key_id[key_index]; @@ -1452,6 +1643,16 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, return -EINVAL; } + spin_lock_bh(&wil->eap_lock); + if (pairwise && wdev->iftype == NL80211_IFTYPE_STATION && + (vif->ptk_rekey_state == WIL_REKEY_M3_RECEIVED || + vif->ptk_rekey_state == WIL_REKEY_WAIT_M4_SENT)) { + key_usage = WMI_KEY_USE_STORE_PTK; + vif->ptk_rekey_state = WIL_REKEY_WAIT_M4_SENT; + wil_dbg_misc(wil, "Store EAPOL key\n"); + } + spin_unlock_bh(&wil->eap_lock); + rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len, params->key, key_usage); if (!rc && !IS_ERR(cs)) { @@ -1707,7 +1908,7 @@ out: static int _wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, const u8 *ssid, size_t ssid_len, u32 privacy, - int bi, u8 chan, + int bi, u8 chan, u8 wmi_edmg_channel, struct cfg80211_beacon_data *bcon, u8 hidden_ssid, u32 pbss) { @@ -1770,6 +1971,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, vif->privacy = privacy; vif->channel = chan; + vif->wmi_edmg_channel = wmi_edmg_channel; vif->hidden_ssid = hidden_ssid; vif->pbss = pbss; vif->bi = bi; @@ -1780,7 +1982,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, if (!wil_has_other_active_ifaces(wil, ndev, false, true)) wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); - rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go); + rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, wmi_edmg_channel, + hidden_ssid, is_go); if (rc) goto err_pcp_start; @@ -1806,7 +2009,7 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil) int rc, i; struct wiphy *wiphy = wil_to_wiphy(wil); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { struct wil6210_vif *vif = wil->vifs[i]; struct net_device *ndev; struct cfg80211_beacon_data bcon = {}; @@ -1832,7 +2035,8 @@ void wil_cfg80211_ap_recovery(struct wil6210_priv *wil) rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, vif->privacy, vif->bi, - vif->channel, &bcon, + vif->channel, + vif->wmi_edmg_channel, &bcon, vif->hidden_ssid, vif->pbss); if (rc) { wil_err(wil, "vif %d recovery failed (%d)\n", i, rc); @@ -1882,7 +2086,8 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, privacy, wdev->beacon_interval, - vif->channel, bcon, + vif->channel, + vif->wmi_edmg_channel, bcon, vif->hidden_ssid, vif->pbss); } else { @@ -1901,10 +2106,17 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; + u8 wmi_edmg_channel; u8 hidden_ssid; wil_dbg_misc(wil, "start_ap\n"); + rc = wil_get_wmi_edmg_channel(wil, info->chandef.edmg.bw_config, + info->chandef.edmg.channels, + &wmi_edmg_channel); + if (rc < 0) + return rc; + if (!channel) { wil_err(wil, "AP: No channel???\n"); return -EINVAL; @@ -1944,7 +2156,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, rc = _wil_cfg80211_start_ap(wiphy, ndev, info->ssid, info->ssid_len, info->privacy, info->beacon_interval, channel->hw_value, - bcon, hidden_ssid, info->pbss); + wmi_edmg_channel, bcon, hidden_ssid, + info->pbss); return rc; } @@ -2620,8 +2833,8 @@ 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(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, - wil_rf_sector_policy, NULL); + rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, + data_len, wil_rf_sector_policy, NULL); if (rc) { wil_err(wil, "Invalid rf sector ATTR\n"); return rc; @@ -2679,13 +2892,13 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy, QCA_ATTR_PAD)) goto nla_put_failure; - nl_cfgs = nla_nest_start(msg, QCA_ATTR_DMG_RF_SECTOR_CFG); + nl_cfgs = nla_nest_start_noflag(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); + nl_cfg = nla_nest_start_noflag(msg, i); if (!nl_cfg) goto nla_put_failure; si = &reply.evt.sectors_info[i]; @@ -2740,8 +2953,8 @@ 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(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, - wil_rf_sector_policy, NULL); + rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, + data_len, wil_rf_sector_policy, NULL); if (rc) { wil_err(wil, "Invalid rf sector ATTR\n"); return rc; @@ -2773,9 +2986,11 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy, 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, - NULL); + rc = nla_parse_nested_deprecated(tb2, + QCA_ATTR_DMG_RF_SECTOR_CFG_MAX, + nl_cfg, + wil_rf_sector_cfg_policy, + NULL); if (rc) { wil_err(wil, "invalid sector cfg\n"); return -EINVAL; @@ -2847,8 +3062,8 @@ 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(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, - wil_rf_sector_policy, NULL); + rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, + data_len, wil_rf_sector_policy, NULL); if (rc) { wil_err(wil, "Invalid rf sector ATTR\n"); return rc; @@ -2955,8 +3170,8 @@ 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(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len, - wil_rf_sector_policy, NULL); + rc = nla_parse_deprecated(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, + data_len, wil_rf_sector_policy, NULL); if (rc) { wil_err(wil, "Invalid rf sector ATTR\n"); return rc; @@ -3015,7 +3230,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy, wil, vif->mid, WMI_INVALID_RF_SECTOR_INDEX, sector_type, WIL_CID_ALL); if (rc == -EINVAL) { - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { if (wil->sta[i].mid != vif->mid) continue; rc = wil_rf_sector_wmi_set_selected( diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c index a9befb971cc4..396c94c53702 100644 --- a/drivers/net/wireless/ath/wil6210/debug.c +++ b/drivers/net/wireless/ath/wil6210/debug.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2013,2016 Qualcomm Atheros, Inc. * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 7ad4e5328439..11d0c79e9056 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> @@ -63,7 +52,9 @@ static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil, &ring->va[idx].rx.enhanced; u16 buff_id = le16_to_cpu(rx_d->mac.buff_id); - has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; + if (wil->rx_buff_mgmt.buff_arr && + wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size)) + has_skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; seq_printf(s, "%c", (has_skb) ? _h : _s); } else { struct wil_tx_enhanced_desc *d = @@ -71,9 +62,9 @@ static void wil_print_desc_edma(struct seq_file *s, struct wil6210_priv *wil, &ring->va[idx].tx.enhanced; num_of_descs = (u8)d->mac.d[2]; - has_skb = ring->ctx[idx].skb; + has_skb = ring->ctx && ring->ctx[idx].skb; if (num_of_descs >= 1) - seq_printf(s, "%c", ring->ctx[idx].skb ? _h : _s); + seq_printf(s, "%c", has_skb ? _h : _s); else /* num_of_descs == 0, it's a frag in a list of descs */ seq_printf(s, "%c", has_skb ? 'h' : _s); @@ -84,7 +75,7 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, const char *name, struct wil_ring *ring, char _s, char _h) { - void __iomem *x = wmi_addr(wil, ring->hwtail); + void __iomem *x; u32 v; seq_printf(s, "RING %s = {\n", name); @@ -96,7 +87,21 @@ static void wil_print_ring(struct seq_file *s, struct wil6210_priv *wil, else seq_printf(s, " swtail = %d\n", ring->swtail); seq_printf(s, " swhead = %d\n", ring->swhead); + if (wil->use_enhanced_dma_hw) { + int ring_id = ring->is_rx ? + WIL_RX_DESC_RING_ID : ring - wil->ring_tx; + /* SUBQ_CONS is a table of 32 entries, one for each Q pair. + * lower 16bits are for even ring_id and upper 16bits are for + * odd ring_id + */ + x = wmi_addr(wil, RGF_DMA_SCM_SUBQ_CONS + 4 * (ring_id / 2)); + v = readl_relaxed(x); + + v = (ring_id % 2 ? (v >> 16) : (v & 0xffff)); + seq_printf(s, " hwhead = %u\n", v); + } seq_printf(s, " hwtail = [0x%08x] -> ", ring->hwtail); + x = wmi_addr(wil, ring->hwtail); if (x) { v = readl(x); seq_printf(s, "0x%08x = %d\n", v, v); @@ -162,7 +167,7 @@ static int ring_show(struct seq_file *s, void *data) snprintf(name, sizeof(name), "tx_%2d", i); - if (cid < max_assoc_sta) + if (cid < wil->max_assoc_sta) seq_printf(s, "\n%pM CID %d TID %d 1x%s BACK([%u] %u TU A%s) [%3d|%3d] idle %s\n", wil->sta[cid].addr, cid, tid, @@ -188,7 +193,7 @@ DEFINE_SHOW_ATTRIBUTE(ring); static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil, struct wil_status_ring *sring) { - void __iomem *x = wmi_addr(wil, sring->hwtail); + void __iomem *x; int sring_idx = sring - wil->srings; u32 v; @@ -199,7 +204,19 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil, seq_printf(s, " size = %d\n", sring->size); seq_printf(s, " elem_size = %zu\n", sring->elem_size); seq_printf(s, " swhead = %d\n", sring->swhead); + if (wil->use_enhanced_dma_hw) { + /* COMPQ_PROD is a table of 32 entries, one for each Q pair. + * lower 16bits are for even ring_id and upper 16bits are for + * odd ring_id + */ + x = wmi_addr(wil, RGF_DMA_SCM_COMPQ_PROD + 4 * (sring_idx / 2)); + v = readl_relaxed(x); + + v = (sring_idx % 2 ? (v >> 16) : (v & 0xffff)); + seq_printf(s, " hwhead = %u\n", v); + } seq_printf(s, " hwtail = [0x%08x] -> ", sring->hwtail); + x = wmi_addr(wil, sring->hwtail); if (x) { v = readl_relaxed(x); seq_printf(s, "0x%08x = %d\n", v, v); @@ -207,6 +224,8 @@ static void wil_print_sring(struct seq_file *s, struct wil6210_priv *wil, seq_puts(s, "???\n"); } seq_printf(s, " desc_rdy_pol = %d\n", sring->desc_rdy_pol); + seq_printf(s, " invalid_buff_id_cnt = %d\n", + sring->invalid_buff_id_cnt); if (sring->va && (sring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) { uint i; @@ -258,6 +277,11 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix, wil_halp_vote(wil); + if (wil_mem_access_lock(wil)) { + wil_halp_unvote(wil); + return; + } + wil_memcpy_fromio_32(&r, off, sizeof(r)); wil_mbox_ring_le2cpus(&r); /* @@ -323,6 +347,7 @@ static void wil_print_mbox_ring(struct seq_file *s, const char *prefix, } out: seq_puts(s, "}\n"); + wil_mem_access_unlock(wil); wil_halp_unvote(wil); } @@ -357,7 +382,8 @@ static int wil_debugfs_iomem_x32_set(void *data, u64 val) if (ret < 0) return ret; - writel(val, (void __iomem *)d->offset); + writel_relaxed(val, (void __iomem *)d->offset); + wmb(); /* make sure write propagated to HW */ wil_pm_runtime_put(wil); @@ -386,25 +412,18 @@ static int wil_debugfs_iomem_x32_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get, wil_debugfs_iomem_x32_set, "0x%08llx\n"); -static struct dentry *wil_debugfs_create_iomem_x32(const char *name, - umode_t mode, - struct dentry *parent, - void *value, - struct wil6210_priv *wil) +static void wil_debugfs_create_iomem_x32(const char *name, umode_t mode, + struct dentry *parent, void *value, + struct wil6210_priv *wil) { - struct dentry *file; struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[ wil->dbg_data.iomem_data_count]; data->wil = wil; data->offset = value; - file = debugfs_create_file_unsafe(name, mode, parent, data, - &fops_iomem_x32); - if (!IS_ERR_OR_NULL(file)) - wil->dbg_data.iomem_data_count++; - - return file; + debugfs_create_file_unsafe(name, mode, parent, data, &fops_iomem_x32); + wil->dbg_data.iomem_data_count++; } static int wil_debugfs_ulong_set(void *data, u64 val) @@ -422,14 +441,6 @@ static int wil_debugfs_ulong_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(wil_fops_ulong, wil_debugfs_ulong_get, wil_debugfs_ulong_set, "0x%llx\n"); -static struct dentry *wil_debugfs_create_ulong(const char *name, umode_t mode, - struct dentry *parent, - ulong *value) -{ - return debugfs_create_file_unsafe(name, mode, parent, value, - &wil_fops_ulong); -} - /** * wil6210_debugfs_init_offset - create set of debugfs files * @wil - driver's context, used for printing @@ -446,37 +457,30 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, int i; for (i = 0; tbl[i].name; i++) { - struct dentry *f; - switch (tbl[i].type) { case doff_u32: - f = debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, - base + tbl[i].off); + debugfs_create_u32(tbl[i].name, tbl[i].mode, dbg, + base + tbl[i].off); break; case doff_x32: - f = debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, - base + tbl[i].off); + debugfs_create_x32(tbl[i].name, tbl[i].mode, dbg, + base + tbl[i].off); break; case doff_ulong: - f = wil_debugfs_create_ulong(tbl[i].name, tbl[i].mode, - dbg, base + tbl[i].off); + debugfs_create_file_unsafe(tbl[i].name, tbl[i].mode, + dbg, base + tbl[i].off, + &wil_fops_ulong); break; case doff_io32: - f = wil_debugfs_create_iomem_x32(tbl[i].name, - tbl[i].mode, dbg, - base + tbl[i].off, - wil); + wil_debugfs_create_iomem_x32(tbl[i].name, tbl[i].mode, + dbg, base + tbl[i].off, + wil); break; case doff_u8: - f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, - base + tbl[i].off); + debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, + base + tbl[i].off); break; - default: - f = ERR_PTR(-EINVAL); } - if (IS_ERR_OR_NULL(f)) - wil_err(wil, "Create file \"%s\": err %ld\n", - tbl[i].name, PTR_ERR(f)); } } @@ -491,19 +495,14 @@ static const struct dbg_off isr_off[] = { {}, }; -static int wil6210_debugfs_create_ISR(struct wil6210_priv *wil, - const char *name, - struct dentry *parent, u32 off) +static void wil6210_debugfs_create_ISR(struct wil6210_priv *wil, + const char *name, struct dentry *parent, + u32 off) { struct dentry *d = debugfs_create_dir(name, parent); - if (IS_ERR_OR_NULL(d)) - return -ENODEV; - wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr + off, isr_off); - - return 0; } static const struct dbg_off pseudo_isr_off[] = { @@ -513,18 +512,13 @@ static const struct dbg_off pseudo_isr_off[] = { {}, }; -static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, - struct dentry *parent) +static void wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil, + struct dentry *parent) { struct dentry *d = debugfs_create_dir("PSEUDO_ISR", parent); - if (IS_ERR_OR_NULL(d)) - return -ENODEV; - wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, pseudo_isr_off); - - return 0; } static const struct dbg_off lgc_itr_cnt_off[] = { @@ -572,13 +566,9 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil, struct dentry *d, *dtx, *drx; d = debugfs_create_dir("ITR_CNT", parent); - if (IS_ERR_OR_NULL(d)) - return -ENODEV; dtx = debugfs_create_dir("TX", d); drx = debugfs_create_dir("RX", d); - if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx)) - return -ENODEV; wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr, lgc_itr_cnt_off); @@ -601,6 +591,12 @@ static int memread_show(struct seq_file *s, void *data) if (ret < 0) return ret; + ret = wil_mem_access_lock(wil); + if (ret) { + wil_pm_runtime_put(wil); + return ret; + } + a = wmi_buffer(wil, cpu_to_le32(mem_addr)); if (a) @@ -608,6 +604,7 @@ static int memread_show(struct seq_file *s, void *data) else seq_printf(s, "[0x%08x] = INVALID\n", mem_addr); + wil_mem_access_unlock(wil); wil_pm_runtime_put(wil); return 0; @@ -626,10 +623,6 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, size_t unaligned_bytes, aligned_count, ret; int rc; - if (test_bit(wil_status_suspending, wil_blob->wil->status) || - test_bit(wil_status_suspended, wil_blob->wil->status)) - return 0; - if (pos < 0) return -EINVAL; @@ -656,11 +649,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, return rc; } + rc = wil_mem_access_lock(wil); + if (rc) { + kfree(buf); + wil_pm_runtime_put(wil); + return rc; + } + wil_memcpy_fromio_32(buf, (const void __iomem *) wil_blob->blob.data + aligned_pos, aligned_count); ret = copy_to_user(user_buf, buf + unaligned_bytes, count); + wil_mem_access_unlock(wil); wil_pm_runtime_put(wil); kfree(buf); @@ -730,6 +731,44 @@ static const struct file_operations fops_rxon = { .open = simple_open, }; +static ssize_t wil_write_file_rbufcap(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct wil6210_priv *wil = file->private_data; + int val; + int rc; + + rc = kstrtoint_from_user(buf, count, 0, &val); + if (rc) { + wil_err(wil, "Invalid argument\n"); + return rc; + } + /* input value: negative to disable, 0 to use system default, + * 1..ring size to set descriptor threshold + */ + wil_info(wil, "%s RBUFCAP, descriptors threshold - %d\n", + val < 0 ? "Disabling" : "Enabling", val); + + if (!wil->ring_rx.va || val > wil->ring_rx.size) { + wil_err(wil, "Invalid descriptors threshold, %d\n", val); + return -EINVAL; + } + + rc = wmi_rbufcap_cfg(wil, val < 0 ? 0 : 1, val < 0 ? 0 : val); + if (rc) { + wil_err(wil, "RBUFCAP config failed: %d\n", rc); + return rc; + } + + return count; +} + +static const struct file_operations fops_rbufcap = { + .write = wil_write_file_rbufcap, + .open = simple_open, +}; + /* block ack control, write: * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side @@ -792,7 +831,7 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf, "BACK: del_rx require at least 2 params\n"); return -EINVAL; } - if (p1 < 0 || p1 >= max_assoc_sta) { + if (p1 < 0 || p1 >= wil->max_assoc_sta) { wil_err(wil, "BACK: invalid CID %d\n", p1); return -EINVAL; } @@ -891,9 +930,8 @@ static ssize_t wil_read_pmccfg(struct file *file, char __user *user_buf, " - \"alloc <num descriptors> <descriptor_size>\" to allocate pmc\n" " - \"free\" to free memory allocated for pmc\n"; - sprintf(text, "Last command status: %d\n\n%s", - wil_pmc_last_cmd_status(wil), - help); + snprintf(text, sizeof(text), "Last command status: %d\n\n%s", + wil_pmc_last_cmd_status(wil), help); return simple_read_from_buffer(user_buf, count, ppos, text, strlen(text) + 1); @@ -911,6 +949,18 @@ static const struct file_operations fops_pmcdata = { .llseek = wil_pmc_llseek, }; +static int wil_pmcring_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_pmcring_read, inode->i_private); +} + +static const struct file_operations fops_pmcring = { + .open = wil_pmcring_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + /*---tx_mgmt---*/ /* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, @@ -1004,8 +1054,7 @@ static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) if (nr_frags) { seq_printf(s, " nr_frags = %d\n", nr_frags); for (i = 0; i < nr_frags; i++) { - const struct skb_frag_struct *frag = - &skb_shinfo(skb)->frags[i]; + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = skb_frag_size(frag); p = skb_frag_address_safe(frag); @@ -1072,19 +1121,18 @@ static int txdesc_show(struct seq_file *s, void *data) if (wil->use_enhanced_dma_hw) { if (tx) { - skb = ring->ctx[txdesc_idx].skb; - } else { + skb = ring->ctx ? ring->ctx[txdesc_idx].skb : NULL; + } else if (wil->rx_buff_mgmt.buff_arr) { struct wil_rx_enhanced_desc *rx_d = (struct wil_rx_enhanced_desc *) &ring->va[txdesc_idx].rx.enhanced; u16 buff_id = le16_to_cpu(rx_d->mac.buff_id); if (!wil_val_in_range(buff_id, 0, - wil->rx_buff_mgmt.size)) { + wil->rx_buff_mgmt.size)) seq_printf(s, "invalid buff_id %d\n", buff_id); - return 0; - } - skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; + else + skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; } } else { skb = ring->ctx[txdesc_idx].skb; @@ -1117,7 +1165,7 @@ static int status_msg_show(struct seq_file *s, void *data) struct wil6210_priv *wil = s->private; int sring_idx = dbg_sring_index; struct wil_status_ring *sring; - bool tx = sring_idx == wil->tx_sring_idx ? 1 : 0; + bool tx; u32 status_msg_idx = dbg_status_msg_index; u32 *u; @@ -1127,6 +1175,7 @@ static int status_msg_show(struct seq_file *s, void *data) } sring = &wil->srings[sring_idx]; + tx = !sring->is_rx; if (!sring->va) { seq_printf(s, "No %cX status ring\n", tx ? 'T' : 'R'); @@ -1243,14 +1292,14 @@ static int bf_show(struct seq_file *s, void *data) memset(&reply, 0, sizeof(reply)); - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { u32 status; cmd.cid = i; rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, &reply, - sizeof(reply), 20); + sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); /* if reply is all-0, ignore this CID */ if (rc || is_all_zeros(&reply.evt, sizeof(reply.evt))) continue; @@ -1288,7 +1337,7 @@ static void print_temp(struct seq_file *s, const char *prefix, s32 t) { switch (t) { case 0: - case ~(u32)0: + case WMI_INVALID_TEMPERATURE: seq_printf(s, "%s N/A\n", prefix); break; default: @@ -1301,17 +1350,41 @@ static void print_temp(struct seq_file *s, const char *prefix, s32 t) static int temp_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - s32 t_m, t_r; - int rc = wmi_get_temperature(wil, &t_m, &t_r); + int rc, i; - if (rc) { - seq_puts(s, "Failed\n"); - return 0; - } + if (test_bit(WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF, + wil->fw_capabilities)) { + struct wmi_temp_sense_all_done_event sense_all_evt; - print_temp(s, "T_mac =", t_m); - print_temp(s, "T_radio =", t_r); + wil_dbg_misc(wil, + "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is supported"); + rc = wmi_get_all_temperatures(wil, &sense_all_evt); + if (rc) { + seq_puts(s, "Failed\n"); + return 0; + } + print_temp(s, "T_mac =", + le32_to_cpu(sense_all_evt.baseband_t1000)); + seq_printf(s, "Connected RFs [0x%08x]\n", + sense_all_evt.rf_bitmap); + for (i = 0; i < WMI_MAX_XIF_PORTS_NUM; i++) { + seq_printf(s, "RF[%d] = ", i); + print_temp(s, "", + le32_to_cpu(sense_all_evt.rf_t1000[i])); + } + } else { + s32 t_m, t_r; + wil_dbg_misc(wil, + "WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF is not supported"); + rc = wmi_get_temperature(wil, &t_m, &t_r); + if (rc) { + seq_puts(s, "Failed\n"); + return 0; + } + print_temp(s, "T_mac =", t_m); + print_temp(s, "T_radio =", t_r); + } return 0; } DEFINE_SHOW_ATTRIBUTE(temp); @@ -1340,7 +1413,7 @@ static int link_show(struct seq_file *s, void *data) if (!sinfo) return -ENOMEM; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; struct wil6210_vif *vif; @@ -1364,7 +1437,7 @@ static int link_show(struct seq_file *s, void *data) if (p->status != wil_sta_connected) continue; - vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; + vif = (mid < GET_MAX_VIFS(wil)) ? wil->vifs[mid] : NULL; if (vif) { rc = wil_cid_fill_sinfo(vif, i, sinfo); if (rc) @@ -1542,7 +1615,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) struct wil6210_priv *wil = s->private; int i, tid, mcs; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; u8 aid = 0; @@ -1562,7 +1635,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) break; } mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; - if (mid < wil->max_vifs) { + if (mid < GET_MAX_VIFS(wil)) { struct wil6210_vif *vif = wil->vifs[mid]; if (vif->wdev.iftype == NL80211_IFTYPE_STATION && @@ -1628,7 +1701,7 @@ static int mids_show(struct seq_file *s, void *data) int i; mutex_lock(&wil->vif_mutex); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (vif) { @@ -1651,7 +1724,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) struct wil6210_priv *wil = s->private; int i, bin; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; u8 aid = 0; @@ -1740,7 +1813,7 @@ static ssize_t wil_tx_latency_write(struct file *file, const char __user *buf, size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS; wil->tx_latency_res = val; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { struct wil_sta_info *sta = &wil->sta[i]; kfree(sta->tx_latency_bins); @@ -1825,7 +1898,7 @@ static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif, } seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf); - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { if (wil->sta[i].status == wil_sta_unused) continue; if (wil->sta[i].mid != vif->mid) @@ -1849,7 +1922,7 @@ static int wil_link_stats_debugfs_show(struct seq_file *s, void *data) /* iterate over all MIDs and show per-cid statistics. Then show the * global statistics */ - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; seq_printf(s, "MID %d ", i); @@ -1905,7 +1978,7 @@ static ssize_t wil_link_stats_write(struct file *file, const char __user *buf, if (rc) return rc; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (!vif) continue; @@ -2300,6 +2373,7 @@ static const struct { {"back", 0644, &fops_back}, {"pmccfg", 0644, &fops_pmccfg}, {"pmcdata", 0444, &fops_pmcdata}, + {"pmcring", 0444, &fops_pmcring}, {"temp", 0444, &temp_fops}, {"freq", 0444, &freq_fops}, {"link", 0444, &link_fops}, @@ -2317,6 +2391,7 @@ static const struct { {"tx_latency", 0644, &fops_tx_latency}, {"link_stats", 0644, &fops_link_stats}, {"link_stats_global", 0644, &fops_link_stats_global}, + {"rbufcap", 0244, &fops_rbufcap}, }; static void wil6210_debugfs_init_files(struct wil6210_priv *wil, @@ -2375,6 +2450,7 @@ static const struct dbg_off dbg_wil_regs[] = { {"RGF_MAC_MTRL_COUNTER_0", 0444, HOSTADDR(RGF_MAC_MTRL_COUNTER_0), doff_io32}, {"RGF_USER_USAGE_1", 0444, HOSTADDR(RGF_USER_USAGE_1), doff_io32}, + {"RGF_USER_USAGE_2", 0444, HOSTADDR(RGF_USER_USAGE_2), doff_io32}, {}, }; @@ -2440,7 +2516,7 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil) wil->debug = NULL; kfree(wil->dbg_data.data_arr); - for (i = 0; i < max_assoc_sta; i++) + for (i = 0; i < wil->max_assoc_sta; i++) kfree(wil->sta[i].tx_latency_bins); /* free pmc memory without sending command to fw, as it will diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index a04c87ffd37b..912c4eaf017b 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 3e2bbbceca06..6d3413a44b05 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2015,2017 Qualcomm Atheros, Inc. * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/firmware.h> #include <linux/module.h> diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h index 3e7a28045cab..540fa1607794 100644 --- a/drivers/net/wireless/ath/wil6210/fw.h +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2014,2016 Qualcomm Atheros, Inc. - * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #ifndef __WIL_FW_H__ #define __WIL_FW_H__ @@ -109,12 +98,17 @@ struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */ /* brd file info encoded inside a comment record */ #define WIL_BRD_FILE_MAGIC (0xabcddcbb) + +struct brd_info { + __le32 base_addr; + __le32 max_size_bytes; +} __packed; + struct wil_fw_record_brd_file { /* type == wil_fw_type_comment */ /* identifies brd file record */ struct wil_fw_record_comment_hdr hdr; __le32 version; - __le32 base_addr; - __le32 max_size_bytes; + struct brd_info brd_info[0]; } __packed; /* perform action diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 388b3d4717ca..fbc84c03406b 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. - * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ /* Algorithmic part of the firmware download. @@ -156,17 +145,52 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data, size_t size) { const struct wil_fw_record_brd_file *rec = data; + u32 max_num_ent, i, ent_size; - if (size < sizeof(*rec)) { - wil_err_fw(wil, "brd_file record too short: %zu\n", size); - return 0; + if (size <= offsetof(struct wil_fw_record_brd_file, brd_info)) { + wil_err(wil, "board record too short, size %zu\n", size); + return -EINVAL; + } + + ent_size = size - offsetof(struct wil_fw_record_brd_file, brd_info); + max_num_ent = ent_size / sizeof(struct brd_info); + + if (!max_num_ent) { + wil_err(wil, "brd info entries are missing\n"); + return -EINVAL; + } + + wil->brd_info = kcalloc(max_num_ent, sizeof(struct wil_brd_info), + GFP_KERNEL); + if (!wil->brd_info) + return -ENOMEM; + + for (i = 0; i < max_num_ent; i++) { + wil->brd_info[i].file_addr = + le32_to_cpu(rec->brd_info[i].base_addr); + wil->brd_info[i].file_max_size = + le32_to_cpu(rec->brd_info[i].max_size_bytes); + + if (!wil->brd_info[i].file_addr) + break; + + wil_dbg_fw(wil, + "brd info %d: file_addr 0x%x, file_max_size %d\n", + i, wil->brd_info[i].file_addr, + wil->brd_info[i].file_max_size); } - wil->brd_file_addr = le32_to_cpu(rec->base_addr); - wil->brd_file_max_size = le32_to_cpu(rec->max_size_bytes); + wil->num_of_brd_entries = i; + if (wil->num_of_brd_entries == 0) { + kfree(wil->brd_info); + wil->brd_info = NULL; + wil_dbg_fw(wil, + "no valid brd info entries, using brd file addr\n"); - wil_dbg_fw(wil, "brd_file_addr 0x%x, brd_file_max_size %d\n", - wil->brd_file_addr, wil->brd_file_max_size); + } else { + wil_dbg_fw(wil, "num of brd info entries %d\n", + wil->num_of_brd_entries); + } return 0; } @@ -634,6 +658,11 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name, } wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size); + /* re-initialize board info params */ + wil->num_of_brd_entries = 0; + kfree(wil->brd_info); + wil->brd_info = NULL; + for (sz = fw->size, d = fw->data; sz; sz -= rc1, d += rc1) { rc1 = wil_fw_verify(wil, d, sz); if (rc1 < 0) { @@ -647,6 +676,8 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name, out: release_firmware(fw); + if (rc) + wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc); return rc; } @@ -660,11 +691,13 @@ static int wil_brd_process(struct wil6210_priv *wil, const void *data, { int rc = 0; const struct wil_fw_record_head *hdr = data; - size_t s, hdr_sz; + size_t s, hdr_sz = 0; u16 type; + int i = 0; - /* Assuming the board file includes only one header record and one data - * record. Each record starts with wil_fw_record_head. + /* Assuming the board file includes only one file header + * and one or several data records. + * Each record starts with wil_fw_record_head. */ if (size < sizeof(*hdr)) return -EINVAL; @@ -672,40 +705,67 @@ static int wil_brd_process(struct wil6210_priv *wil, const void *data, if (s > size) return -EINVAL; - /* Skip the header record and handle the data record */ - hdr = (const void *)hdr + s; + /* Skip the header record and handle the data records */ size -= s; - if (size < sizeof(*hdr)) - return -EINVAL; - hdr_sz = le32_to_cpu(hdr->size); - if (wil->brd_file_max_size && hdr_sz > wil->brd_file_max_size) - return -EINVAL; - if (sizeof(*hdr) + hdr_sz > size) - return -EINVAL; - if (hdr_sz % 4) { - wil_err_fw(wil, "unaligned record size: %zu\n", - hdr_sz); - return -EINVAL; - } - type = le16_to_cpu(hdr->type); - if (type != wil_fw_type_data) { - wil_err_fw(wil, "invalid record type for board file: %d\n", - type); - return -EINVAL; + for (hdr = data + s;; hdr = (const void *)hdr + s, size -= s, i++) { + if (size < sizeof(*hdr)) + break; + + if (i >= wil->num_of_brd_entries) { + wil_err_fw(wil, + "Too many brd records: %d, num of expected entries %d\n", + i, wil->num_of_brd_entries); + break; + } + + hdr_sz = le32_to_cpu(hdr->size); + s = sizeof(*hdr) + hdr_sz; + if (wil->brd_info[i].file_max_size && + hdr_sz > wil->brd_info[i].file_max_size) + return -EINVAL; + if (sizeof(*hdr) + hdr_sz > size) + return -EINVAL; + if (hdr_sz % 4) { + wil_err_fw(wil, "unaligned record size: %zu\n", + hdr_sz); + return -EINVAL; + } + type = le16_to_cpu(hdr->type); + if (type != wil_fw_type_data) { + wil_err_fw(wil, + "invalid record type for board file: %d\n", + type); + return -EINVAL; + } + if (hdr_sz < sizeof(struct wil_fw_record_data)) { + wil_err_fw(wil, "data record too short: %zu\n", hdr_sz); + return -EINVAL; + } + + wil_dbg_fw(wil, + "using info from fw file for record %d: addr[0x%08x], max size %d\n", + i, wil->brd_info[i].file_addr, + wil->brd_info[i].file_max_size); + + rc = __fw_handle_data(wil, &hdr[1], hdr_sz, + cpu_to_le32(wil->brd_info[i].file_addr)); + if (rc) + return rc; } - if (hdr_sz < sizeof(struct wil_fw_record_data)) { - wil_err_fw(wil, "data record too short: %zu\n", hdr_sz); + + if (size) { + wil_err_fw(wil, "unprocessed bytes: %zu\n", size); + if (size >= sizeof(*hdr)) { + wil_err_fw(wil, + "Stop at offset %ld record type %d [%zd bytes]\n", + (long)((const void *)hdr - data), + le16_to_cpu(hdr->type), hdr_sz); + } return -EINVAL; } - wil_dbg_fw(wil, "using addr from fw file: [0x%08x]\n", - wil->brd_file_addr); - - rc = __fw_handle_data(wil, &hdr[1], hdr_sz, - cpu_to_le32(wil->brd_file_addr)); - - return rc; + return 0; } /** @@ -736,11 +796,14 @@ int wil_request_board(struct wil6210_priv *wil, const char *name) rc = dlen; goto out; } - /* Process the data record */ + + /* Process the data records */ rc = wil_brd_process(wil, brd->data, dlen); out: release_firmware(brd); + if (rc) + wil_err_fw(wil, "Loading <%s> failed, rc %d\n", name, rc); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 3f5bd177d55f..b1480b41cd3a 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/interrupt.h> @@ -296,21 +285,24 @@ void wil_configure_interrupt_moderation(struct wil6210_priv *wil) static irqreturn_t wil6210_irq_rx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - u32 isr = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); + u32 isr; bool need_unmask = true; + wil6210_mask_irq_rx(wil); + + isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + trace_wil6210_irq_rx(isr); wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); if (unlikely(!isr)) { wil_err_ratelimited(wil, "spurious IRQ: RX\n"); + wil6210_unmask_irq_rx(wil); return IRQ_NONE; } - wil6210_mask_irq_rx(wil); - /* RX_DONE and RX_HTRSH interrupts are the same if interrupt * moderation is not used. Interrupt moderation may cause RX * buffer overflow while RX_DONE is delayed. The required @@ -355,21 +347,24 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - u32 isr = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_INT_GEN_RX_ICR) + - offsetof(struct RGF_ICR, ICR)); + u32 isr; bool need_unmask = true; + wil6210_mask_irq_rx_edma(wil); + + isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_RX_ICR) + + offsetof(struct RGF_ICR, ICR)); + trace_wil6210_irq_rx(isr); wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: RX\n"); + wil6210_unmask_irq_rx_edma(wil); return IRQ_NONE; } - wil6210_mask_irq_rx_edma(wil); - if (likely(isr & BIT_RX_STATUS_IRQ)) { wil_dbg_irq(wil, "RX status ring\n"); isr &= ~BIT_RX_STATUS_IRQ; @@ -403,21 +398,24 @@ static irqreturn_t wil6210_irq_rx_edma(int irq, void *cookie) static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - u32 isr = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_INT_GEN_TX_ICR) + - offsetof(struct RGF_ICR, ICR)); + u32 isr; bool need_unmask = true; + wil6210_mask_irq_tx_edma(wil); + + isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_INT_GEN_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + trace_wil6210_irq_tx(isr); wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); if (unlikely(!isr)) { wil_err(wil, "spurious IRQ: TX\n"); + wil6210_unmask_irq_tx_edma(wil); return IRQ_NONE; } - wil6210_mask_irq_tx_edma(wil); - if (likely(isr & BIT_TX_STATUS_IRQ)) { wil_dbg_irq(wil, "TX status ring\n"); isr &= ~BIT_TX_STATUS_IRQ; @@ -446,21 +444,24 @@ static irqreturn_t wil6210_irq_tx_edma(int irq, void *cookie) static irqreturn_t wil6210_irq_tx(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - u32 isr = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_TX_ICR) + - offsetof(struct RGF_ICR, ICR)); + u32 isr; bool need_unmask = true; + wil6210_mask_irq_tx(wil); + + isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_TX_ICR) + + offsetof(struct RGF_ICR, ICR)); + trace_wil6210_irq_tx(isr); wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); if (unlikely(!isr)) { wil_err_ratelimited(wil, "spurious IRQ: TX\n"); + wil6210_unmask_irq_tx(wil); return IRQ_NONE; } - wil6210_mask_irq_tx(wil); - if (likely(isr & BIT_DMA_EP_TX_ICR_TX_DONE)) { wil_dbg_irq(wil, "TX done\n"); isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE; @@ -532,20 +533,23 @@ static bool wil_validate_mbox_regs(struct wil6210_priv *wil) static irqreturn_t wil6210_irq_misc(int irq, void *cookie) { struct wil6210_priv *wil = cookie; - u32 isr = wil_ioread32_and_clear(wil->csr + - HOSTADDR(RGF_DMA_EP_MISC_ICR) + - offsetof(struct RGF_ICR, ICR)); + u32 isr; + + wil6210_mask_irq_misc(wil, false); + + isr = wil_ioread32_and_clear(wil->csr + + HOSTADDR(RGF_DMA_EP_MISC_ICR) + + offsetof(struct RGF_ICR, ICR)); trace_wil6210_irq_misc(isr); wil_dbg_irq(wil, "ISR MISC 0x%08x\n", isr); if (!isr) { wil_err(wil, "spurious IRQ: MISC\n"); + wil6210_unmask_irq_misc(wil, false); return IRQ_NONE; } - wil6210_mask_irq_misc(wil, false); - if (isr & ISR_MISC_FW_ERROR) { u32 fw_assert_code = wil_r(wil, wil->rgf_fw_assert_code_addr); u32 ucode_assert_code = @@ -580,7 +584,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) /* no need to handle HALP ICRs until next vote */ wil->halp.handle_icr = false; wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n"); - wil6210_mask_halp(wil); + wil6210_mask_irq_misc(wil, true); complete(&wil->halp.comp); } } diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 277abfdf3322..06091d8a9e23 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/moduleparam.h> @@ -184,6 +173,28 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, } } +/* Device memory access is prohibited while reset or suspend. + * wil_mem_access_lock protects accessing device memory in these cases + */ +int wil_mem_access_lock(struct wil6210_priv *wil) +{ + if (!down_read_trylock(&wil->mem_lock)) + return -EBUSY; + + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status)) { + up_read(&wil->mem_lock); + return -EBUSY; + } + + return 0; +} + +void wil_mem_access_unlock(struct wil6210_priv *wil) +{ + up_read(&wil->mem_lock); +} + static void wil_ring_fini_tx(struct wil6210_priv *wil, int id) { struct wil_ring *ring = &wil->ring_tx[id]; @@ -219,7 +230,7 @@ static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) { int i; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { if (wil->sta[i].mid == mid && wil->sta[i].status == wil_sta_connected) return true; @@ -318,11 +329,11 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif, wil_dbg_misc(wil, "Disconnect complete %pM, CID=%d, reason=%d\n", bssid, cid, reason_code); - if (cid >= 0) /* disconnect 1 peer */ + if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */ wil_disconnect_cid_complete(vif, cid, reason_code); } else { /* all */ wil_dbg_misc(wil, "Disconnect complete all\n"); - for (cid = 0; cid < max_assoc_sta; cid++) + for (cid = 0; cid < wil->max_assoc_sta; cid++) wil_disconnect_cid_complete(vif, cid, reason_code); } @@ -351,6 +362,7 @@ static void _wil6210_disconnect_complete(struct wil6210_vif *vif, } clear_bit(wil_vif_fwconnecting, vif->status); clear_bit(wil_vif_ft_roam, vif->status); + vif->ptk_rekey_state = WIL_REKEY_IDLE; break; case NL80211_IFTYPE_AP: @@ -430,11 +442,11 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, cid = wil_find_cid(wil, vif->mid, bssid); wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", bssid, cid, reason_code); - if (cid >= 0) /* disconnect 1 peer */ + if (wil_cid_valid(wil, cid)) /* disconnect 1 peer */ wil_disconnect_cid(vif, cid, reason_code); } else { /* all */ wil_dbg_misc(wil, "Disconnect all\n"); - for (cid = 0; cid < max_assoc_sta; cid++) + for (cid = 0; cid < wil->max_assoc_sta; cid++) wil_disconnect_cid(vif, cid, reason_code); } @@ -663,7 +675,7 @@ void wil_bcast_fini_all(struct wil6210_priv *wil) int i; struct wil6210_vif *vif; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (vif) wil_bcast_fini(vif); @@ -702,7 +714,10 @@ int wil_priv_init(struct wil6210_priv *wil) INIT_LIST_HEAD(&wil->pending_wmi_ev); spin_lock_init(&wil->wmi_ev_lock); spin_lock_init(&wil->net_queue_lock); + spin_lock_init(&wil->eap_lock); + init_waitqueue_head(&wil->wq); + init_rwsem(&wil->mem_lock); wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); if (!wil->wmi_wq) @@ -730,6 +745,7 @@ int wil_priv_init(struct wil6210_priv *wil) wil->reply_mid = U8_MAX; wil->max_vifs = 1; + wil->max_assoc_sta = max_assoc_sta; /* edma configuration can be updated via debugfs before allocation */ wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS; @@ -815,6 +831,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->brd_info); } static void wil_shutdown_bl(struct wil6210_priv *wil) @@ -1390,13 +1407,22 @@ static int wil_get_otp_info(struct wil6210_priv *wil) u8 mac[8]; int mac_addr; - if (wil->hw_version >= HW_VER_TALYN_MB) - mac_addr = RGF_OTP_MAC_TALYN_MB; - else - mac_addr = RGF_OTP_MAC; + /* OEM MAC has precedence */ + mac_addr = RGF_OTP_OEM_MAC; + wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), sizeof(mac)); + + if (is_valid_ether_addr(mac)) { + wil_info(wil, "using OEM MAC %pM\n", mac); + } else { + if (wil->hw_version >= HW_VER_TALYN_MB) + mac_addr = RGF_OTP_MAC_TALYN_MB; + else + mac_addr = RGF_OTP_MAC; + + wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), + sizeof(mac)); + } - wil_memcpy_fromio_32(mac, wil->csr + HOSTADDR(mac_addr), - sizeof(mac)); if (!is_valid_ether_addr(mac)) { wil_err(wil, "Invalid MAC %pM\n", mac); return -EINVAL; @@ -1460,7 +1486,7 @@ void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync) lockdep_assert_held(&wil->vif_mutex); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { struct wil6210_vif *vif = wil->vifs[i]; if (vif) @@ -1488,6 +1514,7 @@ int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) static void wil_pre_fw_config(struct wil6210_priv *wil) { + wil_clear_fw_log_addr(wil); /* Mark FW as loaded from host */ wil_s(wil, RGF_USER_USAGE_6, 1); @@ -1500,11 +1527,6 @@ static void wil_pre_fw_config(struct wil6210_priv *wil) if (wil->hw_version < HW_VER_TALYN_MB) { wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); - } else { - wil_s(wil, - RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0); - wil_w(wil, RGF_CAF_ICR_TALYN_MB + - offsetof(struct RGF_ICR, IMV), ~0); } /* clear PAL_UNIT_ICR (potential D0->D3 leftover) * In Talyn-MB host cannot access this register due to @@ -1528,7 +1550,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil) struct wireless_dev *wdev; int i, rc; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (!vif) continue; @@ -1550,6 +1572,20 @@ static int wil_restore_vifs(struct wil6210_priv *wil) } /* + * Clear FW and ucode log start addr to indicate FW log is not ready. The host + * driver clears the addresses before FW starts and FW initializes the address + * when it is ready to send logs. + */ +void wil_clear_fw_log_addr(struct wil6210_priv *wil) +{ + /* FW log addr */ + wil_w(wil, RGF_USER_USAGE_1, 0); + /* ucode log addr */ + wil_w(wil, RGF_USER_USAGE_2, 0); + wil_dbg_misc(wil, "Cleared FW and ucode log address"); +} + +/* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload * the firmware. @@ -1580,7 +1616,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (wil->hw_version == HW_VER_UNKNOWN) return -ENODEV; - if (test_bit(WIL_PLATFORM_CAPA_T_PWR_ON_0, wil->platform_capa)) { + if (test_bit(WIL_PLATFORM_CAPA_T_PWR_ON_0, wil->platform_capa) && + wil->hw_version < HW_VER_TALYN_MB) { wil_dbg_misc(wil, "Notify FW to set T_POWER_ON=0\n"); wil_s(wil, RGF_USER_USAGE_8, BIT_USER_SUPPORT_T_POWER_ON_0); } @@ -1599,25 +1636,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) } set_bit(wil_status_resetting, wil->status); - if (test_bit(wil_status_collecting_dumps, wil->status)) { - /* Device collects crash dump, cancel the reset. - * following crash dump collection, reset would take place. - */ - wil_dbg_misc(wil, "reject reset while collecting crash dump\n"); - rc = -EBUSY; - goto out; - } - mutex_lock(&wil->vif_mutex); wil_abort_scan_all_vifs(wil, false); mutex_unlock(&wil->vif_mutex); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (vif) { cancel_work_sync(&vif->disconnect_worker); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING); + vif->ptk_rekey_state = WIL_REKEY_IDLE; } } wil_bcast_fini_all(wil); @@ -1690,7 +1719,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) rc = wil_request_firmware(wil, wil->wil_fw_name, true); if (rc) goto out; - if (wil->brd_file_addr) + if (wil->num_of_brd_entries) rc = wil_request_board(wil, board_file); else rc = wil_request_firmware(wil, board_file, true); @@ -1782,7 +1811,9 @@ int __wil_up(struct wil6210_priv *wil) WARN_ON(!mutex_is_locked(&wil->mutex)); + down_write(&wil->mem_lock); rc = wil_reset(wil, true); + up_write(&wil->mem_lock); if (rc) return rc; @@ -1854,6 +1885,7 @@ int wil_up(struct wil6210_priv *wil) int __wil_down(struct wil6210_priv *wil) { + int rc; WARN_ON(!mutex_is_locked(&wil->mutex)); set_bit(wil_status_resetting, wil->status); @@ -1873,7 +1905,11 @@ int __wil_down(struct wil6210_priv *wil) wil_abort_scan_all_vifs(wil, false); mutex_unlock(&wil->vif_mutex); - return wil_reset(wil, false); + down_write(&wil->mem_lock); + rc = wil_reset(wil, false); + up_write(&wil->mem_lock); + + return rc; } int wil_down(struct wil6210_priv *wil) @@ -1895,7 +1931,7 @@ int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac) int i; int rc = -ENOENT; - for (i = 0; i < max_assoc_sta; i++) { + for (i = 0; i < wil->max_assoc_sta; i++) { if (wil->sta[i].mid == mid && wil->sta[i].status != wil_sta_unused && ether_addr_equal(wil->sta[i].addr, mac)) { @@ -1912,6 +1948,9 @@ void wil_halp_vote(struct wil6210_priv *wil) unsigned long rc; unsigned long to_jiffies = msecs_to_jiffies(WAIT_FOR_HALP_VOTE_MS); + if (wil->hw_version >= HW_VER_TALYN_MB) + return; + mutex_lock(&wil->halp.lock); wil_dbg_irq(wil, "halp_vote: start, HALP ref_cnt (%d)\n", @@ -1943,6 +1982,9 @@ void wil_halp_vote(struct wil6210_priv *wil) void wil_halp_unvote(struct wil6210_priv *wil) { + if (wil->hw_version >= HW_VER_TALYN_MB) + return; + WARN_ON(wil->halp.ref_cnt == 0); mutex_lock(&wil->halp.lock); diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index b4e0eb1585b9..07b4a252a23c 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. - * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include <linux/etherdevice.h> @@ -27,7 +16,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil, struct wil6210_vif *vif; struct net_device *ndev_i; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (vif) { ndev_i = vif_to_ndev(vif); @@ -155,7 +144,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) struct wil6210_vif *vif; if (!ring->va || !txdata->enabled || - txdata->mid >= wil->max_vifs) + txdata->mid >= GET_MAX_VIFS(wil)) continue; vif = wil->vifs[txdata->mid]; @@ -218,6 +207,7 @@ static void wil_vif_deinit(struct wil6210_vif *vif) cancel_work_sync(&vif->p2p.delayed_listen_work); wil_probe_client_flush(vif); cancel_work_sync(&vif->probe_client_worker); + cancel_work_sync(&vif->enable_tx_key_worker); } void wil_vif_free(struct wil6210_vif *vif) @@ -283,7 +273,9 @@ static void wil_vif_init(struct wil6210_vif *vif) INIT_WORK(&vif->probe_client_worker, wil_probe_client_worker); INIT_WORK(&vif->disconnect_worker, wil_disconnect_worker); + INIT_WORK(&vif->p2p.discovery_expired_work, wil_p2p_listen_expired); INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); + INIT_WORK(&vif->enable_tx_key_worker, wil_enable_tx_key_worker); INIT_LIST_HEAD(&vif->probe_client_pending); @@ -294,7 +286,7 @@ static u8 wil_vif_find_free_mid(struct wil6210_priv *wil) { u8 i; - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { if (!wil->vifs[i]) return i; } @@ -500,7 +492,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) bool any_active = wil_has_active_ifaces(wil, true, false); ASSERT_RTNL(); - if (mid >= wil->max_vifs) { + if (mid >= GET_MAX_VIFS(wil)) { wil_err(wil, "invalid MID: %d\n", mid); return; } @@ -540,6 +532,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) cancel_work_sync(&vif->disconnect_worker); wil_probe_client_flush(vif); cancel_work_sync(&vif->probe_client_worker); + cancel_work_sync(&vif->enable_tx_key_worker); /* for VIFs, ndev will be freed by destructor after RTNL is unlocked. * the main interface will be freed in wil_if_free, we need to keep it * a bit longer so logging macros will work. diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index db087ea58ddf..f26bf046d889 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index c8c6613371d1..c174323c5c0b 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. - * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include <linux/module.h> @@ -142,6 +131,8 @@ int wil_set_capabilities(struct wil6210_priv *wil) min(sizeof(wil->platform_capa), sizeof(platform_capa))); } + wil_info(wil, "platform_capa 0x%lx\n", *wil->platform_capa); + /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, wil->wil_fw_name, false); wil_refresh_fw_capabilities(wil); @@ -176,7 +167,7 @@ static void wil_remove_all_additional_vifs(struct wil6210_priv *wil) struct wil6210_vif *vif; int i; - for (i = 1; i < wil->max_vifs; i++) { + for (i = 1; i < GET_MAX_VIFS(wil); i++) { vif = wil->vifs[i]; if (vif) { wil_vif_prepare_stop(vif); @@ -418,6 +409,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* rollback to bus_disable */ + wil_clear_fw_log_addr(wil); rc = wil_if_add(wil); if (rc) { wil_err(wil, "wil_if_add failed: %d\n", rc); @@ -432,7 +424,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) mutex_unlock(&wil->mutex); if (rc) { wil_err(wil, "failed to load WMI only FW\n"); - goto if_remove; + /* ignore the error to allow debugging */ } } @@ -452,8 +444,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; -if_remove: - wil_if_remove(wil); bus_disable: wil_if_pcie_disable(wil); err_iounmap: @@ -628,8 +618,7 @@ static int __maybe_unused wil6210_pm_resume(struct device *dev) static int __maybe_unused wil6210_pm_runtime_idle(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct wil6210_priv *wil = pci_get_drvdata(pdev); + struct wil6210_priv *wil = dev_get_drvdata(dev); wil_dbg_pm(wil, "Runtime idle\n"); @@ -643,8 +632,7 @@ static int __maybe_unused wil6210_pm_runtime_resume(struct device *dev) static int __maybe_unused wil6210_pm_runtime_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct wil6210_priv *wil = pci_get_drvdata(pdev); + struct wil6210_priv *wil = dev_get_drvdata(dev); if (test_bit(wil_status_suspended, wil->status)) { wil_dbg_pm(wil, "trying to suspend while suspended\n"); diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 75fe9323547c..ed4df561e5c5 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. - * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include "wil6210.h" @@ -26,7 +15,7 @@ static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil) int i; mutex_lock(&wil->vif_mutex); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { struct wil6210_vif *vif = wil->vifs[i]; if (vif && test_bit(wil_vif_fwconnected, vif->status)) @@ -40,7 +29,7 @@ static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil) int i; mutex_lock(&wil->vif_mutex); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { struct wil6210_vif *vif = wil->vifs[i]; if (vif) @@ -123,7 +112,7 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) /* interface is running */ mutex_lock(&wil->vif_mutex); - for (i = 0; i < wil->max_vifs; i++) { + for (i = 0; i < GET_MAX_VIFS(wil); i++) { struct wil6210_vif *vif = wil->vifs[i]; if (!vif) @@ -195,14 +184,18 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) wil_dbg_pm(wil, "suspend keep radio on\n"); /* Prevent handling of new tx and wmi commands */ - set_bit(wil_status_suspending, wil->status); - if (test_bit(wil_status_collecting_dumps, wil->status)) { - /* Device collects crash dump, cancel the suspend */ - wil_dbg_pm(wil, "reject suspend while collecting crash dump\n"); - clear_bit(wil_status_suspending, wil->status); + rc = down_write_trylock(&wil->mem_lock); + if (!rc) { + wil_err(wil, + "device is busy. down_write_trylock failed, returned (0x%x)\n", + rc); wil->suspend_stats.rejected_by_host++; return -EBUSY; } + + set_bit(wil_status_suspending, wil->status); + up_write(&wil->mem_lock); + wil_pm_stop_all_net_queues(wil); if (!wil_is_tx_idle(wil)) { @@ -310,15 +303,18 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) wil_dbg_pm(wil, "suspend radio off\n"); - set_bit(wil_status_suspending, wil->status); - if (test_bit(wil_status_collecting_dumps, wil->status)) { - /* Device collects crash dump, cancel the suspend */ - wil_dbg_pm(wil, "reject suspend while collecting crash dump\n"); - clear_bit(wil_status_suspending, wil->status); + rc = down_write_trylock(&wil->mem_lock); + if (!rc) { + wil_err(wil, + "device is busy. down_write_trylock failed, returned (0x%x)\n", + rc); wil->suspend_stats.rejected_by_host++; return -EBUSY; } + set_bit(wil_status_suspending, wil->status); + up_write(&wil->mem_lock); + /* if netif up, hardware is alive, shut it down */ mutex_lock(&wil->vif_mutex); active_ifaces = wil_has_active_ifaces(wil, true, false); diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index c49f7988369e..9b4ca6b256d2 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c @@ -1,23 +1,13 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc. * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/types.h> #include <linux/errno.h> #include <linux/fs.h> +#include <linux/seq_file.h> #include "wmi.h" #include "wil6210.h" #include "txrx.h" @@ -431,3 +421,28 @@ out: return newpos; } + +int wil_pmcring_read(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct pmc_ctx *pmc = &wil->pmc; + size_t pmc_ring_size = + sizeof(struct vring_rx_desc) * pmc->num_descriptors; + + mutex_lock(&pmc->lock); + + if (!wil_is_pmc_allocated(pmc)) { + wil_err(wil, "error, pmc is not allocated!\n"); + pmc->last_cmd_status = -EPERM; + mutex_unlock(&pmc->lock); + return -EPERM; + } + + wil_dbg_misc(wil, "pmcring_read: size %zu\n", pmc_ring_size); + + seq_write(s, pmc->pring_va, pmc_ring_size); + + mutex_unlock(&pmc->lock); + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/pmc.h b/drivers/net/wireless/ath/wil6210/pmc.h index bebc8d52e1e6..b3d79eb50a43 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.h +++ b/drivers/net/wireless/ath/wil6210/pmc.h @@ -1,18 +1,5 @@ -/* - * Copyright (c) 2012-2015 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ +/* SPDX-License-Identifier: ISC */ +/* Copyright (c) 2012-2015 Qualcomm Atheros, Inc. */ #include <linux/types.h> @@ -25,3 +12,4 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd); int wil_pmc_last_cmd_status(struct wil6210_priv *wil); ssize_t wil_pmc_read(struct file *, char __user *, size_t, loff_t *); loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence); +int wil_pmcring_read(struct seq_file *s, void *data); diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 32b14fc33a59..d385bc03033a 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" @@ -260,7 +249,6 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, r->reorder_buf = kcalloc(size, sizeof(struct sk_buff *), GFP_KERNEL); if (!r->reorder_buf) { - kfree(r->reorder_buf); kfree(r); return NULL; } @@ -316,7 +304,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) u16 agg_timeout = le16_to_cpu(ba_timeout); u16 seq_ctrl = le16_to_cpu(ba_seq_ctrl); struct wil_sta_info *sta; - u16 agg_wsize = 0; + u16 agg_wsize; /* bit 0: A-MSDU supported * bit 1: policy (should be 0 for us) * bits 2..5: TID @@ -328,7 +316,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) test_bit(WMI_FW_CAPABILITY_AMSDU, wil->fw_capabilities) && wil->amsdu_en && (param_set & BIT(0)); int ba_policy = param_set & BIT(1); - u16 status = WLAN_STATUS_SUCCESS; u16 ssn = seq_ctrl >> 4; struct wil_tid_ampdu_rx *r; int rc = 0; @@ -336,7 +323,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) might_sleep(); /* sanity checks */ - if (cid >= max_assoc_sta) { + if (cid >= wil->max_assoc_sta) { wil_err(wil, "BACK: invalid CID %d\n", cid); rc = -EINVAL; goto out; @@ -355,27 +342,19 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) agg_amsdu ? "+" : "-", !!ba_policy, dialog_token, ssn); /* apply policies */ - if (ba_policy) { - wil_err(wil, "BACK requested unsupported ba_policy == 1\n"); - status = WLAN_STATUS_INVALID_QOS_PARAM; - } - if (status == WLAN_STATUS_SUCCESS) { - if (req_agg_wsize == 0) { - wil_dbg_misc(wil, "Suggest BACK wsize %d\n", - wil->max_agg_wsize); - agg_wsize = wil->max_agg_wsize; - } else { - agg_wsize = min_t(u16, - wil->max_agg_wsize, req_agg_wsize); - } + if (req_agg_wsize == 0) { + wil_dbg_misc(wil, "Suggest BACK wsize %d\n", + wil->max_agg_wsize); + agg_wsize = wil->max_agg_wsize; + } else { + agg_wsize = min_t(u16, wil->max_agg_wsize, req_agg_wsize); } rc = wil->txrx_ops.wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, - status, agg_amsdu, agg_wsize, - agg_timeout); - if (rc || (status != WLAN_STATUS_SUCCESS)) { - wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc, - status); + WLAN_STATUS_SUCCESS, agg_amsdu, + agg_wsize, agg_timeout); + if (rc) { + wil_err(wil, "do not apply ba, rc(%d)\n", rc); goto out; } diff --git a/drivers/net/wireless/ath/wil6210/trace.c b/drivers/net/wireless/ath/wil6210/trace.c index cd2534b9c5aa..6909e989baec 100644 --- a/drivers/net/wireless/ath/wil6210/trace.c +++ b/drivers/net/wireless/ath/wil6210/trace.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2013 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h index 36ebfcf9ef30..11c989e95880 100644 --- a/drivers/net/wireless/ath/wil6210/trace.h +++ b/drivers/net/wireless/ath/wil6210/trace.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2013-2016 Qualcomm Atheros, Inc. * Copyright (c) 2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #undef TRACE_SYSTEM diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 4ccfd1404458..8ebc6d59aa74 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/etherdevice.h> @@ -411,7 +400,7 @@ static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb) ta = hdr->addr2; } - if (max_assoc_sta <= WIL6210_RX_DESC_MAX_CID) + if (wil->max_assoc_sta <= WIL6210_RX_DESC_MAX_CID) return cid; /* assuming no concurrency between AP interfaces and STA interfaces. @@ -426,14 +415,14 @@ static int wil_rx_get_cid_by_skb(struct wil6210_priv *wil, struct sk_buff *skb) * to find the real cid, compare transmitter address with the stored * stations mac address in the driver sta array */ - for (i = cid; i < max_assoc_sta; i += WIL6210_RX_DESC_MAX_CID) { + for (i = cid; i < wil->max_assoc_sta; i += WIL6210_RX_DESC_MAX_CID) { if (wil->sta[i].status != wil_sta_unused && ether_addr_equal(wil->sta[i].addr, ta)) { cid = i; break; } } - if (i >= max_assoc_sta) { + if (i >= wil->max_assoc_sta) { wil_err_ratelimited(wil, "Could not find cid for frame with transmit addr = %pM, iftype = %d, frametype = %d, len = %d\n", ta, vif->wdev.iftype, ftype, skb->len); cid = -ENOENT; @@ -725,24 +714,198 @@ static void wil_get_netif_rx_params(struct sk_buff *skb, int *cid, } /* + * Check if skb is ptk eapol key message + * + * returns a pointer to the start of the eapol key structure, NULL + * if frame is not PTK eapol key + */ +static struct wil_eapol_key *wil_is_ptk_eapol_key(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + u8 *buf; + const struct wil_1x_hdr *hdr; + struct wil_eapol_key *key; + u16 key_info; + int len = skb->len; + + if (!skb_mac_header_was_set(skb)) { + wil_err(wil, "mac header was not set\n"); + return NULL; + } + + len -= skb_mac_offset(skb); + + if (len < sizeof(struct ethhdr) + sizeof(struct wil_1x_hdr) + + sizeof(struct wil_eapol_key)) + return NULL; + + buf = skb_mac_header(skb) + sizeof(struct ethhdr); + + hdr = (const struct wil_1x_hdr *)buf; + if (hdr->type != WIL_1X_TYPE_EAPOL_KEY) + return NULL; + + key = (struct wil_eapol_key *)(buf + sizeof(struct wil_1x_hdr)); + if (key->type != WIL_EAPOL_KEY_TYPE_WPA && + key->type != WIL_EAPOL_KEY_TYPE_RSN) + return NULL; + + key_info = be16_to_cpu(key->key_info); + if (!(key_info & WIL_KEY_INFO_KEY_TYPE)) /* check if pairwise */ + return NULL; + + return key; +} + +static bool wil_skb_is_eap_3(struct wil6210_priv *wil, struct sk_buff *skb) +{ + struct wil_eapol_key *key; + u16 key_info; + + key = wil_is_ptk_eapol_key(wil, skb); + if (!key) + return false; + + key_info = be16_to_cpu(key->key_info); + if (key_info & (WIL_KEY_INFO_MIC | + WIL_KEY_INFO_ENCR_KEY_DATA)) { + /* 3/4 of 4-Way Handshake */ + wil_dbg_misc(wil, "EAPOL key message 3\n"); + return true; + } + /* 1/4 of 4-Way Handshake */ + wil_dbg_misc(wil, "EAPOL key message 1\n"); + + return false; +} + +static bool wil_skb_is_eap_4(struct wil6210_priv *wil, struct sk_buff *skb) +{ + struct wil_eapol_key *key; + u32 *nonce, i; + + key = wil_is_ptk_eapol_key(wil, skb); + if (!key) + return false; + + nonce = (u32 *)key->key_nonce; + for (i = 0; i < WIL_EAP_NONCE_LEN / sizeof(u32); i++, nonce++) { + if (*nonce != 0) { + /* message 2/4 */ + wil_dbg_misc(wil, "EAPOL key message 2\n"); + return false; + } + } + wil_dbg_misc(wil, "EAPOL key message 4\n"); + + return true; +} + +void wil_enable_tx_key_worker(struct work_struct *work) +{ + struct wil6210_vif *vif = container_of(work, + struct wil6210_vif, enable_tx_key_worker); + struct wil6210_priv *wil = vif_to_wil(vif); + int rc, cid; + + rtnl_lock(); + if (vif->ptk_rekey_state != WIL_REKEY_WAIT_M4_SENT) { + wil_dbg_misc(wil, "Invalid rekey state = %d\n", + vif->ptk_rekey_state); + rtnl_unlock(); + return; + } + + cid = wil_find_cid_by_idx(wil, vif->mid, 0); + if (!wil_cid_valid(wil, cid)) { + wil_err(wil, "Invalid cid = %d\n", cid); + rtnl_unlock(); + return; + } + + wil_dbg_misc(wil, "Apply PTK key after eapol was sent out\n"); + rc = wmi_add_cipher_key(vif, 0, wil->sta[cid].addr, 0, NULL, + WMI_KEY_USE_APPLY_PTK); + + vif->ptk_rekey_state = WIL_REKEY_IDLE; + rtnl_unlock(); + + if (rc) + wil_err(wil, "Apply PTK key failed %d\n", rc); +} + +void wil_tx_complete_handle_eapol(struct wil6210_vif *vif, struct sk_buff *skb) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wireless_dev *wdev = vif_to_wdev(vif); + bool q = false; + + if (wdev->iftype != NL80211_IFTYPE_STATION || + !test_bit(WMI_FW_CAPABILITY_SPLIT_REKEY, wil->fw_capabilities)) + return; + + /* check if skb is an EAP message 4/4 */ + if (!wil_skb_is_eap_4(wil, skb)) + return; + + spin_lock_bh(&wil->eap_lock); + switch (vif->ptk_rekey_state) { + case WIL_REKEY_IDLE: + /* ignore idle state, can happen due to M4 retransmission */ + break; + case WIL_REKEY_M3_RECEIVED: + vif->ptk_rekey_state = WIL_REKEY_IDLE; + break; + case WIL_REKEY_WAIT_M4_SENT: + q = true; + break; + default: + wil_err(wil, "Unknown rekey state = %d", + vif->ptk_rekey_state); + } + spin_unlock_bh(&wil->eap_lock); + + if (q) { + q = queue_work(wil->wmi_wq, &vif->enable_tx_key_worker); + wil_dbg_misc(wil, "queue_work of enable_tx_key_worker -> %d\n", + q); + } +} + +static void wil_rx_handle_eapol(struct wil6210_vif *vif, struct sk_buff *skb) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wireless_dev *wdev = vif_to_wdev(vif); + + if (wdev->iftype != NL80211_IFTYPE_STATION || + !test_bit(WMI_FW_CAPABILITY_SPLIT_REKEY, wil->fw_capabilities)) + return; + + /* check if skb is a EAP message 3/4 */ + if (!wil_skb_is_eap_3(wil, skb)) + return; + + if (vif->ptk_rekey_state == WIL_REKEY_IDLE) + vif->ptk_rekey_state = WIL_REKEY_M3_RECEIVED; +} + +/* * Pass Rx packet to the netif. Update statistics. * Called in softirq context (NAPI poll). */ -void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) +void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid, + struct wil_net_stats *stats, bool gro) { gro_result_t rc = GRO_NORMAL; struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev); struct wireless_dev *wdev = vif_to_wdev(vif); unsigned int len = skb->len; - int cid; - int security; u8 *sa, *da = wil_skb_get_da(skb); /* here looking for DA, not A1, thus Rxdesc's 'mcast' indication * is not suitable, need to look at data */ int mcast = is_multicast_ether_addr(da); - struct wil_net_stats *stats; struct sk_buff *xmit_skb = NULL; static const char * const gro_res_str[] = { [GRO_MERGED] = "GRO_MERGED", @@ -750,27 +913,9 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) [GRO_HELD] = "GRO_HELD", [GRO_NORMAL] = "GRO_NORMAL", [GRO_DROP] = "GRO_DROP", + [GRO_CONSUMED] = "GRO_CONSUMED", }; - wil->txrx_ops.get_netif_rx_params(skb, &cid, &security); - - stats = &wil->sta[cid].stats; - - skb_orphan(skb); - - if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) { - rc = GRO_DROP; - dev_kfree_skb(skb); - stats->rx_replay++; - goto stats; - } - - /* check errors reported by HW and update statistics */ - if (unlikely(wil->txrx_ops.rx_error_check(wil, skb, stats))) { - dev_kfree_skb(skb); - return; - } - if (wdev->iftype == NL80211_IFTYPE_STATION) { sa = wil_skb_get_sa(skb); if (mcast && ether_addr_equal(sa, ndev->dev_addr)) { @@ -816,7 +961,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) if (skb) { /* deliver to local stack */ skb->protocol = eth_type_trans(skb, ndev); skb->dev = ndev; - rc = napi_gro_receive(&wil->napi_rx, skb); + + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + wil_rx_handle_eapol(vif, skb); + + if (gro) + rc = napi_gro_receive(&wil->napi_rx, skb); + else + netif_rx_ni(skb); wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", len, gro_res_str[rc]); } @@ -836,6 +988,36 @@ stats: } } +void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) +{ + int cid, security; + struct wil6210_priv *wil = ndev_to_wil(ndev); + struct wil_net_stats *stats; + + wil->txrx_ops.get_netif_rx_params(skb, &cid, &security); + + stats = &wil->sta[cid].stats; + + skb_orphan(skb); + + if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) { + wil_dbg_txrx(wil, "Rx drop %d bytes\n", skb->len); + dev_kfree_skb(skb); + ndev->stats.rx_dropped++; + stats->rx_replay++; + stats->rx_dropped++; + return; + } + + /* check errors reported by HW and update statistics */ + if (unlikely(wil->txrx_ops.rx_error_check(wil, skb, stats))) { + dev_kfree_skb(skb); + return; + } + + wil_netif_rx(skb, ndev, cid, stats, true); +} + /** * Proceed all completed skb's from Rx VRING * @@ -1036,7 +1218,8 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, if (!vif->privacy) txdata->dot1x_open = true; rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), - WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); + WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) goto out_free; @@ -1063,7 +1246,7 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, txdata->enabled = 0; spin_unlock_bh(&txdata->lock); wil_vring_free(wil, vring); - wil->ring2cid_tid[id][0] = max_assoc_sta; + wil->ring2cid_tid[id][0] = wil->max_assoc_sta; wil->ring2cid_tid[id][1] = 0; out: @@ -1124,7 +1307,8 @@ static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid, cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), - WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); + WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) goto fail; @@ -1148,7 +1332,7 @@ fail: txdata->dot1x_open = false; txdata->enabled = 0; spin_unlock_bh(&txdata->lock); - wil->ring2cid_tid[ring_id][0] = max_assoc_sta; + wil->ring2cid_tid[ring_id][0] = wil->max_assoc_sta; wil->ring2cid_tid[ring_id][1] = 0; return rc; } @@ -1195,7 +1379,7 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) if (rc) goto out; - wil->ring2cid_tid[id][0] = max_assoc_sta; /* CID */ + wil->ring2cid_tid[id][0] = wil->max_assoc_sta; /* CID */ wil->ring2cid_tid[id][1] = 0; /* TID */ cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); @@ -1204,7 +1388,8 @@ int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) txdata->dot1x_open = true; rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), - WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); + WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) goto out_free; @@ -1243,7 +1428,7 @@ static struct wil_ring *wil_find_tx_ucast(struct wil6210_priv *wil, cid = wil_find_cid(wil, vif->mid, da); - if (cid < 0 || cid >= max_assoc_sta) + if (cid < 0 || cid >= wil->max_assoc_sta) return NULL; /* TODO: fix for multiple TID */ @@ -1295,7 +1480,7 @@ static struct wil_ring *wil_find_tx_ring_sta(struct wil6210_priv *wil, continue; cid = wil->ring2cid_tid[i][0]; - if (cid >= max_assoc_sta) /* skip BCAST */ + if (cid >= wil->max_assoc_sta) /* skip BCAST */ continue; if (!wil->ring_tx_data[i].dot1x_open && @@ -1373,7 +1558,7 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil, continue; cid = wil->ring2cid_tid[i][0]; - if (cid >= max_assoc_sta) /* skip BCAST */ + if (cid >= wil->max_assoc_sta) /* skip BCAST */ continue; if (!wil->ring_tx_data[i].dot1x_open && skb->protocol != cpu_to_be16(ETH_P_PAE)) @@ -1401,7 +1586,7 @@ found: if (!v2->va || txdata2->mid != vif->mid) continue; cid = wil->ring2cid_tid[i][0]; - if (cid >= max_assoc_sta) /* skip BCAST */ + if (cid >= wil->max_assoc_sta) /* skip BCAST */ continue; if (!wil->ring_tx_data[i].dot1x_open && skb->protocol != cpu_to_be16(ETH_P_PAE)) @@ -1653,7 +1838,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, len); } else { frag = &skb_shinfo(skb)->frags[f]; - len = frag->size; + len = skb_frag_size(frag); wil_dbg_txrx(wil, "TSO: frag[%d]: len %u\n", f, len); } @@ -1674,8 +1859,8 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, if (!headlen) { pa = skb_frag_dma_map(dev, frag, - frag->size - len, lenmss, - DMA_TO_DEVICE); + skb_frag_size(frag) - len, + lenmss, DMA_TO_DEVICE); vring->ctx[i].mapped_as = wil_mapped_as_page; } else { pa = dma_map_single(dev, @@ -1760,6 +1945,9 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, } } + if (!_desc) + goto mem_error; + /* first descriptor may also be the last. * in this case d pointer is invalid */ @@ -1893,8 +2081,7 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif, /* middle segments */ for (; f < nr_frags; f++) { - const struct skb_frag_struct *frag = - &skb_shinfo(skb)->frags[f]; + const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; int len = skb_frag_size(frag); *_d = *d; @@ -2254,7 +2441,7 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid) used_before_complete = wil_ring_used_tx(vring); - if (cid < max_assoc_sta) + if (cid < wil->max_assoc_sta) stats = &wil->sta[cid].stats; while (!wil_ring_is_empty(vring)) { @@ -2314,6 +2501,10 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid) if (stats) stats->tx_errors++; } + + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + wil_tx_complete_handle_eapol(vif, skb); + wil_consume_skb(skb, d->dma.error == 0); } memset(ctx, 0, sizeof(*ctx)); diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index c0da1340c2d2..1f4c8ec75be8 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef WIL6210_TXRX_H @@ -423,6 +412,46 @@ struct vring_rx_mac { #define RX_DMA_STATUS_PHY_INFO BIT(6) #define RX_DMA_STATUS_FFM BIT(7) /* EtherType Flex Filter Match */ +/* IEEE 802.11, 8.5.2 EAPOL-Key frames */ +#define WIL_KEY_INFO_KEY_TYPE BIT(3) /* val of 1 = Pairwise, 0 = Group key */ + +#define WIL_KEY_INFO_MIC BIT(8) +#define WIL_KEY_INFO_ENCR_KEY_DATA BIT(12) /* for rsn only */ + +#define WIL_EAP_NONCE_LEN 32 +#define WIL_EAP_KEY_RSC_LEN 8 +#define WIL_EAP_REPLAY_COUNTER_LEN 8 +#define WIL_EAP_KEY_IV_LEN 16 +#define WIL_EAP_KEY_ID_LEN 8 + +enum { + WIL_1X_TYPE_EAP_PACKET = 0, + WIL_1X_TYPE_EAPOL_START = 1, + WIL_1X_TYPE_EAPOL_LOGOFF = 2, + WIL_1X_TYPE_EAPOL_KEY = 3, +}; + +#define WIL_EAPOL_KEY_TYPE_RSN 2 +#define WIL_EAPOL_KEY_TYPE_WPA 254 + +struct wil_1x_hdr { + u8 version; + u8 type; + __be16 length; + /* followed by data */ +} __packed; + +struct wil_eapol_key { + u8 type; + __be16 key_info; + __be16 key_length; + u8 replay_counter[WIL_EAP_REPLAY_COUNTER_LEN]; + u8 key_nonce[WIL_EAP_NONCE_LEN]; + u8 key_iv[WIL_EAP_KEY_IV_LEN]; + u8 key_rsc[WIL_EAP_KEY_RSC_LEN]; + u8 key_id[WIL_EAP_KEY_ID_LEN]; +} __packed; + struct vring_rx_dma { u32 d0; struct wil_ring_dma_addr addr; @@ -646,6 +675,8 @@ static inline void wil_skb_set_cid(struct sk_buff *skb, u8 cid) } void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); +void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid, + struct wil_net_stats *stats, bool gro); void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif, u8 cid, u8 tid, u16 seq); diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index c38773878ae3..778b63be6a9a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2019 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/etherdevice.h> @@ -26,9 +15,14 @@ #include "txrx.h" #include "trace.h" +/* Max number of entries (packets to complete) to update the hwtail of tx + * status ring. Should be power of 2 + */ +#define WIL_EDMA_TX_SRING_UPDATE_HW_TAIL 128 #define WIL_EDMA_MAX_DATA_OFFSET (2) /* RX buffer size must be aligned to 4 bytes */ #define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048) +#define MAX_INVALID_BUFF_ID_RETRY (3) static void wil_tx_desc_unmap_edma(struct device *dev, union wil_tx_desc *desc, @@ -216,10 +210,17 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil, } static inline -void wil_get_next_rx_status_msg(struct wil_status_ring *sring, void *msg) +void wil_get_next_rx_status_msg(struct wil_status_ring *sring, u8 *dr_bit, + void *msg) { - memcpy(msg, (void *)(sring->va + (sring->elem_size * sring->swhead)), - sring->elem_size); + struct wil_rx_status_compressed *_msg; + + _msg = (struct wil_rx_status_compressed *) + (sring->va + (sring->elem_size * sring->swhead)); + *dr_bit = WIL_GET_BITS(_msg->d0, 31, 31); + /* make sure dr_bit is read before the rest of status msg */ + rmb(); + memcpy(msg, (void *)_msg, sring->elem_size); } static inline void wil_sring_advance_swhead(struct wil_status_ring *sring) @@ -268,6 +269,9 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil, struct list_head *active = &wil->rx_buff_mgmt.active; dma_addr_t pa; + if (!wil->rx_buff_mgmt.buff_arr) + return; + while (!list_empty(active)) { struct wil_rx_buff *rx_buff = list_first_entry(active, struct wil_rx_buff, list); @@ -312,7 +316,8 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil, struct list_head *free = &wil->rx_buff_mgmt.free; int i; - wil->rx_buff_mgmt.buff_arr = kcalloc(size, sizeof(struct wil_rx_buff), + wil->rx_buff_mgmt.buff_arr = kcalloc(size + 1, + sizeof(struct wil_rx_buff), GFP_KERNEL); if (!wil->rx_buff_mgmt.buff_arr) return -ENOMEM; @@ -321,14 +326,16 @@ static int wil_init_rx_buff_arr(struct wil6210_priv *wil, INIT_LIST_HEAD(active); INIT_LIST_HEAD(free); - /* Linkify the list */ + /* Linkify the list. + * buffer id 0 should not be used (marks invalid id). + */ buff_arr = wil->rx_buff_mgmt.buff_arr; - for (i = 0; i < size; i++) { + for (i = 1; i <= size; i++) { list_add(&buff_arr[i].list, free); buff_arr[i].id = i; } - wil->rx_buff_mgmt.size = size; + wil->rx_buff_mgmt.size = size + 1; return 0; } @@ -428,6 +435,9 @@ static void wil_ring_free_edma(struct wil6210_priv *wil, struct wil_ring *ring) &ring->pa, ring->ctx); wil_move_all_rx_buff_to_free_list(wil, ring); + dma_free_coherent(dev, sizeof(*ring->edma_rx_swtail.va), + ring->edma_rx_swtail.va, + ring->edma_rx_swtail.pa); goto out; } @@ -573,8 +583,7 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil) if (!sring->va) continue; - wil_get_next_rx_status_msg(sring, msg); - dr_bit = wil_rx_status_get_desc_rdy_bit(msg); + wil_get_next_rx_status_msg(sring, &dr_bit, msg); /* Check if there are unhandled RX status messages */ if (dr_bit == sring->desc_rdy_pol) @@ -727,7 +736,7 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, txdata->enabled = 0; spin_unlock_bh(&txdata->lock); wil_ring_free_edma(wil, ring); - wil->ring2cid_tid[ring_id][0] = max_assoc_sta; + wil->ring2cid_tid[ring_id][0] = wil->max_assoc_sta; wil->ring2cid_tid[ring_id][1] = 0; out: @@ -804,18 +813,9 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil, struct sk_buff *skb, struct wil_net_stats *stats) { - int error; int l2_rx_status; - int l3_rx_status; - int l4_rx_status; void *msg = wil_skb_rxstatus(skb); - error = wil_rx_status_get_error(msg); - if (!error) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - return 0; - } - l2_rx_status = wil_rx_status_get_l2_rx_status(msg); if (l2_rx_status != 0) { wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n", @@ -844,17 +844,7 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil, return -EFAULT; } - l3_rx_status = wil_rx_status_get_l3_rx_status(msg); - l4_rx_status = wil_rx_status_get_l4_rx_status(msg); - if (!l3_rx_status && !l4_rx_status) - skb->ip_summed = CHECKSUM_UNNECESSARY; - /* If HW reports bad checksum, let IP stack re-check it - * For example, HW don't understand Microsoft IP stack that - * mis-calculates TCP checksum - if it should be 0x0, - * it writes 0xffff in violation of RFC 1624 - */ - else - stats->rx_csum_err++; + skb->ip_summed = wil_rx_status_get_checksum(msg, stats); return 0; } @@ -883,8 +873,7 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil, BUILD_BUG_ON(sizeof(struct wil_rx_status_extended) > sizeof(skb->cb)); again: - wil_get_next_rx_status_msg(sring, msg); - dr_bit = wil_rx_status_get_desc_rdy_bit(msg); + wil_get_next_rx_status_msg(sring, &dr_bit, msg); /* Completed handling all the ready status messages */ if (dr_bit != sring->desc_rdy_pol) @@ -892,26 +881,50 @@ again: /* Extract the buffer ID from the status message */ buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg)); - if (unlikely(!wil_val_in_range(buff_id, 0, wil->rx_buff_mgmt.size))) { + + while (!buff_id) { + struct wil_rx_status_extended *s; + int invalid_buff_id_retry = 0; + + wil_dbg_txrx(wil, + "buff_id is not updated yet by HW, (swhead 0x%x)\n", + sring->swhead); + if (++invalid_buff_id_retry > MAX_INVALID_BUFF_ID_RETRY) + break; + + /* Read the status message again */ + s = (struct wil_rx_status_extended *) + (sring->va + (sring->elem_size * sring->swhead)); + *(struct wil_rx_status_extended *)msg = *s; + buff_id = le16_to_cpu(wil_rx_status_get_buff_id(msg)); + } + + if (unlikely(!wil_val_in_range(buff_id, 1, wil->rx_buff_mgmt.size))) { wil_err(wil, "Corrupt buff_id=%d, sring->swhead=%d\n", buff_id, sring->swhead); + wil_rx_status_reset_buff_id(sring); wil_sring_advance_swhead(sring); + sring->invalid_buff_id_cnt++; goto again; } - wil_sring_advance_swhead(sring); - /* Extract the SKB from the rx_buff management array */ skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb; wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL; if (!skb) { wil_err(wil, "No Rx skb at buff_id %d\n", buff_id); + wil_rx_status_reset_buff_id(sring); /* Move the buffer from the active list to the free list */ - list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, - &wil->rx_buff_mgmt.free); + list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list, + &wil->rx_buff_mgmt.free); + wil_sring_advance_swhead(sring); + sring->invalid_buff_id_cnt++; goto again; } + wil_rx_status_reset_buff_id(sring); + wil_sring_advance_swhead(sring); + memcpy(&pa, skb->cb, sizeof(pa)); dma_unmap_single(dev, pa, sz, DMA_FROM_DEVICE); dmalen = le16_to_cpu(wil_rx_status_get_length(msg)); @@ -926,13 +939,13 @@ again: sizeof(struct wil_rx_status_extended), false); /* Move the buffer from the active list to the free list */ - list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list, - &wil->rx_buff_mgmt.free); + list_move_tail(&wil->rx_buff_mgmt.buff_arr[buff_id].list, + &wil->rx_buff_mgmt.free); eop = wil_rx_status_get_eop(msg); cid = wil_rx_status_get_cid(msg); - if (unlikely(!wil_val_in_range(cid, 0, max_assoc_sta))) { + if (unlikely(!wil_val_in_range(cid, 0, wil->max_assoc_sta))) { wil_err(wil, "Corrupt cid=%d, sring->swhead=%d\n", cid, sring->swhead); rxdata->skipping = true; @@ -940,8 +953,8 @@ again: } stats = &wil->sta[cid].stats; - if (unlikely(skb->len < ETH_HLEN)) { - wil_dbg_txrx(wil, "Short frame, len = %d\n", skb->len); + if (unlikely(dmalen < ETH_HLEN)) { + wil_dbg_txrx(wil, "Short frame, len = %d\n", dmalen); stats->rx_short_frame++; rxdata->skipping = true; goto skipping; @@ -1004,6 +1017,8 @@ skipping: stats->last_mcs_rx = wil_rx_status_get_mcs(msg); if (stats->last_mcs_rx < ARRAY_SIZE(stats->rx_per_mcs)) stats->rx_per_mcs[stats->last_mcs_rx]++; + + stats->last_cb_mode_rx = wil_rx_status_get_cb_mode(msg); } if (!wil->use_rx_hw_reordering && !wil->use_compressed_rx_status && @@ -1114,12 +1129,15 @@ static int wil_tx_desc_map_edma(union wil_tx_desc *desc, } static inline void -wil_get_next_tx_status_msg(struct wil_status_ring *sring, +wil_get_next_tx_status_msg(struct wil_status_ring *sring, u8 *dr_bit, struct wil_ring_tx_status *msg) { struct wil_ring_tx_status *_msg = (struct wil_ring_tx_status *) (sring->va + (sring->elem_size * sring->swhead)); + *dr_bit = _msg->desc_ready >> TX_STATUS_DESC_READY_POS; + /* make sure dr_bit is read before the rest of status msg */ + rmb(); *msg = *_msg; } @@ -1140,7 +1158,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, struct wil_net_stats *stats; struct wil_tx_enhanced_desc *_d; unsigned int ring_id; - unsigned int num_descs; + unsigned int num_descs, num_statuses = 0; int i; u8 dr_bit; /* Descriptor Ready bit */ struct wil_ring_tx_status msg; @@ -1148,8 +1166,7 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, int used_before_complete; int used_new; - wil_get_next_tx_status_msg(sring, &msg); - dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS; + wil_get_next_tx_status_msg(sring, &dr_bit, &msg); /* Process completion messages while DR bit has the expected polarity */ while (dr_bit == sring->desc_rdy_pol) { @@ -1187,7 +1204,8 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, ndev = vif_to_ndev(vif); cid = wil->ring2cid_tid[ring_id][0]; - stats = (cid < max_assoc_sta ? &wil->sta[cid].stats : NULL); + stats = (cid < wil->max_assoc_sta) ? &wil->sta[cid].stats : + NULL; wil_dbg_txrx(wil, "tx_status: completed desc_ring (%d), num_descs (%d)\n", @@ -1235,6 +1253,10 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, if (stats) stats->tx_errors++; } + + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + wil_tx_complete_handle_eapol(vif, skb); + wil_consume_skb(skb, msg.status == 0); } memset(ctx, 0, sizeof(*ctx)); @@ -1260,18 +1282,23 @@ int wil_tx_sring_handler(struct wil6210_priv *wil, } again: + num_statuses++; + if (num_statuses % WIL_EDMA_TX_SRING_UPDATE_HW_TAIL == 0) + /* update HW tail to allow HW to push new statuses */ + wil_w(wil, sring->hwtail, sring->swhead); + wil_sring_advance_swhead(sring); - wil_get_next_tx_status_msg(sring, &msg); - dr_bit = msg.desc_ready >> TX_STATUS_DESC_READY_POS; + wil_get_next_tx_status_msg(sring, &dr_bit, &msg); } /* shall we wake net queues? */ if (desc_cnt) wil_update_net_queues(wil, vif, NULL, false); - /* Update the HW tail ptr (RD ptr) */ - wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size); + if (num_statuses % WIL_EDMA_TX_SRING_UPDATE_HW_TAIL != 0) + /* Update the HW tail ptr (RD ptr) */ + wil_w(wil, sring->hwtail, (sring->swhead - 1) % sring->size); return desc_cnt; } @@ -1445,7 +1472,7 @@ static int __wil_tx_ring_tso_edma(struct wil6210_priv *wil, /* Rest of the descriptors are from the SKB fragments */ for (f = 0; f < nr_frags; f++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; - int len = frag->size; + int len = skb_frag_size(frag); wil_dbg_txrx(wil, "TSO: frag[%d]: len %u, descs_used %d\n", f, len, descs_used); diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index 343516a03a1e..c744c65225da 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* - * Copyright (c) 2012-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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2012-2016,2018-2019, The Linux Foundation. All rights reserved. */ #ifndef WIL6210_TXRX_EDMA_H @@ -24,7 +13,7 @@ #define WIL_SRING_SIZE_ORDER_MAX (WIL_RING_SIZE_ORDER_MAX) /* RX sring order should be bigger than RX ring order */ #define WIL_RX_SRING_SIZE_ORDER_DEFAULT (12) -#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (12) +#define WIL_TX_SRING_SIZE_ORDER_DEFAULT (14) #define WIL_RX_BUFF_ARR_SIZE_DEFAULT (2600) #define WIL_DEFAULT_RX_STATUS_RING_ID 0 @@ -366,6 +355,12 @@ static inline u8 wil_rx_status_get_mcs(void *msg) 16, 21); } +static inline u8 wil_rx_status_get_cb_mode(void *msg) +{ + return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d1, + 22, 23); +} + static inline u16 wil_rx_status_get_flow_id(void *msg) { return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, @@ -415,16 +410,16 @@ static inline u8 wil_rx_status_get_tid(void *msg) return val & WIL_RX_EDMA_DLPF_LU_MISS_CID_TID_MASK; } -static inline int wil_rx_status_get_desc_rdy_bit(void *msg) +static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */ { return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, - 31, 31); + 30, 30); } -static inline int wil_rx_status_get_eop(void *msg) /* EoP = End of Packet */ +static inline void wil_rx_status_reset_buff_id(struct wil_status_ring *s) { - return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, - 30, 30); + ((struct wil_rx_status_compressed *) + (s->va + (s->elem_size * s->swhead)))->buff_id = 0; } static inline __le16 wil_rx_status_get_buff_id(void *msg) @@ -511,6 +506,45 @@ static inline int wil_rx_status_get_l4_rx_status(void *msg) 5, 6); } +/* L4 L3 Expected result + * 0 0 Ok. No L3 and no L4 known protocols found. + * Treated as L2 packet. (no offloads on this packet) + * 0 1 Ok. It means that L3 was found, and checksum check passed. + * No known L4 protocol was found. + * 0 2 It means that L3 protocol was found, and checksum check failed. + * No L4 known protocol was found. + * 1 any Ok. It means that L4 was found, and checksum check passed. + * 3 0 Not a possible scenario. + * 3 1 Recalculate. It means that L3 protocol was found, and checksum + * passed. But L4 checksum failed. Need to see if really failed, + * or due to fragmentation. + * 3 2 Both L3 and L4 checksum check failed. + */ +static inline int wil_rx_status_get_checksum(void *msg, + struct wil_net_stats *stats) +{ + int l3_rx_status = wil_rx_status_get_l3_rx_status(msg); + int l4_rx_status = wil_rx_status_get_l4_rx_status(msg); + + if (l4_rx_status == 1) + return CHECKSUM_UNNECESSARY; + + if (l4_rx_status == 0 && l3_rx_status == 1) + return CHECKSUM_UNNECESSARY; + + if (l3_rx_status == 0 && l4_rx_status == 0) + /* L2 packet */ + return CHECKSUM_NONE; + + /* If HW reports bad checksum, let IP stack re-check it + * For example, HW doesn't understand Microsoft IP stack that + * mis-calculates TCP checksum - if it should be 0x0, + * it writes 0xffff in violation of RFC 1624 + */ + stats->rx_csum_err++; + return CHECKSUM_NONE; +} + static inline int wil_rx_status_get_security(void *msg) { return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index e1b1039b13ab..97626bfd4dac 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __WIL6210_H__ @@ -99,6 +88,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL_MAX_AMPDU_SIZE_128 (128 * 1024) /* FW/HW limit */ #define WIL_MAX_AGG_WSIZE_64 (64) /* FW/HW limit */ #define WIL6210_MAX_STATUS_RINGS (8) +#define WIL_WMI_CALL_GENERAL_TO_MS 100 /* Hardware offload block adds the following: * 26 bytes - 3-address QoS data header @@ -185,6 +175,7 @@ struct RGF_ICR { /* registers - FW addresses */ #define RGF_USER_USAGE_1 (0x880004) +#define RGF_USER_USAGE_2 (0x880008) #define RGF_USER_USAGE_6 (0x880018) #define BIT_USER_OOB_MODE BIT(31) #define BIT_USER_OOB_R2_MODE BIT(30) @@ -334,6 +325,11 @@ struct RGF_ICR { #define BIT_BOOT_FROM_ROM BIT(31) /* eDMA */ +#define RGF_SCM_PTRS_SUBQ_RD_PTR (0x8b4000) +#define RGF_SCM_PTRS_COMPQ_RD_PTR (0x8b4100) +#define RGF_DMA_SCM_SUBQ_CONS (0x8b60ec) +#define RGF_DMA_SCM_COMPQ_PROD (0x8b616c) + #define RGF_INT_COUNT_ON_SPECIAL_EVT (0x8b62d8) #define RGF_INT_CTRL_INT_GEN_CFG_0 (0x8bc000) @@ -367,6 +363,7 @@ struct RGF_ICR { #define REVISION_ID_SPARROW_D0 (0x3) #define RGF_OTP_MAC_TALYN_MB (0x8a0304) +#define RGF_OTP_OEM_MAC (0x8a0334) #define RGF_OTP_MAC (0x8a0620) /* Talyn-MB */ @@ -454,15 +451,6 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid) *tid = (cidxtid >> 4) & 0xf; } -/** - * wil_cid_valid - check cid is valid - * @cid: CID value - */ -static inline bool wil_cid_valid(u8 cid) -{ - return (cid >= 0 && cid < max_assoc_sta); -} - struct wil6210_mbox_ring { u32 base; u16 entry_size; /* max. size of mbox entry, incl. all headers */ @@ -566,10 +554,11 @@ struct wil_status_ring { bool is_rx; u8 desc_rdy_pol; /* Expected descriptor ready bit polarity */ struct wil_ring_rx_data rx_data; + u32 invalid_buff_id_cnt; /* relevant only for RX */ }; #define WIL_STA_TID_NUM (16) -#define WIL_MCS_MAX (12) /* Maximum MCS supported */ +#define WIL_MCS_MAX (15) /* Maximum MCS supported */ struct wil_net_stats { unsigned long rx_packets; @@ -590,6 +579,7 @@ struct wil_net_stats { unsigned long rx_amsdu_error; /* eDMA specific */ unsigned long rx_csum_err; u16 last_mcs_rx; + u8 last_cb_mode_rx; u64 rx_per_mcs[WIL_MCS_MAX + 1]; u32 ft_roams; /* relevant in STA mode */ }; @@ -660,7 +650,6 @@ enum { /* for wil6210_priv.status */ wil_status_suspending, /* suspend in progress */ wil_status_suspended, /* suspend completed, device is suspended */ wil_status_resuming, /* resume in progress */ - wil_status_collecting_dumps, /* crashdump collection in progress */ wil_status_last /* keep last */ }; @@ -731,6 +720,12 @@ enum wil_sta_status { wil_sta_connected = 2, }; +enum wil_rekey_state { + WIL_REKEY_IDLE = 0, + WIL_REKEY_M3_RECEIVED = 1, + WIL_REKEY_WAIT_M4_SENT = 2, +}; + /** * struct wil_sta_info - data for peer * @@ -851,6 +846,7 @@ struct wil6210_vif { DECLARE_BITMAP(status, wil_vif_status_last); u32 privacy; /* secure connection? */ u16 channel; /* relevant in AP mode */ + u8 wmi_edmg_channel; /* relevant in AP mode */ u8 hidden_ssid; /* relevant in AP mode */ u32 ap_isolate; /* no intra-BSS communication */ bool pbss; @@ -878,6 +874,10 @@ struct wil6210_vif { int net_queue_stopped; /* netif_tx_stop_all_queues invoked */ bool fw_stats_ready; /* per-cid statistics are ready inside sta_info */ u64 fw_stats_tsf; /* measurement timestamp */ + + /* PTK rekey race prevention, this is relevant to station mode only */ + enum wil_rekey_state ptk_rekey_state; + struct work_struct enable_tx_key_worker; }; /** @@ -911,6 +911,11 @@ struct wil_fw_stats_global { struct wmi_link_stats_global stats; }; +struct wil_brd_info { + u32 file_addr; + u32 file_max_size; +}; + struct wil6210_priv { struct pci_dev *pdev; u32 bar_size; @@ -925,8 +930,8 @@ struct wil6210_priv { const char *hw_name; const char *wil_fw_name; char *board_file; - u32 brd_file_addr; - u32 brd_file_max_size; + u32 num_of_brd_entries; + struct wil_brd_info *brd_info; DECLARE_BITMAP(hw_capa, hw_capa_last); DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX); DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX); @@ -938,6 +943,8 @@ struct wil6210_priv { struct wil6210_vif *vifs[WIL_MAX_VIFS]; struct mutex vif_mutex; /* protects access to VIF entries */ atomic_t connected_vifs; + u32 max_assoc_sta; /* max sta's supported by the driver and the FW */ + /* profile */ struct cfg80211_chan_def monitor_chandef; u32 monitor_flags; @@ -971,6 +978,7 @@ struct wil6210_priv { */ spinlock_t wmi_ev_lock; spinlock_t net_queue_lock; /* guarding stop/wake netif queue */ + spinlock_t eap_lock; /* guarding access to eap rekey fields */ struct napi_struct napi_rx; struct napi_struct napi_tx; struct net_device napi_ndev; /* dummy net_device serving all VIFs */ @@ -992,6 +1000,8 @@ struct wil6210_priv { struct wil_txrx_ops txrx_ops; struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ + /* for synchronizing device memory access while reset or suspend */ + struct rw_semaphore mem_lock; /* statistics */ atomic_t isr_count_rx, isr_count_tx; /* debugfs */ @@ -1060,6 +1070,7 @@ struct wil6210_priv { #define vif_to_wil(v) (v->wil) #define vif_to_ndev(v) (v->ndev) #define vif_to_wdev(v) (&v->wdev) +#define GET_MAX_VIFS(wil) min_t(int, (wil)->max_vifs, WIL_MAX_VIFS) static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil, struct wireless_dev *wdev) @@ -1132,6 +1143,14 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) wil_w(wil, reg, wil_r(wil, reg) & ~val); } +/** + * wil_cid_valid - check cid is valid + */ +static inline bool wil_cid_valid(struct wil6210_priv *wil, int cid) +{ + return (cid >= 0 && cid < wil->max_assoc_sta); +} + void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len); #if defined(CONFIG_DYNAMIC_DEBUG) @@ -1176,6 +1195,8 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, size_t count); void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count); +int wil_mem_access_lock(struct wil6210_priv *wil); +void wil_mem_access_unlock(struct wil6210_priv *wil); struct wil6210_vif * wil_vif_alloc(struct wil6210_priv *wil, const char *name, @@ -1205,6 +1226,7 @@ int __wil_down(struct wil6210_priv *wil); void wil_refresh_fw_capabilities(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac); +int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx); void wil_set_ethtoolops(struct net_device *ndev); struct fw_map *wil_find_fw_mapping(const char *section); @@ -1234,6 +1256,9 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring); int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); +int wmi_get_all_temperatures(struct wil6210_priv *wil, + struct wmi_temp_sense_all_done_event + *sense_all_evt); int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason, bool del_sta); int wmi_addba(struct wil6210_priv *wil, u8 mid, @@ -1313,7 +1338,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil); int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan, - u8 hidden_ssid, u8 is_go); + u8 edmg_chan, u8 hidden_ssid, u8 is_go); int wmi_pcp_stop(struct wil6210_vif *vif); int wmi_led_cfg(struct wil6210_priv *wil, bool enable); int wmi_abort_scan(struct wil6210_vif *vif); @@ -1327,6 +1352,7 @@ void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid, void wil_probe_client_flush(struct wil6210_vif *vif); void wil_probe_client_worker(struct work_struct *work); void wil_disconnect_worker(struct work_struct *work); +void wil_enable_tx_key_worker(struct work_struct *work); void wil_init_txrx_ops(struct wil6210_priv *wil); @@ -1343,6 +1369,8 @@ void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif, struct wil_ring *ring, bool check_stop); netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); int wil_tx_complete(struct wil6210_vif *vif, int ringid); +void wil_tx_complete_handle_eapol(struct wil6210_vif *vif, + struct sk_buff *skb); void wil6210_unmask_irq_tx(struct wil6210_priv *wil); void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil); @@ -1388,6 +1416,11 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil); int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len); int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, u8 channel, u16 duration_ms); +int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold); + +int wil_wmi2spec_ch(u8 wmi_ch, u8 *spec_ch); +int wil_spec2wmi_ch(u8 spec_ch, u8 *wmi_ch); +void wil_update_supported_bands(struct wil6210_priv *wil); int reverse_memcmp(const void *cs, const void *ct, size_t count); @@ -1406,4 +1439,5 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, void update_supported_bands(struct wil6210_priv *wil); +void wil_clear_fw_log_addr(struct wil6210_priv *wil); #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c index dc33a0b4c3fa..1332eb8c831f 100644 --- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2015,2017 Qualcomm Atheros, Inc. - * Copyright (c) 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include "wil6210.h" @@ -57,7 +46,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil, int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) { - int i; + int i, rc; const struct fw_map *map; void *data; u32 host_min, dump_size, offset, len; @@ -73,14 +62,9 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) return -EINVAL; } - set_bit(wil_status_collecting_dumps, wil->status); - if (test_bit(wil_status_suspending, wil->status) || - test_bit(wil_status_suspended, wil->status) || - test_bit(wil_status_resetting, wil->status)) { - wil_err(wil, "cannot collect fw dump during suspend/reset\n"); - clear_bit(wil_status_collecting_dumps, wil->status); - return -EINVAL; - } + rc = wil_mem_access_lock(wil); + if (rc) + return rc; /* copy to crash dump area */ for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { @@ -100,8 +84,7 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) wil_memcpy_fromio_32((void * __force)(dest + offset), (const void __iomem * __force)data, len); } - - clear_bit(wil_status_collecting_dumps, wil->status); + wil_mem_access_unlock(wil); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index 4eed05bddb60..10e10dc9fedf 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* - * Copyright (c) 2014 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. */ #include <linux/device.h> diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index bca090611477..5ff66202238d 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __WIL_PLATFORM_H__ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index bda4a9712f91..7a0d934eb271 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, 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 - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/moduleparam.h> @@ -40,7 +29,7 @@ MODULE_PARM_DESC(led_id, " 60G device led enablement. Set the led ID (0-2) to enable"); #define WIL_WAIT_FOR_SUSPEND_RESUME_COMP 200 -#define WIL_WMI_CALL_GENERAL_TO_MS 100 +#define WIL_WMI_PCP_STOP_TO_MS 5000 /** * WMI event receiving - theory of operations @@ -483,6 +472,10 @@ static const char *cmdid2name(u16 cmdid) return "WMI_FT_REASSOC_CMD"; case WMI_UPDATE_FT_IES_CMDID: return "WMI_UPDATE_FT_IES_CMD"; + case WMI_RBUFCAP_CFG_CMDID: + return "WMI_RBUFCAP_CFG_CMD"; + case WMI_TEMP_SENSE_ALL_CMDID: + return "WMI_TEMP_SENSE_ALL_CMDID"; default: return "Untracked CMD"; } @@ -627,6 +620,10 @@ static const char *eventid2name(u16 eventid) return "WMI_FT_AUTH_STATUS_EVENT"; case WMI_FT_REASSOC_STATUS_EVENTID: return "WMI_FT_REASSOC_STATUS_EVENT"; + case WMI_RBUFCAP_CFG_EVENTID: + return "WMI_RBUFCAP_CFG_EVENT"; + case WMI_TEMP_SENSE_ALL_DONE_EVENTID: + return "WMI_TEMP_SENSE_ALL_DONE_EVENTID"; default: return "Untracked EVENT"; } @@ -805,8 +802,8 @@ static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len) } } - max_assoc_sta = min_t(uint, max_assoc_sta, fw_max_assoc_sta); - wil_dbg_wmi(wil, "setting max assoc sta to %d\n", max_assoc_sta); + wil->max_assoc_sta = min_t(uint, max_assoc_sta, fw_max_assoc_sta); + wil_dbg_wmi(wil, "setting max assoc sta to %d\n", wil->max_assoc_sta); wil_set_recovery_state(wil, fw_recovery_idle); set_bit(wil_status_fwready, wil->status); @@ -870,6 +867,12 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) if (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)) { struct cfg80211_bss *bss; + struct cfg80211_inform_bss bss_data = { + .chan = channel, + .scan_width = NL80211_BSS_CHAN_WIDTH_20, + .signal = signal, + .boottime_ns = ktime_to_ns(ktime_get_boottime()), + }; u64 tsf = le64_to_cpu(rx_mgmt_frame->u.beacon.timestamp); u16 cap = le16_to_cpu(rx_mgmt_frame->u.beacon.capab_info); u16 bi = le16_to_cpu(rx_mgmt_frame->u.beacon.beacon_int); @@ -884,8 +887,9 @@ static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) wil_dbg_wmi(wil, "Capability info : 0x%04x\n", cap); - bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame, - d_len, signal, GFP_KERNEL); + bss = cfg80211_inform_bss_frame_data(wiphy, &bss_data, + rx_mgmt_frame, + d_len, GFP_KERNEL); if (bss) { wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid); @@ -973,7 +977,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) evt->assoc_req_len, evt->assoc_resp_len); return; } - if (evt->cid >= max_assoc_sta) { + if (evt->cid >= wil->max_assoc_sta) { wil_err(wil, "Connect CID invalid : %d\n", evt->cid); return; } @@ -1235,7 +1239,7 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len) return; cid = wil->ring2cid_tid[vri][0]; - if (!wil_cid_valid(cid)) { + if (!wil_cid_valid(wil, cid)) { wil_err(wil, "invalid cid %d for vring %d\n", cid, vri); return; } @@ -1324,6 +1328,12 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) cid = evt->cid; tid = evt->tid; } + + if (!wil_cid_valid(wil, cid)) { + wil_err(wil, "DELBA: Invalid CID %d\n", cid); + return; + } + wil_dbg_wmi(wil, "DELBA MID %d CID %d TID %d from %s reason %d\n", vif->mid, cid, tid, evt->from_initiator ? "originator" : "recipient", @@ -1377,6 +1387,10 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len) __le16 fc; u32 d_len; struct cfg80211_bss *bss; + struct cfg80211_inform_bss bss_data = { + .scan_width = NL80211_BSS_CHAN_WIDTH_20, + .boottime_ns = ktime_to_ns(ktime_get_boottime()), + }; if (flen < 0) { wil_err(wil, "sched scan result event too short, len %d\n", @@ -1419,8 +1433,10 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len) return; } - bss = cfg80211_inform_bss_frame(wiphy, channel, rx_mgmt_frame, - d_len, signal, GFP_KERNEL); + bss_data.signal = signal; + bss_data.chan = channel; + bss = cfg80211_inform_bss_frame_data(wiphy, &bss_data, rx_mgmt_frame, + d_len, GFP_KERNEL); if (bss) { wil_dbg_wmi(wil, "Added BSS %pM\n", rx_mgmt_frame->bssid); cfg80211_put_bss(wiphy, bss); @@ -1438,7 +1454,7 @@ static void wil_link_stats_store_basic(struct wil6210_vif *vif, u8 cid = basic->cid; struct wil_sta_info *sta; - if (cid < 0 || cid >= max_assoc_sta) { + if (cid < 0 || cid >= wil->max_assoc_sta) { wil_err(wil, "invalid cid %d\n", cid); return; } @@ -1588,7 +1604,7 @@ static int wil_find_cid_ringid_sta(struct wil6210_priv *wil, continue; lcid = wil->ring2cid_tid[i][0]; - if (lcid >= max_assoc_sta) /* skip BCAST */ + if (lcid >= wil->max_assoc_sta) /* skip BCAST */ continue; wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid); @@ -2050,7 +2066,8 @@ int wmi_echo(struct wil6210_priv *wil) }; return wmi_call(wil, WMI_ECHO_CMDID, vif->mid, &cmd, sizeof(cmd), - WMI_ECHO_RSP_EVENTID, NULL, 0, 50); + WMI_ECHO_RSP_EVENTID, NULL, 0, + WIL_WMI_CALL_GENERAL_TO_MS); } int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) @@ -2109,7 +2126,7 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable) rc = wmi_call(wil, WMI_LED_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply), - 100); + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) goto out; @@ -2123,8 +2140,39 @@ out: return rc; } -int wmi_pcp_start(struct wil6210_vif *vif, - int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go) +int wmi_rbufcap_cfg(struct wil6210_priv *wil, bool enable, u16 threshold) +{ + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + int rc; + + struct wmi_rbufcap_cfg_cmd cmd = { + .enable = enable, + .rx_desc_threshold = cpu_to_le16(threshold), + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_rbufcap_cfg_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + + rc = wmi_call(wil, WMI_RBUFCAP_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), + WMI_RBUFCAP_CFG_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) + return rc; + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "RBUFCAP_CFG failed. status %d\n", + reply.evt.status); + rc = -EINVAL; + } + + return rc; +} + +int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, + u8 chan, u8 wmi_edmg_chan, u8 hidden_ssid, u8 is_go) { struct wil6210_priv *wil = vif_to_wil(vif); int rc; @@ -2134,7 +2182,8 @@ int wmi_pcp_start(struct wil6210_vif *vif, .network_type = wmi_nettype, .disable_sec_offload = 1, .channel = chan - 1, - .pcp_max_assoc_sta = max_assoc_sta, + .edmg_channel = wmi_edmg_chan, + .pcp_max_assoc_sta = wil->max_assoc_sta, .hidden_ssid = hidden_ssid, .is_go = is_go, .ap_sme_offload_mode = disable_ap_sme ? @@ -2195,7 +2244,8 @@ int wmi_pcp_stop(struct wil6210_vif *vif) return rc; return wmi_call(wil, WMI_PCP_STOP_CMDID, vif->mid, NULL, 0, - WMI_PCP_STOPPED_EVENTID, NULL, 0, 20); + WMI_PCP_STOPPED_EVENTID, NULL, 0, + WIL_WMI_PCP_STOP_TO_MS); } int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid) @@ -2226,7 +2276,8 @@ int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid) memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_GET_SSID_CMDID, vif->mid, NULL, 0, - WMI_GET_SSID_EVENTID, &reply, sizeof(reply), 20); + WMI_GET_SSID_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2263,7 +2314,8 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel) memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, vif->mid, NULL, 0, - WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20); + WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2359,7 +2411,8 @@ int wmi_stop_discovery(struct wil6210_vif *vif) wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n"); rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0, - WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100); + WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) wil_err(wil, "Failed to stop discovery\n"); @@ -2393,10 +2446,17 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index, .key_len = key_len, }; - if (!key || (key_len > sizeof(cmd.key))) + if (key_len > sizeof(cmd.key)) + return -EINVAL; + + /* key len = 0 is allowed only for usage of WMI_KEY_USE_APPLY */ + if ((key_len == 0 || !key) && + key_usage != WMI_KEY_USE_APPLY_PTK) return -EINVAL; - memcpy(cmd.key, key, key_len); + if (key) + memcpy(cmd.key, key, key_len); + if (mac_addr) memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); @@ -2434,7 +2494,8 @@ int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie) cmd->mgmt_frm_type = type; /* BUG: FW API define ieLen as u8. Will fix FW */ cmd->ie_len = cpu_to_le16(ie_len); - memcpy(cmd->ie_info, ie, ie_len); + if (ie_len) + memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len); kfree(cmd); out: @@ -2470,7 +2531,8 @@ int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie) } cmd->ie_len = cpu_to_le16(ie_len); - memcpy(cmd->ie_info, ie, ie_len); + if (ie_len) + memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len); kfree(cmd); @@ -2505,12 +2567,14 @@ int wmi_rxon(struct wil6210_priv *wil, bool on) if (on) { rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0, WMI_LISTEN_STARTED_EVENTID, - &reply, sizeof(reply), 100); + &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) rc = -EINVAL; } else { rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0, - WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); + WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, + WIL_WMI_CALL_GENERAL_TO_MS); } return rc; @@ -2599,7 +2663,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, vif->mid, &cmd, sizeof(cmd), - WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100); + WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2611,6 +2676,44 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) return 0; } +int wmi_get_all_temperatures(struct wil6210_priv *wil, + struct wmi_temp_sense_all_done_event + *sense_all_evt) +{ + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + int rc; + struct wmi_temp_sense_all_cmd cmd = { + .measure_baseband_en = true, + .measure_rf_en = true, + .measure_mode = TEMPERATURE_MEASURE_NOW, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_temp_sense_all_done_event evt; + } __packed reply; + + if (!sense_all_evt) { + wil_err(wil, "Invalid sense_all_evt value\n"); + return -EINVAL; + } + + memset(&reply, 0, sizeof(reply)); + reply.evt.status = WMI_FW_STATUS_FAILURE; + rc = wmi_call(wil, WMI_TEMP_SENSE_ALL_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_TEMP_SENSE_ALL_DONE_EVENTID, + &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) + return rc; + + if (reply.evt.status == WMI_FW_STATUS_FAILURE) { + wil_err(wil, "Failed getting TEMP_SENSE_ALL\n"); + return -EINVAL; + } + + memcpy(sense_all_evt, &reply.evt, sizeof(reply.evt)); + return 0; +} + int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason, bool del_sta) { @@ -2713,7 +2816,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, .dialog_token = token, .status_code = cpu_to_le16(status), /* bit 0: A-MSDU supported - * bit 1: policy (should be 0 for us) + * bit 1: policy (controlled by FW) * bits 2..5: TID * bits 6..15: buffer size */ @@ -2743,7 +2846,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, mid, &cmd, sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), - 100); + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2767,7 +2870,7 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, u8 tid, .dialog_token = token, .status_code = cpu_to_le16(status), /* bit 0: A-MSDU supported - * bit 1: policy (should be 0 for us) + * bit 1: policy (controlled by FW) * bits 2..5: TID * bits 6..15: buffer size */ @@ -2825,7 +2928,7 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply), - 100); + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2862,7 +2965,7 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short) rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), - 100); + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2892,7 +2995,7 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short) memset(&reply, 0, sizeof(reply)); rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, vif->mid, NULL, 0, WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), - 100); + WIL_WMI_CALL_GENERAL_TO_MS); if (rc) return rc; @@ -2957,6 +3060,10 @@ static const char *suspend_status2name(u8 status) switch (status) { case WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE: return "LINK_NOT_IDLE"; + case WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT: + return "DISCONNECT"; + case WMI_TRAFFIC_SUSPEND_REJECTED_OTHER: + return "OTHER"; default: return "Untracked status"; } @@ -3046,6 +3153,9 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size) if (triggers & WMI_RESUME_TRIGGER_WMI_EVT) strlcat(string, " WMI_EVT", str_size); + + if (triggers & WMI_RESUME_TRIGGER_DISCONNECT) + strlcat(string, " DISCONNECT", str_size); } int wmi_resume(struct wil6210_priv *wil) @@ -3196,7 +3306,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, if (mid == MID_BROADCAST) mid = 0; - if (mid >= ARRAY_SIZE(wil->vifs) || mid >= wil->max_vifs) { + if (mid >= GET_MAX_VIFS(wil)) { wil_dbg_wmi(wil, "invalid mid %d, event skipped\n", mid); return; @@ -3211,7 +3321,18 @@ static void wmi_event_handle(struct wil6210_priv *wil, /* check if someone waits for this event */ if (wil->reply_id && wil->reply_id == id && wil->reply_mid == mid) { - WARN_ON(wil->reply_buf); + if (wil->reply_buf) { + /* event received while wmi_call is waiting + * with a buffer. Such event should be handled + * in wmi_recv_cmd function. Handling the event + * here means a previous wmi_call was timeout. + * Drop the event and do not handle it. + */ + wil_err(wil, + "Old event (%d, %s) while wmi_call is waiting. Drop it and Continue waiting\n", + id, eventid2name(id)); + return; + } wmi_evt_call_handler(vif, id, evt_data, len - sizeof(*wmi)); @@ -3502,8 +3623,9 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len) rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { - wil_err(wil, "mgmt_tx failed with status %d\n", evt.evt.status); - rc = -EINVAL; + wil_dbg_wmi(wil, "mgmt_tx failed with status %d\n", + evt.evt.status); + rc = -EAGAIN; } kfree(cmd); @@ -3555,9 +3677,9 @@ int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len, rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) { - wil_err(wil, "mgmt_tx_ext failed with status %d\n", - evt.evt.status); - rc = -EINVAL; + wil_dbg_wmi(wil, "mgmt_tx_ext failed with status %d\n", + evt.evt.status); + rc = -EAGAIN; } kfree(cmd); @@ -3790,6 +3912,7 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id) .ring_size = cpu_to_le16(ring->size), .ring_id = ring_id, }, + .max_msdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), .status_ring_id = wil->tx_sring_idx, .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, }; diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index b668758da994..6bd4ccee28ab 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: ISC */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2006-2012 Wilocity - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* @@ -35,6 +24,7 @@ #define WMI_PROX_RANGE_NUM (3) #define WMI_MAX_LOSS_DMG_BEACONS (20) #define MAX_NUM_OF_SECTORS (128) +#define WMI_INVALID_TEMPERATURE (0xFFFFFFFF) #define WMI_SCHED_MAX_ALLOCS_PER_CMD (4) #define WMI_RF_DTYPE_LENGTH (3) #define WMI_RF_ETYPE_LENGTH (3) @@ -64,6 +54,7 @@ #define WMI_QOS_MAX_WEIGHT 50 #define WMI_QOS_SET_VIF_PRIORITY (0xFF) #define WMI_QOS_DEFAULT_PRIORITY (WMI_QOS_NUM_OF_PRIORITY) +#define WMI_MAX_XIF_PORTS_NUM (8) /* Mailbox interface * used for commands and events @@ -95,6 +86,7 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13, WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14, WMI_FW_CAPABILITY_PNO = 15, + WMI_FW_CAPABILITY_CHANNEL_BONDING = 17, WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18, WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19, WMI_FW_CAPABILITY_MULTI_VIFS = 20, @@ -104,6 +96,9 @@ enum wmi_fw_capability { WMI_FW_CAPABILITY_RAW_MODE = 24, WMI_FW_CAPABILITY_TX_REQ_EXT = 25, WMI_FW_CAPABILITY_CHANNEL_4 = 26, + WMI_FW_CAPABILITY_IPA = 27, + WMI_FW_CAPABILITY_TEMPERATURE_ALL_RF = 30, + WMI_FW_CAPABILITY_SPLIT_REKEY = 31, WMI_FW_CAPABILITY_MAX, }; @@ -294,6 +289,8 @@ enum wmi_command_id { WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F, WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10, WMI_SET_VRING_PRIORITY_CMDID = 0xA11, + WMI_RBUFCAP_CFG_CMDID = 0xA12, + WMI_TEMP_SENSE_ALL_CMDID = 0xA13, WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_ABORT_SCAN_CMDID = 0xF007, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, @@ -355,6 +352,19 @@ enum wmi_connect_ctrl_flag_bits { #define WMI_MAX_SSID_LEN (32) +enum wmi_channel { + WMI_CHANNEL_1 = 0x00, + WMI_CHANNEL_2 = 0x01, + WMI_CHANNEL_3 = 0x02, + WMI_CHANNEL_4 = 0x03, + WMI_CHANNEL_5 = 0x04, + WMI_CHANNEL_6 = 0x05, + WMI_CHANNEL_9 = 0x06, + WMI_CHANNEL_10 = 0x07, + WMI_CHANNEL_11 = 0x08, + WMI_CHANNEL_12 = 0x09, +}; + /* WMI_CONNECT_CMDID */ struct wmi_connect_cmd { u8 network_type; @@ -366,8 +376,12 @@ struct wmi_connect_cmd { u8 group_crypto_len; u8 ssid_len; u8 ssid[WMI_MAX_SSID_LEN]; + /* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is + * the primary channel number + */ u8 channel; - u8 reserved0; + /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */ + u8 edmg_channel; u8 bssid[WMI_MAC_LEN]; __le32 ctrl_flags; u8 dst_mac[WMI_MAC_LEN]; @@ -397,6 +411,8 @@ enum wmi_key_usage { WMI_KEY_USE_PAIRWISE = 0x00, WMI_KEY_USE_RX_GROUP = 0x01, WMI_KEY_USE_TX_GROUP = 0x02, + WMI_KEY_USE_STORE_PTK = 0x03, + WMI_KEY_USE_APPLY_PTK = 0x04, }; struct wmi_add_cipher_key_cmd { @@ -979,10 +995,22 @@ enum wmi_rx_msg_type { WMI_RX_MSG_TYPE_EXTENDED = 0x01, }; +enum wmi_ring_add_irq_mode { + /* Backwards compatibility + * for DESC ring - interrupt disabled + * for STATUS ring - interrupt enabled + */ + WMI_RING_ADD_IRQ_MODE_BWC = 0x00, + WMI_RING_ADD_IRQ_MODE_DISABLE = 0x01, + WMI_RING_ADD_IRQ_MODE_ENABLE = 0x02, +}; + struct wmi_tx_status_ring_add_cmd { struct wmi_edma_ring_cfg ring_cfg; u8 irq_index; - u8 reserved[3]; + /* wmi_ring_add_irq_mode */ + u8 irq_mode; + u8 reserved[2]; } __packed; struct wmi_rx_status_ring_add_cmd { @@ -1016,7 +1044,10 @@ struct wmi_tx_desc_ring_add_cmd { u8 mac_ctrl; u8 to_resolution; u8 agg_max_wsize; - u8 reserved[3]; + u8 irq_index; + /* wmi_ring_add_irq_mode */ + u8 irq_mode; + u8 reserved; struct wmi_vring_cfg_schd schd_params; } __packed; @@ -1394,12 +1425,7 @@ struct wmi_rf_xpm_write_cmd { u8 data_bytes[0]; } __packed; -/* WMI_TEMP_SENSE_CMDID - * - * Measure MAC and radio temperatures - * - * Possible modes for temperature measurement - */ +/* Possible modes for temperature measurement */ enum wmi_temperature_measure_mode { TEMPERATURE_USE_OLD_VALUE = 0x01, TEMPERATURE_MEASURE_NOW = 0x02, @@ -1925,6 +1951,14 @@ struct wmi_set_ap_slot_size_cmd { __le32 slot_size; } __packed; +/* WMI_TEMP_SENSE_ALL_CMDID */ +struct wmi_temp_sense_all_cmd { + u8 measure_baseband_en; + u8 measure_rf_en; + u8 measure_mode; + u8 reserved; +} __packed; + /* WMI Events * List of Events (target to host) */ @@ -1982,6 +2016,7 @@ enum wmi_event_id { WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, + WMI_BF_TRIG_EVENTID = 0x183A, WMI_RS_MGMT_DONE_EVENTID = 0x1852, WMI_RF_MGMT_STATUS_EVENTID = 0x1853, WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838, @@ -2082,6 +2117,8 @@ enum wmi_event_id { WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F, WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10, WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11, + WMI_RBUFCAP_CFG_EVENTID = 0x1A12, + WMI_TEMP_SENSE_ALL_DONE_EVENTID = 0x1A13, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, @@ -2267,7 +2304,9 @@ struct wmi_notify_req_done_event { __le32 status; __le64 tsf; s8 rssi; - u8 reserved0[3]; + /* enum wmi_edmg_tx_mode */ + u8 tx_mode; + u8 reserved0[2]; __le32 tx_tpt; __le32 tx_goodput; __le32 rx_goodput; @@ -2283,8 +2322,12 @@ struct wmi_notify_req_done_event { /* WMI_CONNECT_EVENTID */ struct wmi_connect_event { + /* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is + * the primary channel number + */ u8 channel; - u8 reserved0; + /* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */ + u8 edmg_channel; u8 bssid[WMI_MAC_LEN]; __le16 listen_interval; __le16 beacon_interval; @@ -2316,6 +2359,7 @@ enum wmi_disconnect_reason { WMI_DIS_REASON_PROFILE_MISMATCH = 0x0C, WMI_DIS_REASON_CONNECTION_EVICTED = 0x0D, WMI_DIS_REASON_IBSS_MERGE = 0x0E, + WMI_DIS_REASON_HIGH_TEMPERATURE = 0x0F, }; /* WMI_DISCONNECT_EVENTID */ @@ -2762,11 +2806,13 @@ struct wmi_fixed_scheduling_ul_config_event { */ struct wmi_temp_sense_done_event { /* Temperature times 1000 (actual temperature will be achieved by - * dividing the value by 1000) + * dividing the value by 1000). When temperature cannot be read from + * device return WMI_INVALID_TEMPERATURE */ __le32 baseband_t1000; /* Temperature times 1000 (actual temperature will be achieved by - * dividing the value by 1000) + * dividing the value by 1000). When temperature cannot be read from + * device return WMI_INVALID_TEMPERATURE */ __le32 rf_t1000; } __packed; @@ -3168,6 +3214,30 @@ struct wmi_brp_set_ant_limit_event { u8 reserved[3]; } __packed; +enum wmi_bf_type { + WMI_BF_TYPE_SLS = 0x00, + WMI_BF_TYPE_BRP_RX = 0x01, +}; + +/* WMI_BF_TRIG_CMDID */ +struct wmi_bf_trig_cmd { + /* enum wmi_bf_type - type of requested beamforming */ + u8 bf_type; + /* used only for WMI_BF_TYPE_BRP_RX */ + u8 cid; + /* used only for WMI_BF_TYPE_SLS */ + u8 dst_mac[WMI_MAC_LEN]; + u8 reserved[4]; +} __packed; + +/* WMI_BF_TRIG_EVENTID */ +struct wmi_bf_trig_event { + /* enum wmi_fw_status */ + u8 status; + u8 cid; + u8 reserved[2]; +} __packed; + /* broadcast connection ID */ #define WMI_LINK_MAINTAIN_CFG_CID_BROADCAST (0xFFFFFFFF) @@ -3263,6 +3333,8 @@ struct wmi_link_maintain_cfg_read_done_event { enum wmi_traffic_suspend_status { WMI_TRAFFIC_SUSPEND_APPROVED = 0x0, WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE = 0x1, + WMI_TRAFFIC_SUSPEND_REJECTED_DISCONNECT = 0x2, + WMI_TRAFFIC_SUSPEND_REJECTED_OTHER = 0x3, }; /* WMI_TRAFFIC_SUSPEND_EVENTID */ @@ -3282,6 +3354,7 @@ enum wmi_resume_trigger { WMI_RESUME_TRIGGER_UCAST_RX = 0x2, WMI_RESUME_TRIGGER_BCAST_RX = 0x4, WMI_RESUME_TRIGGER_WMI_EVT = 0x8, + WMI_RESUME_TRIGGER_DISCONNECT = 0x10, }; /* WMI_TRAFFIC_RESUME_EVENTID */ @@ -4057,4 +4130,59 @@ struct wmi_set_vring_priority_event { u8 reserved[3]; } __packed; +/* WMI_RADAR_PCI_CTRL_BLOCK struct */ +struct wmi_radar_pci_ctrl_block { + /* last fw tail address index */ + __le32 fw_tail_index; + /* last SW head address index known to FW */ + __le32 sw_head_index; + __le32 last_wr_pulse_tsf_low; + __le32 last_wr_pulse_count; + __le32 last_wr_in_bytes; + __le32 last_wr_pulse_id; + __le32 last_wr_burst_id; + /* When pre overflow detected, advance sw head in unit of pulses */ + __le32 sw_head_inc; + __le32 reserved[8]; +} __packed; + +/* WMI_RBUFCAP_CFG_CMD */ +struct wmi_rbufcap_cfg_cmd { + u8 enable; + u8 reserved; + /* RBUFCAP indicates rx space unavailable when number of rx + * descriptors drops below this threshold. Set 0 to use system + * default + */ + __le16 rx_desc_threshold; +} __packed; + +/* WMI_RBUFCAP_CFG_EVENTID */ +struct wmi_rbufcap_cfg_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_TEMP_SENSE_ALL_DONE_EVENTID + * Measure MAC and all radio temperatures + */ +struct wmi_temp_sense_all_done_event { + /* enum wmi_fw_status */ + u8 status; + /* Bitmap of connected RFs */ + u8 rf_bitmap; + u8 reserved[2]; + /* Temperature times 1000 (actual temperature will be achieved by + * dividing the value by 1000). When temperature cannot be read from + * device return WMI_INVALID_TEMPERATURE + */ + __le32 rf_t1000[WMI_MAX_XIF_PORTS_NUM]; + /* Temperature times 1000 (actual temperature will be achieved by + * dividing the value by 1000). When temperature cannot be read from + * device return WMI_INVALID_TEMPERATURE + */ + __le32 baseband_t1000; +} __packed; + #endif /* __WILOCITY_WMI_H__ */ |