Loading drivers/net/wireless/ath/wil6210/cfg80211.c +98 −6 Original line number Diff line number Diff line Loading @@ -65,6 +65,19 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(4, 0), }; static void wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len) { kfree(*pdst); *pdst = NULL; *pdst_len = 0; if (src_len > 0) { *pdst = kmemdup(src, src_len, GFP_KERNEL); if (*pdst) *pdst_len = src_len; } } struct wil_regd_2_brd_suffix { const char regdomain[3]; /* alpha2 */ const char *brd_suffix; Loading Loading @@ -1734,11 +1747,19 @@ 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 && !IS_ERR(cs)) if (!rc && !IS_ERR(cs)) { /* update local storage used for AP recovery */ if (key_usage == WMI_KEY_USE_TX_GROUP && params->key && params->key_len <= WMI_MAX_KEY_LEN) { vif->gtk_index = key_index; memcpy(vif->gtk, params->key, params->key_len); vif->gtk_len = params->key_len; } /* 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 @@ -1935,6 +1956,14 @@ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp; /* update local storage used for AP recovery */ wil_memdup_ie(&vif->proberesp, &vif->proberesp_len, bcon->probe_resp, bcon->probe_resp_len); wil_memdup_ie(&vif->proberesp_ies, &vif->proberesp_ies_len, bcon->proberesp_ies, bcon->proberesp_ies_len); wil_memdup_ie(&vif->assocresp_ies, &vif->assocresp_ies_len, bcon->assocresp_ies, bcon->assocresp_ies_len); proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, bcon->probe_resp_len, &proberesp_len); Loading Loading @@ -2036,6 +2065,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, vif->channel = chan; vif->hidden_ssid = hidden_ssid; vif->pbss = pbss; vif->bi = bi; memcpy(vif->ssid, ssid, ssid_len); vif->ssid_len = ssid_len; netif_carrier_on(ndev); if (!wil_has_other_active_ifaces(wil, ndev, false, true)) Loading @@ -2062,11 +2094,64 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, return rc; } 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++) { struct wil6210_vif *vif = wil->vifs[i]; struct net_device *ndev; struct cfg80211_beacon_data bcon = {}; struct key_params key_params = {}; if (!vif || vif->ssid_len == 0) continue; ndev = vif_to_ndev(vif); bcon.proberesp_ies = vif->proberesp_ies; bcon.assocresp_ies = vif->assocresp_ies; bcon.probe_resp = vif->proberesp; bcon.proberesp_ies_len = vif->proberesp_ies_len; bcon.assocresp_ies_len = vif->assocresp_ies_len; bcon.probe_resp_len = vif->proberesp_len; wil_info(wil, "AP (vif %d) recovery: privacy %d, bi %d, channel %d, hidden %d, pbss %d\n", i, vif->privacy, vif->bi, vif->channel, vif->hidden_ssid, vif->pbss); wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1, vif->ssid, vif->ssid_len, true); rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, vif->privacy, vif->bi, vif->channel, &bcon, vif->hidden_ssid, vif->pbss); if (rc) { wil_err(wil, "vif %d recovery failed (%d)\n", i, rc); continue; } if (!vif->privacy || vif->gtk_len == 0) continue; key_params.key = vif->gtk; key_params.key_len = vif->gtk_len; key_params.seq_len = IEEE80211_GCMP_PN_LEN; rc = wil_cfg80211_add_key(wiphy, ndev, vif->gtk_index, false, NULL, &key_params); if (rc) wil_err(wil, "vif %d recovery add key failed (%d)\n", i, rc); } } static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wireless_dev *wdev = ndev->ieee80211_ptr; struct wil6210_vif *vif = ndev_to_vif(ndev); int rc; u32 privacy = 0; Loading @@ -2079,15 +2164,16 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, bcon->tail_len)) privacy = 1; memcpy(vif->ssid, wdev->ssid, wdev->ssid_len); vif->ssid_len = wdev->ssid_len; /* in case privacy has changed, need to restart the AP */ if (vif->privacy != privacy) { struct wireless_dev *wdev = ndev->ieee80211_ptr; wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", vif->privacy, privacy); rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, wdev->ssid_len, privacy, rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, privacy, wdev->beacon_interval, vif->channel, bcon, vif->hidden_ssid, Loading Loading @@ -2177,6 +2263,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wmi_pcp_stop(vif); clear_bit(wil_vif_ft_roam, vif->status); vif->ssid_len = 0; wil_memdup_ie(&vif->proberesp, &vif->proberesp_len, NULL, 0); wil_memdup_ie(&vif->proberesp_ies, &vif->proberesp_ies_len, NULL, 0); wil_memdup_ie(&vif->assocresp_ies, &vif->assocresp_ies_len, NULL, 0); memset(vif->gtk, 0, WMI_MAX_KEY_LEN); vif->gtk_len = 0; if (last) __wil_down(wil); Loading Loading @@ -2224,7 +2316,7 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, params->mac, params->reason_code, vif->mid); mutex_lock(&wil->mutex); wil6210_disconnect(vif, params->mac, params->reason_code, false); wil6210_disconnect(vif, params->mac, params->reason_code); mutex_unlock(&wil->mutex); return 0; Loading drivers/net/wireless/ath/wil6210/main.c +148 −50 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/moduleparam.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/rtnetlink.h> #include "wil6210.h" #include "txrx.h" Loading Loading @@ -214,8 +215,21 @@ static void wil_ring_fini_tx(struct wil6210_priv *wil, int id) wil->txrx_ops.ring_fini_tx(wil, ring); } static void wil_disconnect_cid(struct wil6210_vif *vif, int cid, u16 reason_code, bool from_event) static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) { int i; for (i = 0; i < WIL6210_MAX_CID; i++) { if (wil->sta[i].mid == mid && wil->sta[i].status == wil_sta_connected) return true; } return false; } static void wil_disconnect_cid_complete(struct wil6210_vif *vif, int cid, u16 reason_code) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { uint i; Loading @@ -226,24 +240,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) int min_ring_id = wil_get_min_tx_ring_id(wil); might_sleep(); wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", wil_dbg_misc(wil, "disconnect_cid_complete: CID %d, MID %d, status %d\n", cid, sta->mid, sta->status); /* inform upper/lower layers */ /* inform upper layers */ if (sta->status != wil_sta_unused) { if (vif->mid != sta->mid) { wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", vif->mid); /* let FW override sta->mid but be more strict with * user space requests */ if (!from_event) return; } if (!from_event) { bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ? disable_ap_sme : false; wmi_disconnect_sta(vif, sta->addr, reason_code, true, del_sta); } switch (wdev->iftype) { Loading Loading @@ -284,36 +288,20 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) sta->stats.tx_latency_min_us = U32_MAX; } static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) { int i; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { if (wil->sta[i].mid == mid && wil->sta[i].status == wil_sta_connected) return true; } return false; } static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event) static void _wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); int cid = -ENOENT; struct net_device *ndev; struct wireless_dev *wdev; if (unlikely(!vif)) return; ndev = vif_to_ndev(vif); wdev = vif_to_wdev(vif); might_sleep(); wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid, reason_code, from_event ? "+" : "-"); wil_info(wil, "disconnect_complete: bssid=%pM, reason=%d\n", bssid, reason_code); /* Cases are: * - disconnect single STA, still connected Loading @@ -328,14 +316,15 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, if (bssid && !is_broadcast_ether_addr(bssid) && !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) { cid = wil_find_cid(wil, vif->mid, bssid); wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", wil_dbg_misc(wil, "Disconnect complete %pM, CID=%d, reason=%d\n", bssid, cid, reason_code); if (cid >= 0) /* disconnect 1 peer */ wil_disconnect_cid(vif, cid, reason_code, from_event); wil_disconnect_cid_complete(vif, cid, reason_code); } else { /* all */ wil_dbg_misc(wil, "Disconnect all\n"); wil_dbg_misc(wil, "Disconnect complete all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) wil_disconnect_cid(vif, cid, reason_code, from_event); wil_disconnect_cid_complete(vif, cid, reason_code); } /* link state */ Loading Loading @@ -381,6 +370,84 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, } } static int wil_disconnect_cid(struct wil6210_vif *vif, int cid, u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); struct wireless_dev *wdev = vif_to_wdev(vif); struct wil_sta_info *sta = &wil->sta[cid]; bool del_sta = false; might_sleep(); wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", cid, sta->mid, sta->status); if (sta->status == wil_sta_unused) return 0; if (vif->mid != sta->mid) { wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", vif->mid); return -EINVAL; } /* inform lower layers */ if (wdev->iftype == NL80211_IFTYPE_AP && disable_ap_sme) del_sta = true; /* disconnect by sending command disconnect/del_sta and wait * synchronously for WMI_DISCONNECT_EVENTID event. */ return wmi_disconnect_sta(vif, sta->addr, reason_code, del_sta); } static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code) { struct wil6210_priv *wil; struct net_device *ndev; struct wireless_dev *wdev; int cid = -ENOENT; if (unlikely(!vif)) return; wil = vif_to_wil(vif); ndev = vif_to_ndev(vif); wdev = vif_to_wdev(vif); might_sleep(); wil_info(wil, "disconnect bssid=%pM, reason=%d\n", bssid, reason_code); /* Cases are: * - disconnect single STA, still connected * - disconnect single STA, already disconnected * - disconnect all * * For "disconnect all", there are 3 options: * - bssid == NULL * - bssid is broadcast address (ff:ff:ff:ff:ff:ff) * - bssid is our MAC address */ if (bssid && !is_broadcast_ether_addr(bssid) && !ether_addr_equal_unaligned(ndev->dev_addr, 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 */ wil_disconnect_cid(vif, cid, reason_code); } else { /* all */ wil_dbg_misc(wil, "Disconnect all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) wil_disconnect_cid(vif, cid, reason_code); } /* call event handler manually after processing wmi_call, * to avoid deadlock - disconnect event handler acquires * wil->mutex while it is already held here */ _wil6210_disconnect_complete(vif, bssid, reason_code); } void wil_disconnect_worker(struct work_struct *work) { struct wil6210_vif *vif = container_of(work, Loading Loading @@ -487,10 +554,11 @@ static void wil_fw_error_worker(struct work_struct *work) if (wil_wait_for_recovery(wil) != 0) return; rtnl_lock(); mutex_lock(&wil->mutex); /* Needs adaptation for multiple VIFs * need to go over all VIFs and consider the appropriate * recovery. * recovery because each one can have different iftype. */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: Loading @@ -502,15 +570,24 @@ static void wil_fw_error_worker(struct work_struct *work) break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: wil_info(wil, "No recovery for AP-like interface\n"); /* recovery in these modes is done by upper layers */ if (no_fw_recovery) /* upper layers do recovery */ break; /* silent recovery, upper layers will see disconnect */ __wil_down(wil); __wil_up(wil); mutex_unlock(&wil->mutex); wil_cfg80211_ap_recovery(wil); mutex_lock(&wil->mutex); wil_info(wil, "... completed\n"); break; default: wil_err(wil, "No recovery - unknown interface type %d\n", wdev->iftype); break; } mutex_unlock(&wil->mutex); rtnl_unlock(); } static int wil_find_free_ring(struct wil6210_priv *wil) Loading Loading @@ -696,20 +773,41 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) * @vif: virtual interface context * @bssid: peer to disconnect, NULL to disconnect all * @reason_code: Reason code for the Disassociation frame * @from_event: whether is invoked from FW event handler * * Disconnect and release associated resources. If invoked not from the * FW event handler, issue WMI command(s) to trigger MAC disconnect. * Disconnect and release associated resources. Issue WMI * command(s) to trigger MAC disconnect. When command was issued * successfully, call the wil6210_disconnect_complete function * to handle the event synchronously */ void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event) u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); wil_dbg_misc(wil, "disconnecting\n"); del_timer_sync(&vif->connect_timer); _wil6210_disconnect(vif, bssid, reason_code); } /** * wil6210_disconnect_complete - handle disconnect event * @vif: virtual interface context * @bssid: peer to disconnect, NULL to disconnect all * @reason_code: Reason code for the Disassociation frame * * Release associated resources and indicate upper layers the * connection is terminated. */ void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); wil_dbg_misc(wil, "disconnect\n"); wil_dbg_misc(wil, "got disconnect\n"); del_timer_sync(&vif->connect_timer); _wil6210_disconnect(vif, bssid, reason_code, from_event); _wil6210_disconnect_complete(vif, bssid, reason_code); } void wil_priv_deinit(struct wil6210_priv *wil) Loading Loading @@ -1549,7 +1647,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (vif) { cancel_work_sync(&vif->disconnect_worker); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); WLAN_REASON_DEAUTH_LEAVING); } } wil_bcast_fini_all(wil); Loading Loading @@ -1733,7 +1831,7 @@ int __wil_up(struct wil6210_priv *wil) WIL_RX_RING_SIZE_ORDER_DEFAULT : WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT; rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order); rc = wil->txrx_ops.rx_init(wil, rx_ring_order); if (rc) return rc; Loading drivers/net/wireless/ath/wil6210/netdev.c +2 −3 Original line number Diff line number Diff line Loading @@ -361,8 +361,7 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name, ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXHASH; NETIF_F_TSO | NETIF_F_TSO6; ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); Loading Loading @@ -530,7 +529,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) } mutex_lock(&wil->mutex); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING); mutex_unlock(&wil->mutex); ndev = vif_to_ndev(vif); Loading drivers/net/wireless/ath/wil6210/txrx.c +4 −10 Original line number Diff line number Diff line Loading @@ -769,14 +769,6 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) stats = &wil->sta[cid].stats; if (ndev->features & NETIF_F_RXHASH) /* fake L4 to ensure it won't be re-calculated later * set hash to any non-zero value to activate rps * mechanism, core will be chosen according * to user-level rps configuration. */ skb_set_hash(skb, 1, PKT_HASH_TYPE_L4); skb_orphan(skb); if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) { Loading Loading @@ -906,7 +898,7 @@ static void wil_rx_buf_len_init(struct wil6210_priv *wil) } } static int wil_rx_init(struct wil6210_priv *wil, u16 size) static int wil_rx_init(struct wil6210_priv *wil, uint order) { struct wil_ring *vring = &wil->ring_rx; int rc; Loading @@ -920,7 +912,7 @@ static int wil_rx_init(struct wil6210_priv *wil, u16 size) wil_rx_buf_len_init(wil); vring->size = size; vring->size = 1 << order; vring->is_rx = true; rc = wil_vring_alloc(wil, vring); if (rc) Loading Loading @@ -1429,6 +1421,8 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil, wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); wil_set_da_for_vring(wil, skb2, i); wil_tx_ring(wil, vif, v2, skb2); /* successful call to wil_tx_ring takes skb2 ref */ dev_kfree_skb_any(skb2); } else { wil_err(wil, "skb_copy failed\n"); } Loading drivers/net/wireless/ath/wil6210/txrx_edma.c +8 −3 Original line number Diff line number Diff line Loading @@ -607,9 +607,9 @@ static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil) WIL_MAX_ETH_MTU : WIL_EDMA_RX_BUF_LEN_DEFAULT; } static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order) { u16 status_ring_size; u16 status_ring_size, desc_ring_size = 1 << desc_ring_order; struct wil_ring *ring = &wil->ring_rx; int rc; size_t elem_size = wil->use_compressed_rx_status ? Loading @@ -624,7 +624,12 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) "compressed RX status cannot be used with SW reorder\n"); return -EINVAL; } if (wil->rx_status_ring_order <= desc_ring_order) /* make sure sring is larger than desc ring */ wil->rx_status_ring_order = desc_ring_order + 1; if (wil->rx_buff_id_count <= desc_ring_size) /* make sure we will not run out of buff_ids */ wil->rx_buff_id_count = desc_ring_size + 512; if (wil->rx_status_ring_order < WIL_SRING_SIZE_ORDER_MIN || wil->rx_status_ring_order > WIL_SRING_SIZE_ORDER_MAX) wil->rx_status_ring_order = WIL_RX_SRING_SIZE_ORDER_DEFAULT; Loading Loading
drivers/net/wireless/ath/wil6210/cfg80211.c +98 −6 Original line number Diff line number Diff line Loading @@ -65,6 +65,19 @@ static struct ieee80211_channel wil_60ghz_channels[] = { CHAN60G(4, 0), }; static void wil_memdup_ie(u8 **pdst, size_t *pdst_len, const u8 *src, size_t src_len) { kfree(*pdst); *pdst = NULL; *pdst_len = 0; if (src_len > 0) { *pdst = kmemdup(src, src_len, GFP_KERNEL); if (*pdst) *pdst_len = src_len; } } struct wil_regd_2_brd_suffix { const char regdomain[3]; /* alpha2 */ const char *brd_suffix; Loading Loading @@ -1734,11 +1747,19 @@ 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 && !IS_ERR(cs)) if (!rc && !IS_ERR(cs)) { /* update local storage used for AP recovery */ if (key_usage == WMI_KEY_USE_TX_GROUP && params->key && params->key_len <= WMI_MAX_KEY_LEN) { vif->gtk_index = key_index; memcpy(vif->gtk, params->key, params->key_len); vif->gtk_len = params->key_len; } /* 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 @@ -1935,6 +1956,14 @@ static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp; /* update local storage used for AP recovery */ wil_memdup_ie(&vif->proberesp, &vif->proberesp_len, bcon->probe_resp, bcon->probe_resp_len); wil_memdup_ie(&vif->proberesp_ies, &vif->proberesp_ies_len, bcon->proberesp_ies, bcon->proberesp_ies_len); wil_memdup_ie(&vif->assocresp_ies, &vif->assocresp_ies_len, bcon->assocresp_ies, bcon->assocresp_ies_len); proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp, bcon->probe_resp_len, &proberesp_len); Loading Loading @@ -2036,6 +2065,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, vif->channel = chan; vif->hidden_ssid = hidden_ssid; vif->pbss = pbss; vif->bi = bi; memcpy(vif->ssid, ssid, ssid_len); vif->ssid_len = ssid_len; netif_carrier_on(ndev); if (!wil_has_other_active_ifaces(wil, ndev, false, true)) Loading @@ -2062,11 +2094,64 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, return rc; } 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++) { struct wil6210_vif *vif = wil->vifs[i]; struct net_device *ndev; struct cfg80211_beacon_data bcon = {}; struct key_params key_params = {}; if (!vif || vif->ssid_len == 0) continue; ndev = vif_to_ndev(vif); bcon.proberesp_ies = vif->proberesp_ies; bcon.assocresp_ies = vif->assocresp_ies; bcon.probe_resp = vif->proberesp; bcon.proberesp_ies_len = vif->proberesp_ies_len; bcon.assocresp_ies_len = vif->assocresp_ies_len; bcon.probe_resp_len = vif->proberesp_len; wil_info(wil, "AP (vif %d) recovery: privacy %d, bi %d, channel %d, hidden %d, pbss %d\n", i, vif->privacy, vif->bi, vif->channel, vif->hidden_ssid, vif->pbss); wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1, vif->ssid, vif->ssid_len, true); rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, vif->privacy, vif->bi, vif->channel, &bcon, vif->hidden_ssid, vif->pbss); if (rc) { wil_err(wil, "vif %d recovery failed (%d)\n", i, rc); continue; } if (!vif->privacy || vif->gtk_len == 0) continue; key_params.key = vif->gtk; key_params.key_len = vif->gtk_len; key_params.seq_len = IEEE80211_GCMP_PN_LEN; rc = wil_cfg80211_add_key(wiphy, ndev, vif->gtk_index, false, NULL, &key_params); if (rc) wil_err(wil, "vif %d recovery add key failed (%d)\n", i, rc); } } static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wireless_dev *wdev = ndev->ieee80211_ptr; struct wil6210_vif *vif = ndev_to_vif(ndev); int rc; u32 privacy = 0; Loading @@ -2079,15 +2164,16 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, bcon->tail_len)) privacy = 1; memcpy(vif->ssid, wdev->ssid, wdev->ssid_len); vif->ssid_len = wdev->ssid_len; /* in case privacy has changed, need to restart the AP */ if (vif->privacy != privacy) { struct wireless_dev *wdev = ndev->ieee80211_ptr; wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", vif->privacy, privacy); rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, wdev->ssid_len, privacy, rc = _wil_cfg80211_start_ap(wiphy, ndev, vif->ssid, vif->ssid_len, privacy, wdev->beacon_interval, vif->channel, bcon, vif->hidden_ssid, Loading Loading @@ -2177,6 +2263,12 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, wmi_pcp_stop(vif); clear_bit(wil_vif_ft_roam, vif->status); vif->ssid_len = 0; wil_memdup_ie(&vif->proberesp, &vif->proberesp_len, NULL, 0); wil_memdup_ie(&vif->proberesp_ies, &vif->proberesp_ies_len, NULL, 0); wil_memdup_ie(&vif->assocresp_ies, &vif->assocresp_ies_len, NULL, 0); memset(vif->gtk, 0, WMI_MAX_KEY_LEN); vif->gtk_len = 0; if (last) __wil_down(wil); Loading Loading @@ -2224,7 +2316,7 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy, params->mac, params->reason_code, vif->mid); mutex_lock(&wil->mutex); wil6210_disconnect(vif, params->mac, params->reason_code, false); wil6210_disconnect(vif, params->mac, params->reason_code); mutex_unlock(&wil->mutex); return 0; Loading
drivers/net/wireless/ath/wil6210/main.c +148 −50 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/moduleparam.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/rtnetlink.h> #include "wil6210.h" #include "txrx.h" Loading Loading @@ -214,8 +215,21 @@ static void wil_ring_fini_tx(struct wil6210_priv *wil, int id) wil->txrx_ops.ring_fini_tx(wil, ring); } static void wil_disconnect_cid(struct wil6210_vif *vif, int cid, u16 reason_code, bool from_event) static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) { int i; for (i = 0; i < WIL6210_MAX_CID; i++) { if (wil->sta[i].mid == mid && wil->sta[i].status == wil_sta_connected) return true; } return false; } static void wil_disconnect_cid_complete(struct wil6210_vif *vif, int cid, u16 reason_code) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { uint i; Loading @@ -226,24 +240,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) int min_ring_id = wil_get_min_tx_ring_id(wil); might_sleep(); wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", wil_dbg_misc(wil, "disconnect_cid_complete: CID %d, MID %d, status %d\n", cid, sta->mid, sta->status); /* inform upper/lower layers */ /* inform upper layers */ if (sta->status != wil_sta_unused) { if (vif->mid != sta->mid) { wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", vif->mid); /* let FW override sta->mid but be more strict with * user space requests */ if (!from_event) return; } if (!from_event) { bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ? disable_ap_sme : false; wmi_disconnect_sta(vif, sta->addr, reason_code, true, del_sta); } switch (wdev->iftype) { Loading Loading @@ -284,36 +288,20 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) sta->stats.tx_latency_min_us = U32_MAX; } static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) { int i; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { if (wil->sta[i].mid == mid && wil->sta[i].status == wil_sta_connected) return true; } return false; } static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event) static void _wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); int cid = -ENOENT; struct net_device *ndev; struct wireless_dev *wdev; if (unlikely(!vif)) return; ndev = vif_to_ndev(vif); wdev = vif_to_wdev(vif); might_sleep(); wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid, reason_code, from_event ? "+" : "-"); wil_info(wil, "disconnect_complete: bssid=%pM, reason=%d\n", bssid, reason_code); /* Cases are: * - disconnect single STA, still connected Loading @@ -328,14 +316,15 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, if (bssid && !is_broadcast_ether_addr(bssid) && !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) { cid = wil_find_cid(wil, vif->mid, bssid); wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", wil_dbg_misc(wil, "Disconnect complete %pM, CID=%d, reason=%d\n", bssid, cid, reason_code); if (cid >= 0) /* disconnect 1 peer */ wil_disconnect_cid(vif, cid, reason_code, from_event); wil_disconnect_cid_complete(vif, cid, reason_code); } else { /* all */ wil_dbg_misc(wil, "Disconnect all\n"); wil_dbg_misc(wil, "Disconnect complete all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) wil_disconnect_cid(vif, cid, reason_code, from_event); wil_disconnect_cid_complete(vif, cid, reason_code); } /* link state */ Loading Loading @@ -381,6 +370,84 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, } } static int wil_disconnect_cid(struct wil6210_vif *vif, int cid, u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); struct wireless_dev *wdev = vif_to_wdev(vif); struct wil_sta_info *sta = &wil->sta[cid]; bool del_sta = false; might_sleep(); wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", cid, sta->mid, sta->status); if (sta->status == wil_sta_unused) return 0; if (vif->mid != sta->mid) { wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", vif->mid); return -EINVAL; } /* inform lower layers */ if (wdev->iftype == NL80211_IFTYPE_AP && disable_ap_sme) del_sta = true; /* disconnect by sending command disconnect/del_sta and wait * synchronously for WMI_DISCONNECT_EVENTID event. */ return wmi_disconnect_sta(vif, sta->addr, reason_code, del_sta); } static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code) { struct wil6210_priv *wil; struct net_device *ndev; struct wireless_dev *wdev; int cid = -ENOENT; if (unlikely(!vif)) return; wil = vif_to_wil(vif); ndev = vif_to_ndev(vif); wdev = vif_to_wdev(vif); might_sleep(); wil_info(wil, "disconnect bssid=%pM, reason=%d\n", bssid, reason_code); /* Cases are: * - disconnect single STA, still connected * - disconnect single STA, already disconnected * - disconnect all * * For "disconnect all", there are 3 options: * - bssid == NULL * - bssid is broadcast address (ff:ff:ff:ff:ff:ff) * - bssid is our MAC address */ if (bssid && !is_broadcast_ether_addr(bssid) && !ether_addr_equal_unaligned(ndev->dev_addr, 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 */ wil_disconnect_cid(vif, cid, reason_code); } else { /* all */ wil_dbg_misc(wil, "Disconnect all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) wil_disconnect_cid(vif, cid, reason_code); } /* call event handler manually after processing wmi_call, * to avoid deadlock - disconnect event handler acquires * wil->mutex while it is already held here */ _wil6210_disconnect_complete(vif, bssid, reason_code); } void wil_disconnect_worker(struct work_struct *work) { struct wil6210_vif *vif = container_of(work, Loading Loading @@ -487,10 +554,11 @@ static void wil_fw_error_worker(struct work_struct *work) if (wil_wait_for_recovery(wil) != 0) return; rtnl_lock(); mutex_lock(&wil->mutex); /* Needs adaptation for multiple VIFs * need to go over all VIFs and consider the appropriate * recovery. * recovery because each one can have different iftype. */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: Loading @@ -502,15 +570,24 @@ static void wil_fw_error_worker(struct work_struct *work) break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: wil_info(wil, "No recovery for AP-like interface\n"); /* recovery in these modes is done by upper layers */ if (no_fw_recovery) /* upper layers do recovery */ break; /* silent recovery, upper layers will see disconnect */ __wil_down(wil); __wil_up(wil); mutex_unlock(&wil->mutex); wil_cfg80211_ap_recovery(wil); mutex_lock(&wil->mutex); wil_info(wil, "... completed\n"); break; default: wil_err(wil, "No recovery - unknown interface type %d\n", wdev->iftype); break; } mutex_unlock(&wil->mutex); rtnl_unlock(); } static int wil_find_free_ring(struct wil6210_priv *wil) Loading Loading @@ -696,20 +773,41 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) * @vif: virtual interface context * @bssid: peer to disconnect, NULL to disconnect all * @reason_code: Reason code for the Disassociation frame * @from_event: whether is invoked from FW event handler * * Disconnect and release associated resources. If invoked not from the * FW event handler, issue WMI command(s) to trigger MAC disconnect. * Disconnect and release associated resources. Issue WMI * command(s) to trigger MAC disconnect. When command was issued * successfully, call the wil6210_disconnect_complete function * to handle the event synchronously */ void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event) u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); wil_dbg_misc(wil, "disconnecting\n"); del_timer_sync(&vif->connect_timer); _wil6210_disconnect(vif, bssid, reason_code); } /** * wil6210_disconnect_complete - handle disconnect event * @vif: virtual interface context * @bssid: peer to disconnect, NULL to disconnect all * @reason_code: Reason code for the Disassociation frame * * Release associated resources and indicate upper layers the * connection is terminated. */ void wil6210_disconnect_complete(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code) { struct wil6210_priv *wil = vif_to_wil(vif); wil_dbg_misc(wil, "disconnect\n"); wil_dbg_misc(wil, "got disconnect\n"); del_timer_sync(&vif->connect_timer); _wil6210_disconnect(vif, bssid, reason_code, from_event); _wil6210_disconnect_complete(vif, bssid, reason_code); } void wil_priv_deinit(struct wil6210_priv *wil) Loading Loading @@ -1549,7 +1647,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (vif) { cancel_work_sync(&vif->disconnect_worker); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); WLAN_REASON_DEAUTH_LEAVING); } } wil_bcast_fini_all(wil); Loading Loading @@ -1733,7 +1831,7 @@ int __wil_up(struct wil6210_priv *wil) WIL_RX_RING_SIZE_ORDER_DEFAULT : WIL_RX_RING_SIZE_ORDER_TALYN_DEFAULT; rc = wil->txrx_ops.rx_init(wil, 1 << rx_ring_order); rc = wil->txrx_ops.rx_init(wil, rx_ring_order); if (rc) return rc; Loading
drivers/net/wireless/ath/wil6210/netdev.c +2 −3 Original line number Diff line number Diff line Loading @@ -361,8 +361,7 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name, ndev->ieee80211_ptr = wdev; ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXHASH; NETIF_F_TSO | NETIF_F_TSO6; ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); Loading Loading @@ -530,7 +529,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) } mutex_lock(&wil->mutex); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING); mutex_unlock(&wil->mutex); ndev = vif_to_ndev(vif); Loading
drivers/net/wireless/ath/wil6210/txrx.c +4 −10 Original line number Diff line number Diff line Loading @@ -769,14 +769,6 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) stats = &wil->sta[cid].stats; if (ndev->features & NETIF_F_RXHASH) /* fake L4 to ensure it won't be re-calculated later * set hash to any non-zero value to activate rps * mechanism, core will be chosen according * to user-level rps configuration. */ skb_set_hash(skb, 1, PKT_HASH_TYPE_L4); skb_orphan(skb); if (security && (wil->txrx_ops.rx_crypto_check(wil, skb) != 0)) { Loading Loading @@ -906,7 +898,7 @@ static void wil_rx_buf_len_init(struct wil6210_priv *wil) } } static int wil_rx_init(struct wil6210_priv *wil, u16 size) static int wil_rx_init(struct wil6210_priv *wil, uint order) { struct wil_ring *vring = &wil->ring_rx; int rc; Loading @@ -920,7 +912,7 @@ static int wil_rx_init(struct wil6210_priv *wil, u16 size) wil_rx_buf_len_init(wil); vring->size = size; vring->size = 1 << order; vring->is_rx = true; rc = wil_vring_alloc(wil, vring); if (rc) Loading Loading @@ -1429,6 +1421,8 @@ static struct wil_ring *wil_find_tx_bcast_2(struct wil6210_priv *wil, wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); wil_set_da_for_vring(wil, skb2, i); wil_tx_ring(wil, vif, v2, skb2); /* successful call to wil_tx_ring takes skb2 ref */ dev_kfree_skb_any(skb2); } else { wil_err(wil, "skb_copy failed\n"); } Loading
drivers/net/wireless/ath/wil6210/txrx_edma.c +8 −3 Original line number Diff line number Diff line Loading @@ -607,9 +607,9 @@ static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil) WIL_MAX_ETH_MTU : WIL_EDMA_RX_BUF_LEN_DEFAULT; } static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) static int wil_rx_init_edma(struct wil6210_priv *wil, uint desc_ring_order) { u16 status_ring_size; u16 status_ring_size, desc_ring_size = 1 << desc_ring_order; struct wil_ring *ring = &wil->ring_rx; int rc; size_t elem_size = wil->use_compressed_rx_status ? Loading @@ -624,7 +624,12 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size) "compressed RX status cannot be used with SW reorder\n"); return -EINVAL; } if (wil->rx_status_ring_order <= desc_ring_order) /* make sure sring is larger than desc ring */ wil->rx_status_ring_order = desc_ring_order + 1; if (wil->rx_buff_id_count <= desc_ring_size) /* make sure we will not run out of buff_ids */ wil->rx_buff_id_count = desc_ring_size + 512; if (wil->rx_status_ring_order < WIL_SRING_SIZE_ORDER_MIN || wil->rx_status_ring_order > WIL_SRING_SIZE_ORDER_MAX) wil->rx_status_ring_order = WIL_RX_SRING_SIZE_ORDER_DEFAULT; Loading