Commit 5bd60982 authored by Lior David's avatar Lior David Committed by Kalle Valo

wil6210: multiple VIFs support for connections and data path

Track the connection status per-VIF.
The data path code is also updated to support multiple VIFs.
This includes RX and TX VRING management, NAPI poll loops,
RX reordering and related code.
Power management code used to check if the main interface
is up or based on connection state of the main interface,
adapt this code to take all VIFs into account.
Signed-off-by: default avatarLior David <liord@codeaurora.org>
Signed-off-by: default avatarMaya Erez <merez@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 404bbb3c
...@@ -319,7 +319,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, ...@@ -319,7 +319,7 @@ int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
sinfo->tx_packets = stats->tx_packets; sinfo->tx_packets = stats->tx_packets;
sinfo->tx_failed = stats->tx_errors; sinfo->tx_failed = stats->tx_errors;
if (test_bit(wil_status_fwconnected, wil->status)) { if (test_bit(wil_vif_fwconnected, vif->status)) {
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING,
wil->fw_capabilities)) wil->fw_capabilities))
...@@ -490,11 +490,10 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, ...@@ -490,11 +490,10 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
vif = kzalloc(sizeof(*vif), GFP_KERNEL); p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL);
if (!vif) if (!p2p_wdev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
p2p_wdev = vif_to_wdev(vif);
p2p_wdev->iftype = type; p2p_wdev->iftype = type;
p2p_wdev->wiphy = wiphy; p2p_wdev->wiphy = wiphy;
/* use our primary ethernet address */ /* use our primary ethernet address */
...@@ -904,8 +903,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, ...@@ -904,8 +903,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid); wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
wil_print_connect_params(wil, sme); wil_print_connect_params(wil, sme);
if (test_bit(wil_status_fwconnecting, wil->status) || if (test_bit(wil_vif_fwconnecting, vif->status) ||
test_bit(wil_status_fwconnected, wil->status)) test_bit(wil_vif_fwconnected, vif->status))
return -EALREADY; return -EALREADY;
if (sme->ie_len > WMI_MAX_IE_LEN) { if (sme->ie_len > WMI_MAX_IE_LEN) {
...@@ -1009,18 +1008,19 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, ...@@ -1009,18 +1008,19 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
ether_addr_copy(conn.bssid, bss->bssid); ether_addr_copy(conn.bssid, bss->bssid);
ether_addr_copy(conn.dst_mac, bss->bssid); ether_addr_copy(conn.dst_mac, bss->bssid);
set_bit(wil_status_fwconnecting, wil->status); set_bit(wil_vif_fwconnecting, vif->status);
rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn)); rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn));
if (rc == 0) { if (rc == 0) {
netif_carrier_on(ndev); netif_carrier_on(ndev);
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
vif->bss = bss; vif->bss = bss;
/* Connect can take lots of time */ /* Connect can take lots of time */
mod_timer(&vif->connect_timer, mod_timer(&vif->connect_timer,
jiffies + msecs_to_jiffies(5000)); jiffies + msecs_to_jiffies(5000));
} else { } else {
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_vif_fwconnecting, vif->status);
} }
out: out:
...@@ -1040,8 +1040,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, ...@@ -1040,8 +1040,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n", wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n",
reason_code, vif->mid); reason_code, vif->mid);
if (!(test_bit(wil_status_fwconnecting, wil->status) || if (!(test_bit(wil_vif_fwconnecting, vif->status) ||
test_bit(wil_status_fwconnected, wil->status))) { test_bit(wil_vif_fwconnected, vif->status))) {
wil_err(wil, "Disconnect was called while disconnected\n"); wil_err(wil, "Disconnect was called while disconnected\n");
return 0; return 0;
} }
...@@ -1946,7 +1946,7 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy, ...@@ -1946,7 +1946,7 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
mutex_lock(&wil->vif_mutex); mutex_lock(&wil->vif_mutex);
wil_p2p_stop_radio_operations(wil); wil_p2p_stop_radio_operations(wil);
wil_abort_scan(ndev_to_vif(wil->main_ndev), true); wil_abort_scan_all_vifs(wil, true);
mutex_unlock(&wil->vif_mutex); mutex_unlock(&wil->vif_mutex);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
...@@ -2234,7 +2234,6 @@ void wil_cfg80211_deinit(struct wil6210_priv *wil) ...@@ -2234,7 +2234,6 @@ void wil_cfg80211_deinit(struct wil6210_priv *wil)
void wil_p2p_wdev_free(struct wil6210_priv *wil) void wil_p2p_wdev_free(struct wil6210_priv *wil)
{ {
struct wireless_dev *p2p_wdev; struct wireless_dev *p2p_wdev;
struct wil6210_vif *vif;
mutex_lock(&wil->vif_mutex); mutex_lock(&wil->vif_mutex);
p2p_wdev = wil->p2p_wdev; p2p_wdev = wil->p2p_wdev;
...@@ -2243,8 +2242,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil) ...@@ -2243,8 +2242,7 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
mutex_unlock(&wil->vif_mutex); mutex_unlock(&wil->vif_mutex);
if (p2p_wdev) { if (p2p_wdev) {
cfg80211_unregister_wdev(p2p_wdev); cfg80211_unregister_wdev(p2p_wdev);
vif = wdev_to_vif(wil, p2p_wdev); kfree(p2p_wdev);
kfree(vif);
} }
} }
...@@ -2538,7 +2536,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy, ...@@ -2538,7 +2536,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy,
return -ENOENT; return -ENOENT;
} }
} else { } else {
if (test_bit(wil_status_fwconnected, wil->status)) { if (test_bit(wil_vif_fwconnected, vif->status)) {
wil_err(wil, "must specify MAC address when connected\n"); wil_err(wil, "must specify MAC address when connected\n");
return -EINVAL; return -EINVAL;
} }
...@@ -2665,7 +2663,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy, ...@@ -2665,7 +2663,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy,
cid = -1; cid = -1;
} }
} else { } else {
if (test_bit(wil_status_fwconnected, wil->status)) { if (test_bit(wil_vif_fwconnected, vif->status)) {
wil_err(wil, "must specify MAC address when connected\n"); wil_err(wil, "must specify MAC address when connected\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -1201,12 +1201,13 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) ...@@ -1201,12 +1201,13 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
{ {
struct wil6210_priv *wil = s->private; struct wil6210_priv *wil = s->private;
struct station_info sinfo; struct station_info sinfo;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
int i, rc; int i, rc;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i]; struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown"; char *status = "unknown";
struct wil6210_vif *vif;
u8 mid;
switch (p->status) { switch (p->status) {
case wil_sta_unused: case wil_sta_unused:
...@@ -1219,9 +1220,15 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) ...@@ -1219,9 +1220,15 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
status = "connected"; status = "connected";
break; break;
} }
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
seq_printf(s, "[%d][MID %d] %pM %s\n",
i, mid, p->addr, status);
if (p->status == wil_sta_connected) { if (p->status != wil_sta_connected)
continue;
vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
if (vif) {
rc = wil_cid_fill_sinfo(vif, i, &sinfo); rc = wil_cid_fill_sinfo(vif, i, &sinfo);
if (rc) if (rc)
return rc; return rc;
...@@ -1229,6 +1236,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) ...@@ -1229,6 +1236,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
seq_printf(s, " SQ = %d\n", sinfo.signal); seq_printf(s, " SQ = %d\n", sinfo.signal);
} else {
seq_puts(s, " INVALID MID\n");
} }
} }
...@@ -1420,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) ...@@ -1420,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
struct wil_sta_info *p = &wil->sta[i]; struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown"; char *status = "unknown";
u8 aid = 0; u8 aid = 0;
u8 mid;
switch (p->status) { switch (p->status) {
case wil_sta_unused: case wil_sta_unused:
...@@ -1433,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) ...@@ -1433,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
aid = p->aid; aid = p->aid;
break; break;
} }
seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid); 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 (p->status == wil_sta_connected) { if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock); spin_lock_bh(&p->tid_rx_lock);
......
...@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil) ...@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
void wil6210_unmask_irq_rx(struct wil6210_priv *wil) void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{ {
bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status); bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC), wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH); unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
......
...@@ -175,6 +175,15 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) ...@@ -175,6 +175,15 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
cid, sta->mid, sta->status); cid, sta->mid, sta->status);
/* inform upper/lower layers */ /* inform upper/lower layers */
if (sta->status != wil_sta_unused) { 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) { if (!from_event) {
bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ? bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
disable_ap_sme : false; disable_ap_sme : false;
...@@ -277,32 +286,35 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, ...@@ -277,32 +286,35 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
wil_bcast_fini(vif); wil_bcast_fini(vif);
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev); netif_carrier_off(ndev);
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
if (test_bit(wil_status_fwconnected, wil->status)) { if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) {
clear_bit(wil_status_fwconnected, wil->status); atomic_dec(&wil->connected_vifs);
cfg80211_disconnected(ndev, reason_code, cfg80211_disconnected(ndev, reason_code,
NULL, 0, NULL, 0,
vif->locally_generated_disc, vif->locally_generated_disc,
GFP_KERNEL); GFP_KERNEL);
vif->locally_generated_disc = false; vif->locally_generated_disc = false;
} else if (test_bit(wil_status_fwconnecting, wil->status)) { } else if (test_bit(wil_vif_fwconnecting, vif->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL); GFP_KERNEL);
vif->bss = NULL; vif->bss = NULL;
} }
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_vif_fwconnecting, vif->status);
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
if (!wil_vif_is_connected(wil, vif->mid)) { if (!wil_vif_is_connected(wil, vif->mid)) {
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
clear_bit(wil_status_fwconnected, wil->status); if (test_and_clear_bit(wil_vif_fwconnected,
vif->status))
atomic_dec(&wil->connected_vifs);
} else { } else {
wil_update_net_queues_bh(wil, NULL, false); wil_update_net_queues_bh(wil, vif, NULL, false);
} }
break; break;
default: default:
...@@ -322,11 +334,11 @@ void wil_disconnect_worker(struct work_struct *work) ...@@ -322,11 +334,11 @@ void wil_disconnect_worker(struct work_struct *work)
struct wmi_disconnect_event evt; struct wmi_disconnect_event evt;
} __packed reply; } __packed reply;
if (test_bit(wil_status_fwconnected, wil->status)) if (test_bit(wil_vif_fwconnected, vif->status))
/* connect succeeded after all */ /* connect succeeded after all */
return; return;
if (!test_bit(wil_status_fwconnecting, wil->status)) if (!test_bit(wil_vif_fwconnecting, vif->status))
/* already disconnected */ /* already disconnected */
return; return;
...@@ -338,11 +350,11 @@ void wil_disconnect_worker(struct work_struct *work) ...@@ -338,11 +350,11 @@ void wil_disconnect_worker(struct work_struct *work)
return; return;
} }
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev); netif_carrier_off(ndev);
cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_vif_fwconnecting, vif->status);
} }
static int wil_wait_for_recovery(struct wil6210_priv *wil) static int wil_wait_for_recovery(struct wil6210_priv *wil)
...@@ -1087,6 +1099,20 @@ void wil_abort_scan(struct wil6210_vif *vif, bool sync) ...@@ -1087,6 +1099,20 @@ void wil_abort_scan(struct wil6210_vif *vif, bool sync)
} }
} }
void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
{
int i;
lockdep_assert_held(&wil->vif_mutex);
for (i = 0; i < wil->max_vifs; i++) {
struct wil6210_vif *vif = wil->vifs[i];
if (vif)
wil_abort_scan(vif, sync);
}
}
int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile)
{ {
int rc; int rc;
...@@ -1139,6 +1165,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil) ...@@ -1139,6 +1165,7 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
vif = wil->vifs[i]; vif = wil->vifs[i];
if (!vif) if (!vif)
continue; continue;
vif->ap_isolate = 0;
if (vif->mid) { if (vif->mid) {
ndev = vif_to_ndev(vif); ndev = vif_to_ndev(vif);
wdev = vif_to_wdev(vif); wdev = vif_to_wdev(vif);
...@@ -1162,10 +1189,10 @@ static int wil_restore_vifs(struct wil6210_priv *wil) ...@@ -1162,10 +1189,10 @@ static int wil_restore_vifs(struct wil6210_priv *wil)
*/ */
int wil_reset(struct wil6210_priv *wil, bool load_fw) int wil_reset(struct wil6210_priv *wil, bool load_fw)
{ {
int rc; int rc, i;
unsigned long status_flags = BIT(wil_status_resetting); unsigned long status_flags = BIT(wil_status_resetting);
int no_flash; int no_flash;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wil6210_vif *vif;
wil_dbg_misc(wil, "reset\n"); wil_dbg_misc(wil, "reset\n");
...@@ -1214,17 +1241,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1214,17 +1241,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
goto out; 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++) {
vif = wil->vifs[i];
if (vif) {
cancel_work_sync(&vif->disconnect_worker); cancel_work_sync(&vif->disconnect_worker);
wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil6210_disconnect(vif, NULL,
WLAN_REASON_DEAUTH_LEAVING, false);
}
}
wil_bcast_fini_all(wil); wil_bcast_fini_all(wil);
/* Disable device led before reset*/ /* Disable device led before reset*/
wmi_led_cfg(wil, false); wmi_led_cfg(wil, false);
mutex_lock(&wil->vif_mutex);
wil_abort_scan(vif, false);
mutex_unlock(&wil->vif_mutex);
/* prevent NAPI from being scheduled and prevent wmi commands */ /* prevent NAPI from being scheduled and prevent wmi commands */
mutex_lock(&wil->wmi_mutex); mutex_lock(&wil->wmi_mutex);
if (test_bit(wil_status_suspending, wil->status)) if (test_bit(wil_status_suspending, wil->status))
...@@ -1294,7 +1327,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1294,7 +1327,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
} }
/* init after reset */ /* init after reset */
vif->ap_isolate = 0;
reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call); reinit_completion(&wil->wmi_call);
reinit_completion(&wil->halp.comp); reinit_completion(&wil->halp.comp);
...@@ -1446,7 +1478,7 @@ int __wil_down(struct wil6210_priv *wil) ...@@ -1446,7 +1478,7 @@ int __wil_down(struct wil6210_priv *wil)
mutex_lock(&wil->vif_mutex); mutex_lock(&wil->vif_mutex);
wil_p2p_stop_radio_operations(wil); wil_p2p_stop_radio_operations(wil);
wil_abort_scan(ndev_to_vif(wil->main_ndev), false); wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->vif_mutex); mutex_unlock(&wil->vif_mutex);
return wil_reset(wil, false); return wil_reset(wil, false);
......
...@@ -43,6 +43,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil, ...@@ -43,6 +43,7 @@ bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok) bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
{ {
/* use NULL ndev argument to check all interfaces */
return wil_has_other_active_ifaces(wil, NULL, up, ok); return wil_has_other_active_ifaces(wil, NULL, up, ok);
} }
...@@ -130,11 +131,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) ...@@ -130,11 +131,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *vring = &wil->vring_tx[i]; struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i]; struct vring_tx_data *txdata = &wil->vring_tx_data[i];
struct wil6210_vif *vif;
if (!vring->va || !txdata->enabled ||
txdata->mid >= wil->max_vifs)
continue;
if (!vring->va || !txdata->enabled) vif = wil->vifs[txdata->mid];
if (unlikely(!vif)) {
wil_dbg_txrx(wil, "Invalid MID %d\n", txdata->mid);
continue; continue;
}
tx_done += wil_tx_complete(wil, i); tx_done += wil_tx_complete(vif, i);
} }
if (tx_done < budget) { if (tx_done < budget) {
...@@ -232,6 +241,8 @@ static void wil_vif_init(struct wil6210_vif *vif) ...@@ -232,6 +241,8 @@ static void wil_vif_init(struct wil6210_vif *vif)
INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
INIT_LIST_HEAD(&vif->probe_client_pending); INIT_LIST_HEAD(&vif->probe_client_pending);
vif->net_queue_stopped = 1;
} }
static u8 wil_vif_find_free_mid(struct wil6210_priv *wil) static u8 wil_vif_find_free_mid(struct wil6210_priv *wil)
...@@ -406,12 +417,14 @@ int wil_if_add(struct wil6210_priv *wil) ...@@ -406,12 +417,14 @@ int wil_if_add(struct wil6210_priv *wil)
return rc; return rc;
} }
netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx, init_dummy_netdev(&wil->napi_ndev);
netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
WIL6210_NAPI_BUDGET); WIL6210_NAPI_BUDGET);
netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, netif_tx_napi_add(&wil->napi_ndev,
&wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET); WIL6210_NAPI_BUDGET);
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
rtnl_lock(); rtnl_lock();
rc = wil_vif_add(wil, vif); rc = wil_vif_add(wil, vif);
...@@ -450,10 +463,29 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) ...@@ -450,10 +463,29 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
*/ */
unregister_netdevice(ndev); unregister_netdevice(ndev);
mutex_lock(&wil->mutex);
wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
mutex_unlock(&wil->mutex);
if (any_active && vif->mid != 0) if (any_active && vif->mid != 0)
wmi_port_delete(wil, vif->mid); wmi_port_delete(wil, vif->mid);
/* make sure no one is accessing the VIF before removing */
mutex_lock(&wil->vif_mutex);
wil->vifs[mid] = NULL; wil->vifs[mid] = NULL;
/* ensure NAPI code will see the NULL VIF */
wmb();
if (test_bit(wil_status_napi_en, wil->status)) {
napi_synchronize(&wil->napi_rx);
napi_synchronize(&wil->napi_tx);
}
mutex_unlock(&wil->vif_mutex);
flush_work(&wil->wmi_event_worker);
del_timer_sync(&vif->connect_timer);
cancel_work_sync(&vif->disconnect_worker);
wil_probe_client_flush(vif);
cancel_work_sync(&vif->probe_client_worker);
/* for VIFs, ndev will be freed by destructor after RTNL is unlocked. /* 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 * the main interface will be freed in wil_if_free, we need to keep it
* a bit longer so logging macros will work. * a bit longer so logging macros will work.
...@@ -470,5 +502,9 @@ void wil_if_remove(struct wil6210_priv *wil) ...@@ -470,5 +502,9 @@ void wil_if_remove(struct wil6210_priv *wil)
rtnl_lock(); rtnl_lock();
wil_vif_remove(wil, 0); wil_vif_remove(wil, 0);
rtnl_unlock(); rtnl_unlock();
netif_napi_del(&wil->napi_tx);
netif_napi_del(&wil->napi_rx);
wiphy_unregister(wdev->wiphy); wiphy_unregister(wdev->wiphy);
} }
...@@ -450,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime) ...@@ -450,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
int rc = 0; int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev); struct wil6210_priv *wil = pci_get_drvdata(pdev);
struct net_device *ndev = wil->main_ndev; bool keep_radio_on, active_ifaces;
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
rc = wil_can_suspend(wil, is_runtime); rc = wil_can_suspend(wil, is_runtime);
if (rc) if (rc)
goto out; goto out;
...@@ -482,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime) ...@@ -482,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
int rc = 0; int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev); struct wil6210_priv *wil = pci_get_drvdata(pdev);
struct net_device *ndev = wil->main_ndev; bool keep_radio_on, active_ifaces;
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
/* In case radio stays on, platform device will control /* In case radio stays on, platform device will control
* PCIe master * PCIe master
*/ */
......
...@@ -21,13 +21,72 @@ ...@@ -21,13 +21,72 @@
#define WIL6210_AUTOSUSPEND_DELAY_MS (1000) #define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
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++) {
struct wil6210_vif *vif = wil->vifs[i];
if (vif && test_bit(wil_vif_fwconnected, vif->status))
wil_update_net_queues_bh(wil, vif, NULL, false);
}
mutex_unlock(&wil->vif_mutex);
}
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++) {
struct wil6210_vif *vif = wil->vifs[i];
if (vif)
wil_update_net_queues_bh(wil, vif, NULL, true);
}
mutex_unlock(&wil->vif_mutex);
}
static bool
wil_can_suspend_vif(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool is_runtime)
{
struct wireless_dev *wdev = vif_to_wdev(vif);
switch (wdev->iftype) {
case NL80211_IFTYPE_MONITOR:
wil_dbg_pm(wil, "Sniffer\n");
return false;
/* for STA-like interface, don't runtime suspend */
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
if (test_bit(wil_vif_fwconnecting, vif->status)) {
wil_dbg_pm(wil, "Delay suspend when connecting\n");
return false;
}
if (is_runtime) {
wil_dbg_pm(wil, "STA-like interface\n");
return false;
}
break;
/* AP-like interface - can't suspend */
default:
wil_dbg_pm(wil, "AP-like interface\n");
return false;
}
return true;
}
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
{ {
int rc = 0; int rc = 0, i;
struct net_device *ndev = wil->main_ndev;
struct wireless_dev *wdev = ndev->ieee80211_ptr;
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY, bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
wil->fw_capabilities); wil->fw_capabilities);
bool active_ifaces;
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
...@@ -41,7 +100,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) ...@@ -41,7 +100,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
rc = -EBUSY; rc = -EBUSY;
goto out; goto out;
} }
if (!(ndev->flags & IFF_UP)) {
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
if (!active_ifaces) {
/* can always sleep when down */ /* can always sleep when down */
wil_dbg_pm(wil, "Interface is down\n"); wil_dbg_pm(wil, "Interface is down\n");
goto out; goto out;
...@@ -58,32 +122,19 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) ...@@ -58,32 +122,19 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
} }
/* interface is running */ /* interface is running */
switch (wdev->iftype) { mutex_lock(&wil->vif_mutex);
case NL80211_IFTYPE_MONITOR: for (i = 0; i < wil->max_vifs; i++) {
wil_dbg_pm(wil, "Sniffer\n"); struct wil6210_vif *vif = wil->vifs[i];
rc = -EBUSY;
goto out; if (!vif)
/* for STA-like interface, don't runtime suspend */ continue;
case NL80211_IFTYPE_STATION: if (!wil_can_suspend_vif(wil, vif, is_runtime)) {
case NL80211_IFTYPE_P2P_CLIENT:
if (test_bit(wil_status_fwconnecting, wil->status)) {
wil_dbg_pm(wil, "Delay suspend when connecting\n");
rc = -EBUSY;
goto out;
}
/* Runtime pm not supported in case the interface is up */
if (is_runtime) {
wil_dbg_pm(wil, "STA-like interface\n");
rc = -EBUSY; rc = -EBUSY;
mutex_unlock(&wil->vif_mutex);
goto out; goto out;
} }
break;
/* AP-like interface - can't suspend */
default:
wil_dbg_pm(wil, "AP-like interface\n");
rc = -EBUSY;
break;
} }
mutex_unlock(&wil->vif_mutex);
out: out:
wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n",
...@@ -128,8 +179,7 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil) ...@@ -128,8 +179,7 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
} }
/* Wake all queues */ /* Wake all queues */
if (test_bit(wil_status_fwconnected, wil->status)) wil_pm_wake_connected_net_queues(wil);
wil_update_net_queues_bh(wil, NULL, false);
out: out:
if (rc) if (rc)
...@@ -153,7 +203,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) ...@@ -153,7 +203,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
wil->suspend_stats.rejected_by_host++; wil->suspend_stats.rejected_by_host++;
return -EBUSY; return -EBUSY;
} }
wil_update_net_queues_bh(wil, NULL, true); wil_pm_stop_all_net_queues(wil);
if (!wil_is_tx_idle(wil)) { if (!wil_is_tx_idle(wil)) {
wil_dbg_pm(wil, "Pending TX data, reject suspend\n"); wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
...@@ -244,22 +294,20 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) ...@@ -244,22 +294,20 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
/* if resume succeeded, reject the suspend */ /* if resume succeeded, reject the suspend */
if (!rc) { if (!rc) {
rc = -EBUSY; rc = -EBUSY;
if (test_bit(wil_status_fwconnected, wil->status)) wil_pm_wake_connected_net_queues(wil);
wil_update_net_queues_bh(wil, NULL, false);
} }
return rc; return rc;
reject_suspend: reject_suspend:
clear_bit(wil_status_suspending, wil->status); clear_bit(wil_status_suspending, wil->status);
if (test_bit(wil_status_fwconnected, wil->status)) wil_pm_wake_connected_net_queues(wil);
wil_update_net_queues_bh(wil, NULL, false);
return -EBUSY; return -EBUSY;
} }
static int wil_suspend_radio_off(struct wil6210_priv *wil) static int wil_suspend_radio_off(struct wil6210_priv *wil)
{ {
int rc = 0; int rc = 0;
struct net_device *ndev = wil->main_ndev; bool active_ifaces;
wil_dbg_pm(wil, "suspend radio off\n"); wil_dbg_pm(wil, "suspend radio off\n");
...@@ -273,7 +321,11 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) ...@@ -273,7 +321,11 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
} }
/* if netif up, hardware is alive, shut it down */ /* if netif up, hardware is alive, shut it down */
if (ndev->flags & IFF_UP) { mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
if (active_ifaces) {
rc = wil_down(wil); rc = wil_down(wil);
if (rc) { if (rc) {
wil_err(wil, "wil_down : %d\n", rc); wil_err(wil, "wil_down : %d\n", rc);
...@@ -307,16 +359,19 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) ...@@ -307,16 +359,19 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
static int wil_resume_radio_off(struct wil6210_priv *wil) static int wil_resume_radio_off(struct wil6210_priv *wil)
{ {
int rc = 0; int rc = 0;
struct net_device *ndev = wil->main_ndev; bool active_ifaces;
wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); wil_dbg_pm(wil, "Enabling PCIe IRQ\n");
wil_enable_irq(wil); wil_enable_irq(wil);
/* if netif up, bring hardware up /* if any netif up, bring hardware up
* During open(), IFF_UP set after actual device method * During open(), IFF_UP set after actual device method
* invocation. This prevent recursive call to wil_up() * invocation. This prevent recursive call to wil_up()
* wil_status_suspended will be cleared in wil_reset * wil_status_suspended will be cleared in wil_reset
*/ */
if (ndev->flags & IFF_UP) mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
if (active_ifaces)
rc = wil_up(wil); rc = wil_up(wil);
else else
clear_bit(wil_status_suspended, wil->status); clear_bit(wil_status_suspended, wil->status);
......
...@@ -41,11 +41,10 @@ static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) ...@@ -41,11 +41,10 @@ static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
return seq_sub(seq, r->ssn) % r->buf_size; return seq_sub(seq, r->ssn) % r->buf_size;
} }
static void wil_release_reorder_frame(struct wil6210_priv *wil, static void wil_release_reorder_frame(struct net_device *ndev,
struct wil_tid_ampdu_rx *r, struct wil_tid_ampdu_rx *r,
int index) int index)
{ {
struct net_device *ndev = wil->main_ndev;
struct sk_buff *skb = r->reorder_buf[index]; struct sk_buff *skb = r->reorder_buf[index];
if (!skb) if (!skb)
...@@ -60,7 +59,7 @@ static void wil_release_reorder_frame(struct wil6210_priv *wil, ...@@ -60,7 +59,7 @@ static void wil_release_reorder_frame(struct wil6210_priv *wil,
r->head_seq_num = seq_inc(r->head_seq_num); r->head_seq_num = seq_inc(r->head_seq_num);
} }
static void wil_release_reorder_frames(struct wil6210_priv *wil, static void wil_release_reorder_frames(struct net_device *ndev,
struct wil_tid_ampdu_rx *r, struct wil_tid_ampdu_rx *r,
u16 hseq) u16 hseq)
{ {
...@@ -74,18 +73,18 @@ static void wil_release_reorder_frames(struct wil6210_priv *wil, ...@@ -74,18 +73,18 @@ static void wil_release_reorder_frames(struct wil6210_priv *wil,
*/ */
while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) { while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) {
index = reorder_index(r, r->head_seq_num); index = reorder_index(r, r->head_seq_num);
wil_release_reorder_frame(wil, r, index); wil_release_reorder_frame(ndev, r, index);
} }
r->head_seq_num = hseq; r->head_seq_num = hseq;
} }
static void wil_reorder_release(struct wil6210_priv *wil, static void wil_reorder_release(struct net_device *ndev,
struct wil_tid_ampdu_rx *r) struct wil_tid_ampdu_rx *r)
{ {
int index = reorder_index(r, r->head_seq_num); int index = reorder_index(r, r->head_seq_num);
while (r->reorder_buf[index]) { while (r->reorder_buf[index]) {
wil_release_reorder_frame(wil, r, index); wil_release_reorder_frame(ndev, r, index);
index = reorder_index(r, r->head_seq_num); index = reorder_index(r, r->head_seq_num);
} }
} }
...@@ -94,7 +93,8 @@ static void wil_reorder_release(struct wil6210_priv *wil, ...@@ -94,7 +93,8 @@ static void wil_reorder_release(struct wil6210_priv *wil,
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{ {
struct net_device *ndev = wil->main_ndev; struct wil6210_vif *vif;
struct net_device *ndev;
struct vring_rx_desc *d = wil_skb_rxdesc(skb); struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int tid = wil_rxdesc_tid(d); int tid = wil_rxdesc_tid(d);
int cid = wil_rxdesc_cid(d); int cid = wil_rxdesc_cid(d);
...@@ -109,6 +109,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) ...@@ -109,6 +109,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
mid, cid, tid, seq, mcast); mid, cid, tid, seq, mcast);
vif = wil->vifs[mid];
if (unlikely(!vif)) {
wil_dbg_txrx(wil, "invalid VIF, mid %d\n", mid);
dev_kfree_skb(skb);
return;
}
ndev = vif_to_ndev(vif);
if (unlikely(mcast)) { if (unlikely(mcast)) {
wil_netif_rx_any(skb, ndev); wil_netif_rx_any(skb, ndev);
return; return;
...@@ -169,7 +177,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) ...@@ -169,7 +177,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
if (!seq_less(seq, r->head_seq_num + r->buf_size)) { if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
hseq = seq_inc(seq_sub(seq, r->buf_size)); hseq = seq_inc(seq_sub(seq, r->buf_size));
/* release stored frames up to new head to stack */ /* release stored frames up to new head to stack */
wil_release_reorder_frames(wil, r, hseq); wil_release_reorder_frames(ndev, r, hseq);
} }
/* Now the new frame is always in the range of the reordering buffer */ /* Now the new frame is always in the range of the reordering buffer */
...@@ -200,16 +208,18 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) ...@@ -200,16 +208,18 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
r->reorder_buf[index] = skb; r->reorder_buf[index] = skb;
r->reorder_time[index] = jiffies; r->reorder_time[index] = jiffies;
r->stored_mpdu_num++; r->stored_mpdu_num++;
wil_reorder_release(wil, r); wil_reorder_release(ndev, r);
out: out:
spin_unlock(&sta->tid_rx_lock); spin_unlock(&sta->tid_rx_lock);
} }
/* process BAR frame, called in NAPI context */ /* process BAR frame, called in NAPI context */
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq) void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
u8 cid, u8 tid, u16 seq)
{ {
struct wil_sta_info *sta = &wil->sta[cid]; struct wil_sta_info *sta = &wil->sta[cid];
struct net_device *ndev = vif_to_ndev(vif);
struct wil_tid_ampdu_rx *r; struct wil_tid_ampdu_rx *r;
spin_lock(&sta->tid_rx_lock); spin_lock(&sta->tid_rx_lock);
...@@ -224,9 +234,9 @@ void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq) ...@@ -224,9 +234,9 @@ void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
seq, r->head_seq_num); seq, r->head_seq_num);
goto out; goto out;
} }
wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n", wil_dbg_txrx(wil, "BAR: CID %d MID %d TID %d Seq 0x%03x head 0x%03x\n",
cid, tid, seq, r->head_seq_num); cid, vif->mid, tid, seq, r->head_seq_num);
wil_release_reorder_frames(wil, r, seq); wil_release_reorder_frames(ndev, r, seq);
out: out:
spin_unlock(&sta->tid_rx_lock); spin_unlock(&sta->tid_rx_lock);
......
...@@ -475,7 +475,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -475,7 +475,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
struct vring *vring) struct vring *vring)
{ {
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct net_device *ndev = wil->main_ndev; struct wil6210_vif *vif;
struct net_device *ndev;
volatile struct vring_rx_desc *_d; volatile struct vring_rx_desc *_d;
struct vring_rx_desc *d; struct vring_rx_desc *d;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -484,7 +485,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -484,7 +485,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen; unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen;
u16 dmalen; u16 dmalen;
u8 ftype; u8 ftype;
int cid; int cid, mid;
int i; int i;
struct wil_net_stats *stats; struct wil_net_stats *stats;
...@@ -521,6 +522,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -521,6 +522,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
(const void *)d, sizeof(*d), false); (const void *)d, sizeof(*d), false);
cid = wil_rxdesc_cid(d); cid = wil_rxdesc_cid(d);
mid = wil_rxdesc_mid(d);
vif = wil->vifs[mid];
if (unlikely(!vif)) {
wil_dbg_txrx(wil, "skipped RX descriptor with invalid mid %d",
mid);
kfree_skb(skb);
goto again;
}
ndev = vif_to_ndev(vif);
stats = &wil->sta[cid].stats; stats = &wil->sta[cid].stats;
if (unlikely(dmalen > sz)) { if (unlikely(dmalen > sz)) {
...@@ -554,7 +565,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -554,7 +565,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
ftype = wil_rxdesc_ftype(d) << 2; ftype = wil_rxdesc_ftype(d) << 2;
if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
u8 fc1 = wil_rxdesc_fc1(d); u8 fc1 = wil_rxdesc_fc1(d);
int mid = wil_rxdesc_mid(d);
int tid = wil_rxdesc_tid(d); int tid = wil_rxdesc_tid(d);
u16 seq = wil_rxdesc_seq(d); u16 seq = wil_rxdesc_seq(d);
...@@ -566,7 +576,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -566,7 +576,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
wil_dbg_txrx(wil, wil_dbg_txrx(wil,
"BAR: MID %d CID %d TID %d Seq 0x%03x\n", "BAR: MID %d CID %d TID %d Seq 0x%03x\n",
mid, cid, tid, seq); mid, cid, tid, seq);
wil_rx_bar(wil, cid, tid, seq); wil_rx_bar(wil, vif, cid, tid, seq);
} else { } else {
/* print again all info. One can enable only this /* print again all info. One can enable only this
* without overhead for printing every Rx frame * without overhead for printing every Rx frame
...@@ -622,6 +632,11 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, ...@@ -622,6 +632,11 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
/** /**
* allocate and fill up to @count buffers in rx ring * allocate and fill up to @count buffers in rx ring
* buffers posted at @swtail * buffers posted at @swtail
* Note: we have a single RX queue for servicing all VIFs, but we
* allocate skbs with headroom according to main interface only. This
* means it will not work with monitor interface together with other VIFs.
* Currently we only support monitor interface on its own without other VIFs,
* and we will need to fix this code once we add support.
*/ */
static int wil_rx_refill(struct wil6210_priv *wil, int count) static int wil_rx_refill(struct wil6210_priv *wil, int count)
{ {
...@@ -789,8 +804,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) ...@@ -789,8 +804,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
} }
if (skb) { /* deliver to local stack */ if (skb) { /* deliver to local stack */
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
skb->dev = ndev;
rc = napi_gro_receive(&wil->napi_rx, skb); rc = napi_gro_receive(&wil->napi_rx, skb);
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
len, gro_res_str[rc]); len, gro_res_str[rc]);
...@@ -1905,6 +1920,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, ...@@ -1905,6 +1920,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
/** /**
* Check status of tx vrings and stop/wake net queues if needed * Check status of tx vrings and stop/wake net queues if needed
* It will start/stop net queues of a specific VIF net_device.
* *
* This function does one of two checks: * This function does one of two checks:
* In case check_stop is true, will check if net queues need to be stopped. If * In case check_stop is true, will check if net queues need to be stopped. If
...@@ -1920,28 +1936,32 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, ...@@ -1920,28 +1936,32 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
* availability and modified vring has high descriptor availability. * availability and modified vring has high descriptor availability.
*/ */
static inline void __wil_update_net_queues(struct wil6210_priv *wil, static inline void __wil_update_net_queues(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct vring *vring, struct vring *vring,
bool check_stop) bool check_stop)
{ {
int i; int i;
if (unlikely(!vif))
return;
if (vring) if (vring)
wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d", wil_dbg_txrx(wil, "vring %d, mid %d, check_stop=%d, stopped=%d",
(int)(vring - wil->vring_tx), check_stop, (int)(vring - wil->vring_tx), vif->mid, check_stop,
wil->net_queue_stopped); vif->net_queue_stopped);
else else
wil_dbg_txrx(wil, "check_stop=%d, stopped=%d", wil_dbg_txrx(wil, "check_stop=%d, mid=%d, stopped=%d",
check_stop, wil->net_queue_stopped); check_stop, vif->mid, vif->net_queue_stopped);
if (check_stop == wil->net_queue_stopped) if (check_stop == vif->net_queue_stopped)
/* net queues already in desired state */ /* net queues already in desired state */
return; return;
if (check_stop) { if (check_stop) {
if (!vring || unlikely(wil_vring_avail_low(vring))) { if (!vring || unlikely(wil_vring_avail_low(vring))) {
/* not enough room in the vring */ /* not enough room in the vring */
netif_tx_stop_all_queues(wil->main_ndev); netif_tx_stop_all_queues(vif_to_ndev(vif));
wil->net_queue_stopped = true; vif->net_queue_stopped = true;
wil_dbg_txrx(wil, "netif_tx_stop called\n"); wil_dbg_txrx(wil, "netif_tx_stop called\n");
} }
return; return;
...@@ -1957,7 +1977,8 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, ...@@ -1957,7 +1977,8 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
struct vring *cur_vring = &wil->vring_tx[i]; struct vring *cur_vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[i]; struct vring_tx_data *txdata = &wil->vring_tx_data[i];
if (!cur_vring->va || !txdata->enabled || cur_vring == vring) if (txdata->mid != vif->mid || !cur_vring->va ||
!txdata->enabled || cur_vring == vring)
continue; continue;
if (wil_vring_avail_low(cur_vring)) { if (wil_vring_avail_low(cur_vring)) {
...@@ -1970,24 +1991,24 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, ...@@ -1970,24 +1991,24 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
if (!vring || wil_vring_avail_high(vring)) { if (!vring || wil_vring_avail_high(vring)) {
/* enough room in the vring */ /* enough room in the vring */
wil_dbg_txrx(wil, "calling netif_tx_wake\n"); wil_dbg_txrx(wil, "calling netif_tx_wake\n");
netif_tx_wake_all_queues(wil->main_ndev); netif_tx_wake_all_queues(vif_to_ndev(vif));
wil->net_queue_stopped = false; vif->net_queue_stopped = false;
} }
} }
void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool check_stop) struct vring *vring, bool check_stop)
{ {
spin_lock(&wil->net_queue_lock); spin_lock(&wil->net_queue_lock);
__wil_update_net_queues(wil, vring, check_stop); __wil_update_net_queues(wil, vif, vring, check_stop);
spin_unlock(&wil->net_queue_lock); spin_unlock(&wil->net_queue_lock);
} }
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool check_stop) struct vring *vring, bool check_stop)
{ {
spin_lock_bh(&wil->net_queue_lock); spin_lock_bh(&wil->net_queue_lock);
__wil_update_net_queues(wil, vring, check_stop); __wil_update_net_queues(wil, vif, vring, check_stop);
spin_unlock_bh(&wil->net_queue_lock); spin_unlock_bh(&wil->net_queue_lock);
} }
...@@ -2009,8 +2030,9 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -2009,8 +2030,9 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} }
goto drop; goto drop;
} }
if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { if (unlikely(!test_bit(wil_vif_fwconnected, vif->status))) {
wil_dbg_ratelimited(wil, "FW not connected, packet dropped\n"); wil_dbg_ratelimited(wil,
"VIF not connected, packet dropped\n");
goto drop; goto drop;
} }
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_MONITOR)) { if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_MONITOR)) {
...@@ -2051,7 +2073,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -2051,7 +2073,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
switch (rc) { switch (rc) {
case 0: case 0:
/* shall we stop net queues? */ /* shall we stop net queues? */
wil_update_net_queues_bh(wil, vring, true); wil_update_net_queues_bh(wil, vif, vring, true);
/* statistics will be updated on the tx_complete */ /* statistics will be updated on the tx_complete */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -2090,9 +2112,10 @@ static inline void wil_consume_skb(struct sk_buff *skb, bool acked) ...@@ -2090,9 +2112,10 @@ static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
* *
* Safe to call from IRQ * Safe to call from IRQ
*/ */
int wil_tx_complete(struct wil6210_priv *wil, int ringid) int wil_tx_complete(struct wil6210_vif *vif, int ringid)
{ {
struct net_device *ndev = wil->main_ndev; struct wil6210_priv *wil = vif_to_wil(vif);
struct net_device *ndev = vif_to_ndev(vif);
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid]; struct vring *vring = &wil->vring_tx[ringid];
struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
...@@ -2202,7 +2225,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) ...@@ -2202,7 +2225,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
/* shall we wake net queues? */ /* shall we wake net queues? */
if (done) if (done)
wil_update_net_queues(wil, vring, false); wil_update_net_queues(wil, vif, vring, false);
return done; return done;
} }
/* /*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * Copyright (c) 2012-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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, ...@@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* [dword 1] * [dword 1]
* bit 0.. 3 : pkt_mode:4 * bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1 * bit 4 : pkt_mode_en:1
* bit 5..14 : reserved0:10 * bit 5 : mac_id_en:1
* bit 6..7 : mac_id:2
* bit 8..14 : reserved0:7
* bit 15 : ack_policy_en:1 * bit 15 : ack_policy_en:1
* bit 16..19 : dst_index:4 * bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1 * bit 20 : dst_index_en:1
...@@ -132,6 +135,14 @@ struct vring_tx_mac { ...@@ -132,6 +135,14 @@ struct vring_tx_mac {
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1 #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_POS 5
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_LEN 1
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_MSK 0x20
#define MAC_CFG_DESC_TX_1_MAC_ID_POS 6
#define MAC_CFG_DESC_TX_1_MAC_ID_LEN 2
#define MAC_CFG_DESC_TX_1_MAC_ID_MSK 0xc0
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
...@@ -304,7 +315,7 @@ enum { ...@@ -304,7 +315,7 @@ enum {
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
* bit 4.. 6 : cid:3 The Source index that was found during parsing the TA. * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA.
* This field is used to define the source of the packet * This field is used to define the source of the packet
* bit 7 : reserved:1 * bit 7 : MAC_id_valid:1, 1 if MAC virtual number is valid.
* bit 8.. 9 : mid:2 The MAC virtual number * bit 8.. 9 : mid:2 The MAC virtual number
* bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
* (management, data, control and extension) * (management, data, control and extension)
...@@ -395,6 +406,7 @@ struct vring_rx_mac { ...@@ -395,6 +406,7 @@ struct vring_rx_mac {
#define RX_DMA_D0_CMD_DMA_EOP BIT(8) #define RX_DMA_D0_CMD_DMA_EOP BIT(8)
#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */ #define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */ #define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
#define RX_MAC_D0_MAC_ID_VALID BIT(7)
/* Error field */ /* Error field */
#define RX_DMA_ERROR_FCS BIT(0) #define RX_DMA_ERROR_FCS BIT(0)
...@@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d) ...@@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d)
static inline int wil_rxdesc_mid(struct vring_rx_desc *d) static inline int wil_rxdesc_mid(struct vring_rx_desc *d)
{ {
return WIL_GET_BITS(d->mac.d0, 8, 9); return (d->mac.d0 & RX_MAC_D0_MAC_ID_VALID) ?
WIL_GET_BITS(d->mac.d0, 8, 9) : 0;
} }
static inline int wil_rxdesc_ftype(struct vring_rx_desc *d) static inline int wil_rxdesc_ftype(struct vring_rx_desc *d)
...@@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) ...@@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq); void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
u8 cid, u8 tid, u16 seq);
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn); int size, u16 ssn);
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
......
...@@ -475,8 +475,6 @@ struct vring_tx_data { ...@@ -475,8 +475,6 @@ struct vring_tx_data {
enum { /* for wil6210_priv.status */ enum { /* for wil6210_priv.status */
wil_status_fwready = 0, /* FW operational */ wil_status_fwready = 0, /* FW operational */
wil_status_fwconnecting,
wil_status_fwconnected,
wil_status_dontscan, wil_status_dontscan,
wil_status_mbox_ready, /* MBOX structures ready */ wil_status_mbox_ready, /* MBOX structures ready */
wil_status_irqen, /* interrupts enabled - for debug */ wil_status_irqen, /* interrupts enabled - for debug */
...@@ -676,11 +674,18 @@ extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST]; ...@@ -676,11 +674,18 @@ extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
extern u8 led_id; extern u8 led_id;
extern u8 led_polarity; extern u8 led_polarity;
enum wil6210_vif_status {
wil_vif_fwconnecting,
wil_vif_fwconnected,
wil_vif_status_last /* keep last */
};
struct wil6210_vif { struct wil6210_vif {
struct wireless_dev wdev; struct wireless_dev wdev;
struct net_device *ndev; struct net_device *ndev;
struct wil6210_priv *wil; struct wil6210_priv *wil;
u8 mid; u8 mid;
DECLARE_BITMAP(status, wil_vif_status_last);
u32 privacy; /* secure connection? */ u32 privacy; /* secure connection? */
u16 channel; /* relevant in AP mode */ u16 channel; /* relevant in AP mode */
u8 hidden_ssid; /* relevant in AP mode */ u8 hidden_ssid; /* relevant in AP mode */
...@@ -699,6 +704,7 @@ struct wil6210_vif { ...@@ -699,6 +704,7 @@ struct wil6210_vif {
struct list_head probe_client_pending; struct list_head probe_client_pending;
struct mutex probe_client_mutex; /* protect @probe_client_pending */ struct mutex probe_client_mutex; /* protect @probe_client_pending */
struct work_struct probe_client_worker; struct work_struct probe_client_worker;
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
}; };
struct wil6210_priv { struct wil6210_priv {
...@@ -726,6 +732,7 @@ struct wil6210_priv { ...@@ -726,6 +732,7 @@ struct wil6210_priv {
u8 max_vifs; /* maximum number of interfaces, including main */ u8 max_vifs; /* maximum number of interfaces, including main */
struct wil6210_vif *vifs[WIL_MAX_VIFS]; struct wil6210_vif *vifs[WIL_MAX_VIFS];
struct mutex vif_mutex; /* protects access to VIF entries */ struct mutex vif_mutex; /* protects access to VIF entries */
atomic_t connected_vifs;
/* profile */ /* profile */
struct cfg80211_chan_def monitor_chandef; struct cfg80211_chan_def monitor_chandef;
u32 monitor_flags; u32 monitor_flags;
...@@ -759,9 +766,10 @@ struct wil6210_priv { ...@@ -759,9 +766,10 @@ struct wil6210_priv {
*/ */
spinlock_t wmi_ev_lock; spinlock_t wmi_ev_lock;
spinlock_t net_queue_lock; /* guarding stop/wake netif queue */ spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
struct napi_struct napi_rx; struct napi_struct napi_rx;
struct napi_struct napi_tx; struct napi_struct napi_tx;
struct net_device napi_ndev; /* dummy net_device serving all VIFs */
/* DMA related */ /* DMA related */
struct vring vring_rx; struct vring vring_rx;
unsigned int rx_buf_len; unsigned int rx_buf_len;
...@@ -1077,6 +1085,7 @@ int wmi_pcp_stop(struct wil6210_vif *vif); ...@@ -1077,6 +1085,7 @@ int wmi_pcp_stop(struct wil6210_vif *vif);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable); int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
int wmi_abort_scan(struct wil6210_vif *vif); int wmi_abort_scan(struct wil6210_vif *vif);
void wil_abort_scan(struct wil6210_vif *vif, bool sync); void wil_abort_scan(struct wil6210_vif *vif, bool sync);
void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync);
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps); void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps);
void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
u16 reason_code, bool from_event); u16 reason_code, bool from_event);
...@@ -1097,12 +1106,12 @@ int wil_bcast_init(struct wil6210_vif *vif); ...@@ -1097,12 +1106,12 @@ int wil_bcast_init(struct wil6210_vif *vif);
void wil_bcast_fini(struct wil6210_vif *vif); void wil_bcast_fini(struct wil6210_vif *vif);
void wil_bcast_fini_all(struct wil6210_priv *wil); void wil_bcast_fini_all(struct wil6210_priv *wil);
void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool should_stop); struct vring *vring, bool should_stop);
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool check_stop); struct vring *vring, bool check_stop);
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
int wil_tx_complete(struct wil6210_priv *wil, int ringid); int wil_tx_complete(struct wil6210_vif *vif, int ringid);
void wil6210_unmask_irq_tx(struct wil6210_priv *wil); void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
/* RX API */ /* RX API */
......
...@@ -886,7 +886,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) ...@@ -886,7 +886,7 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) || if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (!test_bit(wil_status_fwconnecting, wil->status)) { if (!test_bit(wil_vif_fwconnecting, vif->status)) {
wil_err(wil, "Not in connecting state\n"); wil_err(wil, "Not in connecting state\n");
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
return; return;
...@@ -965,15 +965,16 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) ...@@ -965,15 +965,16 @@ static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len)
wil->sta[evt->cid].status = wil_sta_connected; wil->sta[evt->cid].status = wil_sta_connected;
wil->sta[evt->cid].aid = evt->aid; wil->sta[evt->cid].aid = evt->aid;
set_bit(wil_status_fwconnected, wil->status); if (!test_and_set_bit(wil_vif_fwconnected, vif->status))
wil_update_net_queues_bh(wil, NULL, false); atomic_inc(&wil->connected_vifs);
wil_update_net_queues_bh(wil, vif, NULL, false);
out: out:
if (rc) { if (rc) {
wil->sta[evt->cid].status = wil_sta_unused; wil->sta[evt->cid].status = wil_sta_unused;
wil->sta[evt->cid].mid = U8_MAX; wil->sta[evt->cid].mid = U8_MAX;
} }
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_vif_fwconnecting, vif->status);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment