Loading drivers/net/wireless/ath/wil6210/cfg80211.c +338 −63 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ #include "fw.h" #define WIL_MAX_ROC_DURATION_MS 5000 #define CTRY_CHINA "CN" #define WIL_BRD_SUFFIX_CN "CN" #define WIL_BRD_SUFFIX_FCC "FCC" bool disable_ap_sme; module_param(disable_ap_sme, bool, 0444); Loading Loading @@ -50,7 +51,26 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(1, 0), CHAN60G(2, 0), CHAN60G(3, 0), /* channel 4 not supported yet */ CHAN60G(4, 0), }; struct wil_regd_2_brd_suffix { const char regdomain[3]; /* alpha2 */ const char *brd_suffix; }; static struct wil_regd_2_brd_suffix wil_regd_2_brd_suffix_map[] = { {"BO", WIL_BRD_SUFFIX_FCC}, {"CN", WIL_BRD_SUFFIX_CN}, {"EC", WIL_BRD_SUFFIX_FCC}, {"GU", WIL_BRD_SUFFIX_FCC}, {"HN", WIL_BRD_SUFFIX_FCC}, {"JM", WIL_BRD_SUFFIX_FCC}, {"MX", WIL_BRD_SUFFIX_FCC}, {"NI", WIL_BRD_SUFFIX_FCC}, {"PY", WIL_BRD_SUFFIX_FCC}, {"TT", WIL_BRD_SUFFIX_FCC}, {"US", WIL_BRD_SUFFIX_FCC}, }; enum wil_nl_60g_cmd_type { Loading Loading @@ -96,6 +116,26 @@ struct wil_nl_60g_debug_force_wmi { u32 enable; } __packed; static int wil_num_supported_channels(struct wil6210_priv *wil) { int num_channels = ARRAY_SIZE(wil_60ghz_channels); if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities)) num_channels--; return num_channels; } void update_supported_bands(struct wil6210_priv *wil) { struct wiphy *wiphy = wil_to_wiphy(wil); wil_dbg_misc(wil, "update supported bands"); wiphy->bands[NL80211_BAND_60GHZ]->n_channels = wil_num_supported_channels(wil); } /* Vendor id to be used in vendor specific command and events * to user space. * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, Loading Loading @@ -362,7 +402,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = { .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_RESP >> 4) | BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) | BIT(IEEE80211_STYPE_DISASSOC >> 4), BIT(IEEE80211_STYPE_DISASSOC >> 4) | BIT(IEEE80211_STYPE_AUTH >> 4) | BIT(IEEE80211_STYPE_REASSOC_RESP >> 4), .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | Loading Loading @@ -1114,6 +1156,26 @@ static void wil_print_crypto(struct wil6210_priv *wil, c->control_port_no_encrypt); } static const char * wil_get_auth_type_name(enum nl80211_auth_type auth_type) { switch (auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: return "OPEN_SYSTEM"; case NL80211_AUTHTYPE_SHARED_KEY: return "SHARED_KEY"; case NL80211_AUTHTYPE_FT: return "FT"; case NL80211_AUTHTYPE_NETWORK_EAP: return "NETWORK_EAP"; case NL80211_AUTHTYPE_SAE: return "SAE"; case NL80211_AUTHTYPE_AUTOMATIC: return "AUTOMATIC"; default: return "unknown"; } } static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { Loading @@ -1127,11 +1189,82 @@ static void wil_print_connect_params(struct wil6210_priv *wil, if (sme->ssid) print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); if (sme->prev_bssid) wil_info(wil, " Previous BSSID=%pM\n", sme->prev_bssid); wil_info(wil, " Auth Type: %s\n", wil_get_auth_type_name(sme->auth_type)); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); wil_info(wil, " PBSS: %d\n", sme->pbss); wil_print_crypto(wil, &sme->crypto); } static int wil_ft_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = ndev_to_vif(ndev); struct wmi_ft_auth_cmd auth_cmd; int rc; if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { wil_err(wil, "FT: FW does not support FT roaming\n"); return -EOPNOTSUPP; } if (!sme->prev_bssid) { wil_err(wil, "FT: prev_bssid was not set\n"); return -EINVAL; } if (ether_addr_equal(sme->prev_bssid, sme->bssid)) { wil_err(wil, "FT: can not roam to same AP\n"); return -EINVAL; } if (!test_bit(wil_vif_fwconnected, vif->status)) { wil_err(wil, "FT: roam while not connected\n"); return -EINVAL; } if (vif->privacy != sme->privacy) { wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n", vif->privacy, sme->privacy); return -EINVAL; } if (sme->pbss) { wil_err(wil, "FT: roam is not valid for PBSS\n"); return -EINVAL; } memset(&auth_cmd, 0, sizeof(auth_cmd)); auth_cmd.channel = sme->channel->hw_value - 1; ether_addr_copy(auth_cmd.bssid, sme->bssid); if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) if (wil->force_edmg_channel) { rc = wil_spec2wmi_ch(wil->force_edmg_channel, &auth_cmd.channel); if (rc) wil_err(wil, "FT: wmi channel for channel %d not found", wil->force_edmg_channel); } wil_info(wil, "FT: roaming\n"); set_bit(wil_vif_ft_roam, vif->status); rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid, &auth_cmd, sizeof(auth_cmd)); if (rc == 0) mod_timer(&vif->connect_timer, jiffies + msecs_to_jiffies(5000)); else clear_bit(wil_vif_ft_roam, vif->status); return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) Loading @@ -1144,11 +1277,20 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, const u8 *rsn_eid; int ch; int rc = 0; bool is_ft_roam = false; u8 network_type; enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS; wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid); wil_print_connect_params(wil, sme); if (sme->auth_type == NL80211_AUTHTYPE_FT) is_ft_roam = true; if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC && test_bit(wil_vif_fwconnected, vif->status)) is_ft_roam = true; if (!is_ft_roam) if (test_bit(wil_vif_fwconnecting, vif->status) || test_bit(wil_vif_fwconnected, vif->status)) return -EALREADY; Loading @@ -1161,8 +1303,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rsn_eid = sme->ie ? cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : NULL; if (sme->privacy && !rsn_eid) if (sme->privacy && !rsn_eid) { wil_info(wil, "WSC connection\n"); if (is_ft_roam) { wil_err(wil, "No WSC with FT roam\n"); return -EINVAL; } } if (sme->pbss) bss_type = IEEE80211_BSS_TYPE_PBSS; Loading @@ -1184,6 +1331,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, vif->privacy = sme->privacy; vif->pbss = sme->pbss; rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); if (rc) goto out; switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) { case WLAN_CAPABILITY_DMG_TYPE_AP: network_type = WMI_NETTYPE_INFRA; break; case WLAN_CAPABILITY_DMG_TYPE_PBSS: network_type = WMI_NETTYPE_P2P; break; default: wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", bss->capability); rc = -EINVAL; goto out; } ch = bss->channel->hw_value; if (ch == 0) { wil_err(wil, "BSS at unknown frequency %dMhz\n", bss->channel->center_freq); rc = -EOPNOTSUPP; goto out; } if (is_ft_roam) { if (network_type != WMI_NETTYPE_INFRA) { wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n", bss->capability); rc = -EINVAL; goto out; } rc = wil_ft_connect(wiphy, ndev, sme); if (rc == 0) vif->bss = bss; goto out; } if (vif->privacy) { /* For secure assoc, remove old keys */ rc = wmi_del_cipher_key(vif, 0, bss->bssid, Loading @@ -1200,28 +1386,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } } /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info * elements. Send it also in case it's empty, to erase previously set * ies in FW. */ rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); if (rc) goto out; /* WMI_CONNECT_CMD */ memset(&conn, 0, sizeof(conn)); switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) { case WLAN_CAPABILITY_DMG_TYPE_AP: conn.network_type = WMI_NETTYPE_INFRA; break; case WLAN_CAPABILITY_DMG_TYPE_PBSS: conn.network_type = WMI_NETTYPE_P2P; break; default: wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", bss->capability); goto out; } conn.network_type = network_type; if (vif->privacy) { if (rsn_eid) { /* regular secure connection */ conn.dot11_auth_mode = WMI_AUTH11_SHARED; Loading @@ -1241,14 +1408,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, conn.ssid_len = min_t(u8, ssid_eid[1], 32); memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); ch = bss->channel->hw_value; if (ch == 0) { wil_err(wil, "BSS at unknown frequency %dMhz\n", bss->channel->center_freq); rc = -EOPNOTSUPP; goto out; } conn.channel = ch - 1; if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) Loading Loading @@ -1454,7 +1613,7 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid, return &wil->sta[cid]; } static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, struct wil_sta_info *cs, struct key_params *params) { Loading Loading @@ -1539,12 +1698,18 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, params->seq_len, params->seq); if (IS_ERR(cs)) { /* in FT, sta info may not be available as add_key may be * sent by host before FW sends WMI_CONNECT_EVENT */ if (!test_bit(wil_vif_ft_roam, vif->status)) { wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n", mac_addr, key_usage_str[key_usage], key_index, params->seq_len, params->seq); return -EINVAL; } } if (!IS_ERR(cs)) wil_del_rx_key(key_index, key_usage, cs); if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) { Loading @@ -1558,7 +1723,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len, params->key, key_usage); if (!rc) if (!rc && !IS_ERR(cs)) /* in FT set crypto will take place upon receiving * WMI_RING_EN_EVENTID event */ wil_set_crypto_rx(key_index, key_usage, cs, params); return rc; Loading Loading @@ -1721,21 +1889,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) } /* internal functions for device reset and starting AP */ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, struct cfg80211_beacon_data *bcon) static u8 * _wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len, u16 *ies_len) { int rc; u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp = NULL; u8 *ies = NULL; if (bcon->probe_resp) { if (proberesp) { struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; (struct ieee80211_mgmt *)proberesp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); proberesp = f->u.probe_resp.variable; proberesp_len = bcon->probe_resp_len - hlen; ies = f->u.probe_resp.variable; if (ies_len) *ies_len = proberesp_len - hlen; } return ies; } static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, struct cfg80211_beacon_data *bcon) { int rc; u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp; proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, bcon->probe_resp_len, &proberesp_len); rc = _wil_cfg80211_merge_extra_ies(proberesp, proberesp_len, bcon->proberesp_ies, Loading Loading @@ -1779,6 +1962,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, struct wireless_dev *wdev = ndev->ieee80211_ptr; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO); u16 proberesp_len = 0; u8 *proberesp; bool ft = false; if (pbss) wmi_nettype = WMI_NETTYPE_P2P; Loading @@ -1791,6 +1977,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, wil_set_recovery_state(wil, fw_recovery_idle); proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, bcon->probe_resp_len, &proberesp_len); /* check that the probe response IEs has a MDE */ if ((proberesp && proberesp_len > 0 && cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN, proberesp, proberesp_len))) ft = true; if (ft) { if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { wil_err(wil, "FW does not support FT roaming\n"); return -ENOTSUPP; } set_bit(wil_vif_ft_roam, vif->status); } mutex_lock(&wil->mutex); if (!wil_has_other_active_ifaces(wil, ndev, true, false)) { Loading Loading @@ -1952,6 +2157,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); wmi_pcp_stop(vif); clear_bit(wil_vif_ft_roam, vif->status); if (last) __wil_down(wil); Loading @@ -1971,8 +2177,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy, struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "add station %pM aid %d mid %d\n", mac, params->aid, vif->mid); wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n", mac, params->aid, vif->mid, params->sta_flags_mask, params->sta_flags_set); if (!disable_ap_sme) { wil_err(wil, "not supported with AP SME enabled\n"); Loading Loading @@ -2294,24 +2501,43 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, return 0; } static void wil_get_brd_reg_suffix(struct wil6210_priv *wil, const u8 *new_regdomain, char *brd_reg_suffix, size_t len) { int i; struct wil_regd_2_brd_suffix *entry; for (i = 0; i < ARRAY_SIZE(wil_regd_2_brd_suffix_map); i++) { entry = &wil_regd_2_brd_suffix_map[i]; if (!memcmp(entry->regdomain, new_regdomain, 2)) { strlcpy(brd_reg_suffix, entry->brd_suffix, len); return; } } /* regdomain not found in our map, set suffix to none */ brd_reg_suffix[0] = '\0'; } static int wil_switch_board_file(struct wil6210_priv *wil, const u8 *new_regdomain) { int rc = 0; char brd_reg_suffix[WIL_BRD_SUFFIX_LEN]; if (!country_specific_board_file) return 0; if (memcmp(wil->regdomain, CTRY_CHINA, 2) == 0) { wil_info(wil, "moving out of China reg domain, use default board file\n"); wil->board_file_country[0] = '\0'; } else if (memcmp(new_regdomain, CTRY_CHINA, 2) == 0) { wil_info(wil, "moving into China reg domain, use country specific board file\n"); strlcpy(wil->board_file_country, CTRY_CHINA, sizeof(wil->board_file_country)); } else { wil_get_brd_reg_suffix(wil, new_regdomain, brd_reg_suffix, sizeof(brd_reg_suffix)); if (!strcmp(wil->board_file_reg_suffix, brd_reg_suffix)) return 0; } wil_info(wil, "switch board file suffix '%s' => '%s'\n", wil->board_file_reg_suffix, brd_reg_suffix); strlcpy(wil->board_file_reg_suffix, brd_reg_suffix, sizeof(wil->board_file_reg_suffix)); /* need to switch board file - reset the device */ Loading Loading @@ -2353,6 +2579,54 @@ static void wil_cfg80211_reg_notify(struct wiphy *wiphy, memcpy(wil->regdomain, request->alpha2, 2); } static int wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_update_ft_ies_params *ftie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = ndev_to_vif(dev); struct cfg80211_bss *bss; struct wmi_ft_reassoc_cmd reassoc; int rc = 0; wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid); wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1, ftie->ie, ftie->ie_len, true); if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { wil_err(wil, "FW does not support FT roaming\n"); return -EOPNOTSUPP; } rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie); if (rc) return rc; if (!test_bit(wil_vif_ft_roam, vif->status)) /* vif is not roaming */ return 0; /* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as * a trigger for reassoc */ bss = vif->bss; if (!bss) { wil_err(wil, "FT: bss is NULL\n"); return -EINVAL; } memset(&reassoc, 0, sizeof(reassoc)); ether_addr_copy(reassoc.bssid, bss->bssid); rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid, &reassoc, sizeof(reassoc)); if (rc) wil_err(wil, "FT: reassoc failed (%d)\n", rc); return rc; } static const struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, Loading Loading @@ -2388,6 +2662,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = { .resume = wil_cfg80211_resume, .sched_scan_start = wil_cfg80211_sched_scan_start, .sched_scan_stop = wil_cfg80211_sched_scan_stop, .update_ft_ies = wil_cfg80211_update_ft_ies, }; static void wil_wiphy_init(struct wiphy *wiphy) Loading drivers/net/wireless/ath/wil6210/debugfs.c +18 −29 Original line number Diff line number Diff line Loading @@ -714,32 +714,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name, return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob); } /*---reset---*/ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct net_device *ndev = wil->main_ndev; /** * BUG: * this code does NOT sync device state with the rest of system * use with care, debug only!!! */ rtnl_lock(); dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); wil_reset(wil, true); return len; } static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, size_t len, loff_t *ppos) Loading Loading @@ -1252,6 +1226,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data) int num_active; int num_free; if (!rbm->buff_arr) return -EINVAL; seq_printf(s, " size = %zu\n", rbm->size); seq_printf(s, " free_list_empty_cnt = %lu\n", rbm->free_list_empty_cnt); Loading Loading @@ -1684,6 +1661,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) char *status = "unknown"; u8 aid = 0; u8 mid; bool sta_connected = false; switch (p->status) { case wil_sta_unused: Loading @@ -1698,8 +1676,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) break; } mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, mid, aid); if (mid < wil->max_vifs) { struct wil6210_vif *vif = wil->vifs[mid]; if (vif->wdev.iftype == NL80211_IFTYPE_STATION && p->status == wil_sta_connected) sta_connected = true; } /* print roam counter only for connected stations */ if (sta_connected) seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n", i, p->addr, p->stats.ft_roams, mid, aid); else seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, mid, aid); if (p->status == wil_sta_connected) { spin_lock_bh(&p->tid_rx_lock); Loading Loading @@ -2440,7 +2430,6 @@ static const struct { {"desc", 0444, &fops_txdesc}, {"bf", 0444, &fops_bf}, {"mem_val", 0644, &fops_memread}, {"reset", 0244, &fops_reset}, {"rxon", 0244, &fops_rxon}, {"tx_mgmt", 0244, &fops_txmgmt}, {"wmi_send", 0244, &fops_wmi}, Loading drivers/net/wireless/ath/wil6210/main.c +14 −5 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ static const struct kernel_param_ops mtu_max_ops = { module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444); MODULE_PARM_DESC(mtu_max, " Max MTU value."); static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; static uint rx_ring_order; static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; Loading Loading @@ -351,6 +351,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, vif->bss = NULL; } clear_bit(wil_vif_fwconnecting, vif->status); clear_bit(wil_vif_ft_roam, vif->status); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: Loading Loading @@ -1146,6 +1148,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wil->max_agg_wsize = WIL_MAX_AGG_WSIZE; wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE; } update_supported_bands(wil); } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) Loading Loading @@ -1178,19 +1182,19 @@ void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len) board_file = WIL_BOARD_FILE_NAME; } if (wil->board_file_country[0] == '\0') { if (wil->board_file_reg_suffix[0] == '\0') { strlcpy(buf, board_file, len); return; } /* use country specific board file */ if (len < strlen(board_file) + 4 /* for _XX and terminating null */) if (len < strlen(board_file) + 1 + WIL_BRD_SUFFIX_LEN) /* 1 for '_' */ return; ext = strrchr(board_file, '.'); prefix_len = (ext ? ext - board_file : strlen(board_file)); snprintf(buf, len, "%.*s_%.2s", prefix_len, board_file, wil->board_file_country); snprintf(buf, len, "%.*s_%.3s", prefix_len, board_file, wil->board_file_reg_suffix); if (ext) strlcat(buf, ext, len); } Loading Loading @@ -1699,6 +1703,11 @@ int __wil_up(struct wil6210_priv *wil) return rc; /* Rx RING. After MAC and beacon */ if (rx_ring_order == 0) rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ? WIL_RX_RING_SIZE_ORDER_DEFAULT : WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT; rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order); if (rc) return rc; Loading drivers/net/wireless/ath/wil6210/txrx.c +83 −0 Original line number Diff line number Diff line Loading @@ -1048,6 +1048,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, return rc; } static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid, int tid) { struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_vring_cfg_cmd cmd = { .action = cpu_to_le32(WMI_VRING_CMD_MODIFY), .vring_cfg = { .tx_sw_ring = { .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), .ring_size = 0, }, .ringid = ring_id, .cidxtid = mk_cidxtid(cid, tid), .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, .agg_max_wsize = 0, .schd_params = { .priority = cpu_to_le16(0), .timeslot_us = cpu_to_le16(0xfff), }, }, }; struct { struct wmi_cmd_hdr wmi; struct wmi_vring_cfg_done_event cmd; } __packed reply = { .cmd = {.status = WMI_FW_STATUS_FAILURE}, }; struct wil_ring *vring = &wil->ring_tx[ring_id]; struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id, cid, tid); lockdep_assert_held(&wil->mutex); if (!vring->va) { wil_err(wil, "Tx ring [%d] not allocated\n", ring_id); return -EINVAL; } if (wil->ring2cid_tid[ring_id][0] != cid || wil->ring2cid_tid[ring_id][1] != tid) { wil_err(wil, "ring info does not match cid=%u tid=%u\n", wil->ring2cid_tid[ring_id][0], wil->ring2cid_tid[ring_id][1]); } 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); if (rc) goto fail; if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) { wil_err(wil, "Tx modify failed, status 0x%02x\n", reply.cmd.status); rc = -EINVAL; goto fail; } /* set BA aggregation window size to 0 to force a new BA with the * new AP */ txdata->agg_wsize = 0; if (txdata->dot1x_open && agg_wsize >= 0) wil_addba_tx_request(wil, ring_id, agg_wsize); return 0; fail: spin_lock_bh(&txdata->lock); txdata->dot1x_open = false; txdata->enabled = 0; spin_unlock_bh(&txdata->lock); wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID; wil->ring2cid_tid[ring_id][1] = 0; return rc; } int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) { struct wil6210_priv *wil = vif_to_wil(vif); Loading Loading @@ -2270,6 +2352,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast; wil->txrx_ops.tx_init = wil_tx_init; wil->txrx_ops.tx_fini = wil_tx_fini; wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init; wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp; Loading drivers/net/wireless/ath/wil6210/txrx_edma.c +13 −2 Original line number Diff line number Diff line Loading @@ -357,8 +357,8 @@ static int wil_init_rx_sring(struct wil6210_priv *wil, struct wil_status_ring *sring = &wil->srings[ring_id]; int rc; wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", sring->size, ring_id); wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", status_ring_size, ring_id); memset(&sring->rx_data, 0, sizeof(sring->rx_data)); Loading Loading @@ -747,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, return rc; } static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id, int cid, int tid) { struct wil6210_priv *wil = vif_to_wil(vif); wil_err(wil, "ring modify is not supported for EDMA\n"); return -EOPNOTSUPP; } /* This function is used only for RX SW reorder */ static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid, struct sk_buff *skb, struct wil_net_stats *stats) Loading Loading @@ -1600,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil) wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma; wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma; wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma; wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init_edma; wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma; Loading Loading
drivers/net/wireless/ath/wil6210/cfg80211.c +338 −63 Original line number Diff line number Diff line Loading @@ -14,7 +14,8 @@ #include "fw.h" #define WIL_MAX_ROC_DURATION_MS 5000 #define CTRY_CHINA "CN" #define WIL_BRD_SUFFIX_CN "CN" #define WIL_BRD_SUFFIX_FCC "FCC" bool disable_ap_sme; module_param(disable_ap_sme, bool, 0444); Loading Loading @@ -50,7 +51,26 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(1, 0), CHAN60G(2, 0), CHAN60G(3, 0), /* channel 4 not supported yet */ CHAN60G(4, 0), }; struct wil_regd_2_brd_suffix { const char regdomain[3]; /* alpha2 */ const char *brd_suffix; }; static struct wil_regd_2_brd_suffix wil_regd_2_brd_suffix_map[] = { {"BO", WIL_BRD_SUFFIX_FCC}, {"CN", WIL_BRD_SUFFIX_CN}, {"EC", WIL_BRD_SUFFIX_FCC}, {"GU", WIL_BRD_SUFFIX_FCC}, {"HN", WIL_BRD_SUFFIX_FCC}, {"JM", WIL_BRD_SUFFIX_FCC}, {"MX", WIL_BRD_SUFFIX_FCC}, {"NI", WIL_BRD_SUFFIX_FCC}, {"PY", WIL_BRD_SUFFIX_FCC}, {"TT", WIL_BRD_SUFFIX_FCC}, {"US", WIL_BRD_SUFFIX_FCC}, }; enum wil_nl_60g_cmd_type { Loading Loading @@ -96,6 +116,26 @@ struct wil_nl_60g_debug_force_wmi { u32 enable; } __packed; static int wil_num_supported_channels(struct wil6210_priv *wil) { int num_channels = ARRAY_SIZE(wil_60ghz_channels); if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities)) num_channels--; return num_channels; } void update_supported_bands(struct wil6210_priv *wil) { struct wiphy *wiphy = wil_to_wiphy(wil); wil_dbg_misc(wil, "update supported bands"); wiphy->bands[NL80211_BAND_60GHZ]->n_channels = wil_num_supported_channels(wil); } /* Vendor id to be used in vendor specific command and events * to user space. * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, Loading Loading @@ -362,7 +402,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = { .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_RESP >> 4) | BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) | BIT(IEEE80211_STYPE_DISASSOC >> 4), BIT(IEEE80211_STYPE_DISASSOC >> 4) | BIT(IEEE80211_STYPE_AUTH >> 4) | BIT(IEEE80211_STYPE_REASSOC_RESP >> 4), .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | Loading Loading @@ -1114,6 +1156,26 @@ static void wil_print_crypto(struct wil6210_priv *wil, c->control_port_no_encrypt); } static const char * wil_get_auth_type_name(enum nl80211_auth_type auth_type) { switch (auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: return "OPEN_SYSTEM"; case NL80211_AUTHTYPE_SHARED_KEY: return "SHARED_KEY"; case NL80211_AUTHTYPE_FT: return "FT"; case NL80211_AUTHTYPE_NETWORK_EAP: return "NETWORK_EAP"; case NL80211_AUTHTYPE_SAE: return "SAE"; case NL80211_AUTHTYPE_AUTOMATIC: return "AUTOMATIC"; default: return "unknown"; } } static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { Loading @@ -1127,11 +1189,82 @@ static void wil_print_connect_params(struct wil6210_priv *wil, if (sme->ssid) print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); if (sme->prev_bssid) wil_info(wil, " Previous BSSID=%pM\n", sme->prev_bssid); wil_info(wil, " Auth Type: %s\n", wil_get_auth_type_name(sme->auth_type)); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); wil_info(wil, " PBSS: %d\n", sme->pbss); wil_print_crypto(wil, &sme->crypto); } static int wil_ft_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = ndev_to_vif(ndev); struct wmi_ft_auth_cmd auth_cmd; int rc; if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { wil_err(wil, "FT: FW does not support FT roaming\n"); return -EOPNOTSUPP; } if (!sme->prev_bssid) { wil_err(wil, "FT: prev_bssid was not set\n"); return -EINVAL; } if (ether_addr_equal(sme->prev_bssid, sme->bssid)) { wil_err(wil, "FT: can not roam to same AP\n"); return -EINVAL; } if (!test_bit(wil_vif_fwconnected, vif->status)) { wil_err(wil, "FT: roam while not connected\n"); return -EINVAL; } if (vif->privacy != sme->privacy) { wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n", vif->privacy, sme->privacy); return -EINVAL; } if (sme->pbss) { wil_err(wil, "FT: roam is not valid for PBSS\n"); return -EINVAL; } memset(&auth_cmd, 0, sizeof(auth_cmd)); auth_cmd.channel = sme->channel->hw_value - 1; ether_addr_copy(auth_cmd.bssid, sme->bssid); if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) if (wil->force_edmg_channel) { rc = wil_spec2wmi_ch(wil->force_edmg_channel, &auth_cmd.channel); if (rc) wil_err(wil, "FT: wmi channel for channel %d not found", wil->force_edmg_channel); } wil_info(wil, "FT: roaming\n"); set_bit(wil_vif_ft_roam, vif->status); rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid, &auth_cmd, sizeof(auth_cmd)); if (rc == 0) mod_timer(&vif->connect_timer, jiffies + msecs_to_jiffies(5000)); else clear_bit(wil_vif_ft_roam, vif->status); return rc; } static int wil_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *sme) Loading @@ -1144,11 +1277,20 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, const u8 *rsn_eid; int ch; int rc = 0; bool is_ft_roam = false; u8 network_type; enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS; wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid); wil_print_connect_params(wil, sme); if (sme->auth_type == NL80211_AUTHTYPE_FT) is_ft_roam = true; if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC && test_bit(wil_vif_fwconnected, vif->status)) is_ft_roam = true; if (!is_ft_roam) if (test_bit(wil_vif_fwconnecting, vif->status) || test_bit(wil_vif_fwconnected, vif->status)) return -EALREADY; Loading @@ -1161,8 +1303,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rsn_eid = sme->ie ? cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) : NULL; if (sme->privacy && !rsn_eid) if (sme->privacy && !rsn_eid) { wil_info(wil, "WSC connection\n"); if (is_ft_roam) { wil_err(wil, "No WSC with FT roam\n"); return -EINVAL; } } if (sme->pbss) bss_type = IEEE80211_BSS_TYPE_PBSS; Loading @@ -1184,6 +1331,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, vif->privacy = sme->privacy; vif->pbss = sme->pbss; rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); if (rc) goto out; switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) { case WLAN_CAPABILITY_DMG_TYPE_AP: network_type = WMI_NETTYPE_INFRA; break; case WLAN_CAPABILITY_DMG_TYPE_PBSS: network_type = WMI_NETTYPE_P2P; break; default: wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", bss->capability); rc = -EINVAL; goto out; } ch = bss->channel->hw_value; if (ch == 0) { wil_err(wil, "BSS at unknown frequency %dMhz\n", bss->channel->center_freq); rc = -EOPNOTSUPP; goto out; } if (is_ft_roam) { if (network_type != WMI_NETTYPE_INFRA) { wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n", bss->capability); rc = -EINVAL; goto out; } rc = wil_ft_connect(wiphy, ndev, sme); if (rc == 0) vif->bss = bss; goto out; } if (vif->privacy) { /* For secure assoc, remove old keys */ rc = wmi_del_cipher_key(vif, 0, bss->bssid, Loading @@ -1200,28 +1386,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, } } /* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info * elements. Send it also in case it's empty, to erase previously set * ies in FW. */ rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); if (rc) goto out; /* WMI_CONNECT_CMD */ memset(&conn, 0, sizeof(conn)); switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) { case WLAN_CAPABILITY_DMG_TYPE_AP: conn.network_type = WMI_NETTYPE_INFRA; break; case WLAN_CAPABILITY_DMG_TYPE_PBSS: conn.network_type = WMI_NETTYPE_P2P; break; default: wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n", bss->capability); goto out; } conn.network_type = network_type; if (vif->privacy) { if (rsn_eid) { /* regular secure connection */ conn.dot11_auth_mode = WMI_AUTH11_SHARED; Loading @@ -1241,14 +1408,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, conn.ssid_len = min_t(u8, ssid_eid[1], 32); memcpy(conn.ssid, ssid_eid+2, conn.ssid_len); ch = bss->channel->hw_value; if (ch == 0) { wil_err(wil, "BSS at unknown frequency %dMhz\n", bss->channel->center_freq); rc = -EOPNOTSUPP; goto out; } conn.channel = ch - 1; if (test_bit(WMI_FW_CAPABILITY_CHANNEL_BONDING, wil->fw_capabilities)) Loading Loading @@ -1454,7 +1613,7 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid, return &wil->sta[cid]; } static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage, struct wil_sta_info *cs, struct key_params *params) { Loading Loading @@ -1539,12 +1698,18 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, params->seq_len, params->seq); if (IS_ERR(cs)) { /* in FT, sta info may not be available as add_key may be * sent by host before FW sends WMI_CONNECT_EVENT */ if (!test_bit(wil_vif_ft_roam, vif->status)) { wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n", mac_addr, key_usage_str[key_usage], key_index, params->seq_len, params->seq); return -EINVAL; } } if (!IS_ERR(cs)) wil_del_rx_key(key_index, key_usage, cs); if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) { Loading @@ -1558,7 +1723,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len, params->key, key_usage); if (!rc) if (!rc && !IS_ERR(cs)) /* in FT set crypto will take place upon receiving * WMI_RING_EN_EVENTID event */ wil_set_crypto_rx(key_index, key_usage, cs, params); return rc; Loading Loading @@ -1721,21 +1889,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) } /* internal functions for device reset and starting AP */ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, struct cfg80211_beacon_data *bcon) static u8 * _wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len, u16 *ies_len) { int rc; u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp = NULL; u8 *ies = NULL; if (bcon->probe_resp) { if (proberesp) { struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; (struct ieee80211_mgmt *)proberesp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); proberesp = f->u.probe_resp.variable; proberesp_len = bcon->probe_resp_len - hlen; ies = f->u.probe_resp.variable; if (ies_len) *ies_len = proberesp_len - hlen; } return ies; } static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, struct cfg80211_beacon_data *bcon) { int rc; u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp; proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, bcon->probe_resp_len, &proberesp_len); rc = _wil_cfg80211_merge_extra_ies(proberesp, proberesp_len, bcon->proberesp_ies, Loading Loading @@ -1779,6 +1962,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, struct wireless_dev *wdev = ndev->ieee80211_ptr; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO); u16 proberesp_len = 0; u8 *proberesp; bool ft = false; if (pbss) wmi_nettype = WMI_NETTYPE_P2P; Loading @@ -1791,6 +1977,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, wil_set_recovery_state(wil, fw_recovery_idle); proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, bcon->probe_resp_len, &proberesp_len); /* check that the probe response IEs has a MDE */ if ((proberesp && proberesp_len > 0 && cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN, proberesp, proberesp_len))) ft = true; if (ft) { if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { wil_err(wil, "FW does not support FT roaming\n"); return -ENOTSUPP; } set_bit(wil_vif_ft_roam, vif->status); } mutex_lock(&wil->mutex); if (!wil_has_other_active_ifaces(wil, ndev, true, false)) { Loading Loading @@ -1952,6 +2157,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); wmi_pcp_stop(vif); clear_bit(wil_vif_ft_roam, vif->status); if (last) __wil_down(wil); Loading @@ -1971,8 +2177,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy, struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "add station %pM aid %d mid %d\n", mac, params->aid, vif->mid); wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n", mac, params->aid, vif->mid, params->sta_flags_mask, params->sta_flags_set); if (!disable_ap_sme) { wil_err(wil, "not supported with AP SME enabled\n"); Loading Loading @@ -2294,24 +2501,43 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, return 0; } static void wil_get_brd_reg_suffix(struct wil6210_priv *wil, const u8 *new_regdomain, char *brd_reg_suffix, size_t len) { int i; struct wil_regd_2_brd_suffix *entry; for (i = 0; i < ARRAY_SIZE(wil_regd_2_brd_suffix_map); i++) { entry = &wil_regd_2_brd_suffix_map[i]; if (!memcmp(entry->regdomain, new_regdomain, 2)) { strlcpy(brd_reg_suffix, entry->brd_suffix, len); return; } } /* regdomain not found in our map, set suffix to none */ brd_reg_suffix[0] = '\0'; } static int wil_switch_board_file(struct wil6210_priv *wil, const u8 *new_regdomain) { int rc = 0; char brd_reg_suffix[WIL_BRD_SUFFIX_LEN]; if (!country_specific_board_file) return 0; if (memcmp(wil->regdomain, CTRY_CHINA, 2) == 0) { wil_info(wil, "moving out of China reg domain, use default board file\n"); wil->board_file_country[0] = '\0'; } else if (memcmp(new_regdomain, CTRY_CHINA, 2) == 0) { wil_info(wil, "moving into China reg domain, use country specific board file\n"); strlcpy(wil->board_file_country, CTRY_CHINA, sizeof(wil->board_file_country)); } else { wil_get_brd_reg_suffix(wil, new_regdomain, brd_reg_suffix, sizeof(brd_reg_suffix)); if (!strcmp(wil->board_file_reg_suffix, brd_reg_suffix)) return 0; } wil_info(wil, "switch board file suffix '%s' => '%s'\n", wil->board_file_reg_suffix, brd_reg_suffix); strlcpy(wil->board_file_reg_suffix, brd_reg_suffix, sizeof(wil->board_file_reg_suffix)); /* need to switch board file - reset the device */ Loading Loading @@ -2353,6 +2579,54 @@ static void wil_cfg80211_reg_notify(struct wiphy *wiphy, memcpy(wil->regdomain, request->alpha2, 2); } static int wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_update_ft_ies_params *ftie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_vif *vif = ndev_to_vif(dev); struct cfg80211_bss *bss; struct wmi_ft_reassoc_cmd reassoc; int rc = 0; wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid); wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1, ftie->ie, ftie->ie_len, true); if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) { wil_err(wil, "FW does not support FT roaming\n"); return -EOPNOTSUPP; } rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie); if (rc) return rc; if (!test_bit(wil_vif_ft_roam, vif->status)) /* vif is not roaming */ return 0; /* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as * a trigger for reassoc */ bss = vif->bss; if (!bss) { wil_err(wil, "FT: bss is NULL\n"); return -EINVAL; } memset(&reassoc, 0, sizeof(reassoc)); ether_addr_copy(reassoc.bssid, bss->bssid); rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid, &reassoc, sizeof(reassoc)); if (rc) wil_err(wil, "FT: reassoc failed (%d)\n", rc); return rc; } static const struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, Loading Loading @@ -2388,6 +2662,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = { .resume = wil_cfg80211_resume, .sched_scan_start = wil_cfg80211_sched_scan_start, .sched_scan_stop = wil_cfg80211_sched_scan_stop, .update_ft_ies = wil_cfg80211_update_ft_ies, }; static void wil_wiphy_init(struct wiphy *wiphy) Loading
drivers/net/wireless/ath/wil6210/debugfs.c +18 −29 Original line number Diff line number Diff line Loading @@ -714,32 +714,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name, return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob); } /*---reset---*/ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct net_device *ndev = wil->main_ndev; /** * BUG: * this code does NOT sync device state with the rest of system * use with care, debug only!!! */ rtnl_lock(); dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); wil_reset(wil, true); return len; } static const struct file_operations fops_reset = { .write = wil_write_file_reset, .open = simple_open, }; /*---write channel 1..4 to rxon for it, 0 to rxoff---*/ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf, size_t len, loff_t *ppos) Loading Loading @@ -1252,6 +1226,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data) int num_active; int num_free; if (!rbm->buff_arr) return -EINVAL; seq_printf(s, " size = %zu\n", rbm->size); seq_printf(s, " free_list_empty_cnt = %lu\n", rbm->free_list_empty_cnt); Loading Loading @@ -1684,6 +1661,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) char *status = "unknown"; u8 aid = 0; u8 mid; bool sta_connected = false; switch (p->status) { case wil_sta_unused: Loading @@ -1698,8 +1676,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) break; } mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, mid, aid); if (mid < wil->max_vifs) { struct wil6210_vif *vif = wil->vifs[mid]; if (vif->wdev.iftype == NL80211_IFTYPE_STATION && p->status == wil_sta_connected) sta_connected = true; } /* print roam counter only for connected stations */ if (sta_connected) seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n", i, p->addr, p->stats.ft_roams, mid, aid); else seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, mid, aid); if (p->status == wil_sta_connected) { spin_lock_bh(&p->tid_rx_lock); Loading Loading @@ -2440,7 +2430,6 @@ static const struct { {"desc", 0444, &fops_txdesc}, {"bf", 0444, &fops_bf}, {"mem_val", 0644, &fops_memread}, {"reset", 0244, &fops_reset}, {"rxon", 0244, &fops_rxon}, {"tx_mgmt", 0244, &fops_txmgmt}, {"wmi_send", 0244, &fops_wmi}, Loading
drivers/net/wireless/ath/wil6210/main.c +14 −5 Original line number Diff line number Diff line Loading @@ -69,7 +69,7 @@ static const struct kernel_param_ops mtu_max_ops = { module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, 0444); MODULE_PARM_DESC(mtu_max, " Max MTU value."); static uint rx_ring_order = WIL_RX_RING_SIZE_ORDER_DEFAULT; static uint rx_ring_order; static uint tx_ring_order = WIL_TX_RING_SIZE_ORDER_DEFAULT; static uint bcast_ring_order = WIL_BCAST_RING_SIZE_ORDER_DEFAULT; Loading Loading @@ -351,6 +351,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, vif->bss = NULL; } clear_bit(wil_vif_fwconnecting, vif->status); clear_bit(wil_vif_ft_roam, vif->status); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: Loading Loading @@ -1146,6 +1148,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil) wil->max_agg_wsize = WIL_MAX_AGG_WSIZE; wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE; } update_supported_bands(wil); } void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) Loading Loading @@ -1178,19 +1182,19 @@ void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len) board_file = WIL_BOARD_FILE_NAME; } if (wil->board_file_country[0] == '\0') { if (wil->board_file_reg_suffix[0] == '\0') { strlcpy(buf, board_file, len); return; } /* use country specific board file */ if (len < strlen(board_file) + 4 /* for _XX and terminating null */) if (len < strlen(board_file) + 1 + WIL_BRD_SUFFIX_LEN) /* 1 for '_' */ return; ext = strrchr(board_file, '.'); prefix_len = (ext ? ext - board_file : strlen(board_file)); snprintf(buf, len, "%.*s_%.2s", prefix_len, board_file, wil->board_file_country); snprintf(buf, len, "%.*s_%.3s", prefix_len, board_file, wil->board_file_reg_suffix); if (ext) strlcat(buf, ext, len); } Loading Loading @@ -1699,6 +1703,11 @@ int __wil_up(struct wil6210_priv *wil) return rc; /* Rx RING. After MAC and beacon */ if (rx_ring_order == 0) rx_ring_order = wil->hw_version < HW_VER_TALYN_MB ? WIL_RX_RING_SIZE_ORDER_DEFAULT : WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT; rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order); if (rc) return rc; Loading
drivers/net/wireless/ath/wil6210/txrx.c +83 −0 Original line number Diff line number Diff line Loading @@ -1048,6 +1048,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, return rc; } static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid, int tid) { struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_vring_cfg_cmd cmd = { .action = cpu_to_le32(WMI_VRING_CMD_MODIFY), .vring_cfg = { .tx_sw_ring = { .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)), .ring_size = 0, }, .ringid = ring_id, .cidxtid = mk_cidxtid(cid, tid), .encap_trans_type = WMI_VRING_ENC_TYPE_802_3, .mac_ctrl = 0, .to_resolution = 0, .agg_max_wsize = 0, .schd_params = { .priority = cpu_to_le16(0), .timeslot_us = cpu_to_le16(0xfff), }, }, }; struct { struct wmi_cmd_hdr wmi; struct wmi_vring_cfg_done_event cmd; } __packed reply = { .cmd = {.status = WMI_FW_STATUS_FAILURE}, }; struct wil_ring *vring = &wil->ring_tx[ring_id]; struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id]; wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id, cid, tid); lockdep_assert_held(&wil->mutex); if (!vring->va) { wil_err(wil, "Tx ring [%d] not allocated\n", ring_id); return -EINVAL; } if (wil->ring2cid_tid[ring_id][0] != cid || wil->ring2cid_tid[ring_id][1] != tid) { wil_err(wil, "ring info does not match cid=%u tid=%u\n", wil->ring2cid_tid[ring_id][0], wil->ring2cid_tid[ring_id][1]); } 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); if (rc) goto fail; if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) { wil_err(wil, "Tx modify failed, status 0x%02x\n", reply.cmd.status); rc = -EINVAL; goto fail; } /* set BA aggregation window size to 0 to force a new BA with the * new AP */ txdata->agg_wsize = 0; if (txdata->dot1x_open && agg_wsize >= 0) wil_addba_tx_request(wil, ring_id, agg_wsize); return 0; fail: spin_lock_bh(&txdata->lock); txdata->dot1x_open = false; txdata->enabled = 0; spin_unlock_bh(&txdata->lock); wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID; wil->ring2cid_tid[ring_id][1] = 0; return rc; } int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) { struct wil6210_priv *wil = vif_to_wil(vif); Loading Loading @@ -2270,6 +2352,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil) wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast; wil->txrx_ops.tx_init = wil_tx_init; wil->txrx_ops.tx_fini = wil_tx_fini; wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init; wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp; Loading
drivers/net/wireless/ath/wil6210/txrx_edma.c +13 −2 Original line number Diff line number Diff line Loading @@ -357,8 +357,8 @@ static int wil_init_rx_sring(struct wil6210_priv *wil, struct wil_status_ring *sring = &wil->srings[ring_id]; int rc; wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", sring->size, ring_id); wil_dbg_misc(wil, "init RX sring: size=%u, ring_id=%u\n", status_ring_size, ring_id); memset(&sring->rx_data, 0, sizeof(sring->rx_data)); Loading Loading @@ -747,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id, return rc; } static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id, int cid, int tid) { struct wil6210_priv *wil = vif_to_wil(vif); wil_err(wil, "ring modify is not supported for EDMA\n"); return -EOPNOTSUPP; } /* This function is used only for RX SW reorder */ static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid, struct sk_buff *skb, struct wil_net_stats *stats) Loading Loading @@ -1600,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil) wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma; wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma; wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma; wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma; /* RX ops */ wil->txrx_ops.rx_init = wil_rx_init_edma; wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma; Loading