Commit 3ada9314 authored by Lior David's avatar Lior David Committed by Kalle Valo

wil6210: multiple VIFs support for start/stop AP

Add support for multiple VIFs in the cfg80211 operations start_ap,
stop_ap and change_beacon. This change allows starting multiple APs
using virtual interfaces.
The data path and most other operations are still working only
on the main interface.
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 4aebd3bd
...@@ -544,8 +544,9 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, ...@@ -544,8 +544,9 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name,
return ERR_PTR(rc); return ERR_PTR(rc);
} }
int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif) int wil_vif_prepare_stop(struct wil6210_vif *vif)
{ {
struct wil6210_priv *wil = vif_to_wil(vif);
struct wireless_dev *wdev = vif_to_wdev(vif); struct wireless_dev *wdev = vif_to_wdev(vif);
struct net_device *ndev; struct net_device *ndev;
int rc; int rc;
...@@ -561,6 +562,7 @@ int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif) ...@@ -561,6 +562,7 @@ int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif)
rc); rc);
/* continue */ /* continue */
} }
wil_bcast_fini(vif);
netif_carrier_off(ndev); netif_carrier_off(ndev);
} }
...@@ -593,7 +595,7 @@ static int wil_cfg80211_del_iface(struct wiphy *wiphy, ...@@ -593,7 +595,7 @@ static int wil_cfg80211_del_iface(struct wiphy *wiphy,
return -EINVAL; return -EINVAL;
} }
rc = wil_vif_prepare_stop(wil, vif); rc = wil_vif_prepare_stop(vif);
if (rc) if (rc)
goto out; goto out;
...@@ -614,6 +616,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, ...@@ -614,6 +616,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wireless_dev *wdev = vif_to_wdev(vif); struct wireless_dev *wdev = vif_to_wdev(vif);
int rc; int rc;
bool fw_reset = false;
wil_dbg_misc(wil, "change_iface: type=%d\n", type); wil_dbg_misc(wil, "change_iface: type=%d\n", type);
...@@ -628,7 +631,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, ...@@ -628,7 +631,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
/* do not reset FW when there are active VIFs, /* do not reset FW when there are active VIFs,
* because it can cause significant disruption * because it can cause significant disruption
*/ */
if (!wil_has_other_up_ifaces(wil, ndev) && if (!wil_has_other_active_ifaces(wil, ndev, true, false) &&
netif_running(ndev) && !wil_is_recovery_blocked(wil)) { netif_running(ndev) && !wil_is_recovery_blocked(wil)) {
wil_dbg_misc(wil, "interface is up. resetting...\n"); wil_dbg_misc(wil, "interface is up. resetting...\n");
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
...@@ -638,6 +641,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, ...@@ -638,6 +641,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
if (rc) if (rc)
return rc; return rc;
fw_reset = true;
} }
switch (type) { switch (type) {
...@@ -654,8 +658,9 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, ...@@ -654,8 +658,9 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (vif->mid != 0 && wil_has_up_ifaces(wil)) { if (vif->mid != 0 && wil_has_active_ifaces(wil, true, false)) {
wil_vif_prepare_stop(wil, vif); if (!fw_reset)
wil_vif_prepare_stop(vif);
rc = wmi_port_delete(wil, vif->mid); rc = wmi_port_delete(wil, vif->mid);
if (rc) if (rc)
return rc; return rc;
...@@ -1530,10 +1535,12 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, ...@@ -1530,10 +1535,12 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
__wil_down(wil); if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
rc = __wil_up(wil); __wil_down(wil);
if (rc) rc = __wil_up(wil);
goto out; if (rc)
goto out;
}
rc = wmi_set_ssid(vif, ssid_len, ssid); rc = wmi_set_ssid(vif, ssid_len, ssid);
if (rc) if (rc)
...@@ -1549,7 +1556,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, ...@@ -1549,7 +1556,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
vif->pbss = pbss; vif->pbss = pbss;
netif_carrier_on(ndev); netif_carrier_on(ndev);
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); if (!wil_has_other_active_ifaces(wil, ndev, false, true))
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go); rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go);
if (rc) if (rc)
...@@ -1565,7 +1573,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, ...@@ -1565,7 +1573,8 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
wmi_pcp_stop(vif); wmi_pcp_stop(vif);
err_pcp_start: err_pcp_start:
netif_carrier_off(ndev); netif_carrier_off(ndev);
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); if (!wil_has_other_active_ifaces(wil, ndev, false, true))
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
out: out:
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
return rc; return rc;
...@@ -1670,20 +1679,26 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, ...@@ -1670,20 +1679,26 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
{ {
struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_vif *vif = ndev_to_vif(ndev);
bool last;
wil_dbg_misc(wil, "stop_ap\n"); wil_dbg_misc(wil, "stop_ap, mid=%d\n", vif->mid);
netif_carrier_off(ndev); netif_carrier_off(ndev);
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); last = !wil_has_other_active_ifaces(wil, ndev, false, true);
wil_set_recovery_state(wil, fw_recovery_idle); if (last) {
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
set_bit(wil_status_resetting, wil->status); wil_set_recovery_state(wil, fw_recovery_idle);
set_bit(wil_status_resetting, wil->status);
}
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
wmi_pcp_stop(vif); wmi_pcp_stop(vif);
__wil_down(wil); if (last)
__wil_down(wil);
else
wil_bcast_fini(vif);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
......
...@@ -508,6 +508,18 @@ void wil_bcast_fini(struct wil6210_vif *vif) ...@@ -508,6 +508,18 @@ void wil_bcast_fini(struct wil6210_vif *vif)
wil_vring_fini_tx(wil, ri); wil_vring_fini_tx(wil, ri);
} }
void wil_bcast_fini_all(struct wil6210_priv *wil)
{
int i;
struct wil6210_vif *vif;
for (i = 0; i < wil->max_vifs; i++) {
vif = wil->vifs[i];
if (vif)
wil_bcast_fini(vif);
}
}
int wil_priv_init(struct wil6210_priv *wil) int wil_priv_init(struct wil6210_priv *wil)
{ {
uint i; uint i;
...@@ -1204,7 +1216,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1204,7 +1216,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
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(vif); 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);
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#include "wil6210.h" #include "wil6210.h"
#include "txrx.h" #include "txrx.h"
bool wil_has_other_up_ifaces(struct wil6210_priv *wil, bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
struct net_device *ndev) struct net_device *ndev, bool up, bool ok)
{ {
int i; int i;
struct wil6210_vif *vif; struct wil6210_vif *vif;
...@@ -31,17 +31,19 @@ bool wil_has_other_up_ifaces(struct wil6210_priv *wil, ...@@ -31,17 +31,19 @@ bool wil_has_other_up_ifaces(struct wil6210_priv *wil,
vif = wil->vifs[i]; vif = wil->vifs[i];
if (vif) { if (vif) {
ndev_i = vif_to_ndev(vif); ndev_i = vif_to_ndev(vif);
if (ndev_i != ndev && ndev_i->flags & IFF_UP) if (ndev_i != ndev)
return true; if ((up && (ndev_i->flags & IFF_UP)) ||
(ok && netif_carrier_ok(ndev_i)))
return true;
} }
} }
return false; return false;
} }
bool wil_has_up_ifaces(struct wil6210_priv *wil) bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
{ {
return wil_has_other_up_ifaces(wil, NULL); return wil_has_other_active_ifaces(wil, NULL, up, ok);
} }
static int wil_open(struct net_device *ndev) static int wil_open(struct net_device *ndev)
...@@ -57,7 +59,7 @@ static int wil_open(struct net_device *ndev) ...@@ -57,7 +59,7 @@ static int wil_open(struct net_device *ndev)
return -EINVAL; return -EINVAL;
} }
if (!wil_has_other_up_ifaces(wil, ndev)) { if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
wil_dbg_misc(wil, "open, first iface\n"); wil_dbg_misc(wil, "open, first iface\n");
rc = wil_pm_runtime_get(wil); rc = wil_pm_runtime_get(wil);
if (rc < 0) if (rc < 0)
...@@ -78,7 +80,7 @@ static int wil_stop(struct net_device *ndev) ...@@ -78,7 +80,7 @@ static int wil_stop(struct net_device *ndev)
wil_dbg_misc(wil, "stop\n"); wil_dbg_misc(wil, "stop\n");
if (!wil_has_other_up_ifaces(wil, ndev)) { if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
wil_dbg_misc(wil, "stop, last iface\n"); wil_dbg_misc(wil, "stop, last iface\n");
rc = wil_down(wil); rc = wil_down(wil);
if (!rc) if (!rc)
...@@ -359,7 +361,7 @@ int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif) ...@@ -359,7 +361,7 @@ int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif)
{ {
struct net_device *ndev = vif_to_ndev(vif); struct net_device *ndev = vif_to_ndev(vif);
struct wireless_dev *wdev = vif_to_wdev(vif); struct wireless_dev *wdev = vif_to_wdev(vif);
bool any_active = wil_has_up_ifaces(wil); bool any_active = wil_has_active_ifaces(wil, true, false);
int rc; int rc;
ASSERT_RTNL(); ASSERT_RTNL();
...@@ -428,7 +430,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid) ...@@ -428,7 +430,7 @@ void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
{ {
struct wil6210_vif *vif; struct wil6210_vif *vif;
struct net_device *ndev; struct net_device *ndev;
bool any_active = wil_has_up_ifaces(wil); bool any_active = wil_has_active_ifaces(wil, true, false);
ASSERT_RTNL(); ASSERT_RTNL();
if (mid >= wil->max_vifs) { if (mid >= wil->max_vifs) {
......
...@@ -145,7 +145,7 @@ static void wil_remove_all_additional_vifs(struct wil6210_priv *wil) ...@@ -145,7 +145,7 @@ static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
for (i = 1; i < wil->max_vifs; i++) { for (i = 1; i < wil->max_vifs; i++) {
vif = wil->vifs[i]; vif = wil->vifs[i];
if (vif) { if (vif) {
wil_vif_prepare_stop(wil, vif); wil_vif_prepare_stop(vif);
wil_vif_remove(wil, vif->mid); wil_vif_remove(wil, vif->mid);
} }
} }
......
...@@ -944,9 +944,9 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name, ...@@ -944,9 +944,9 @@ wil_vif_alloc(struct wil6210_priv *wil, const char *name,
unsigned char name_assign_type, enum nl80211_iftype iftype); unsigned char name_assign_type, enum nl80211_iftype iftype);
void wil_vif_free(struct wil6210_vif *vif); void wil_vif_free(struct wil6210_vif *vif);
void *wil_if_alloc(struct device *dev); void *wil_if_alloc(struct device *dev);
bool wil_has_other_up_ifaces(struct wil6210_priv *wil, bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
struct net_device *ndev); struct net_device *ndev, bool up, bool ok);
bool wil_has_up_ifaces(struct wil6210_priv *wil); bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok);
void wil_if_free(struct wil6210_priv *wil); void wil_if_free(struct wil6210_priv *wil);
int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif); int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif);
int wil_if_add(struct wil6210_priv *wil); int wil_if_add(struct wil6210_priv *wil);
...@@ -1053,7 +1053,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, ...@@ -1053,7 +1053,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
int wil_cfg80211_iface_combinations_from_fw( int wil_cfg80211_iface_combinations_from_fw(
struct wil6210_priv *wil, struct wil6210_priv *wil,
const struct wil_fw_record_concurrency *conc); const struct wil_fw_record_concurrency *conc);
int wil_vif_prepare_stop(struct wil6210_priv *wil, struct wil6210_vif *vif); int wil_vif_prepare_stop(struct wil6210_vif *vif);
#if defined(CONFIG_WIL6210_DEBUGFS) #if defined(CONFIG_WIL6210_DEBUGFS)
int wil6210_debugfs_init(struct wil6210_priv *wil); int wil6210_debugfs_init(struct wil6210_priv *wil);
...@@ -1095,6 +1095,7 @@ int wil_tx_init(struct wil6210_vif *vif, int cid); ...@@ -1095,6 +1095,7 @@ int wil_tx_init(struct wil6210_vif *vif, int cid);
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size); int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
int wil_bcast_init(struct wil6210_vif *vif); 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_update_net_queues(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
bool should_stop); bool should_stop);
......
...@@ -341,6 +341,10 @@ static const char *cmdid2name(u16 cmdid) ...@@ -341,6 +341,10 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_GET_PCP_CHANNEL_CMD"; return "WMI_GET_PCP_CHANNEL_CMD";
case WMI_P2P_CFG_CMDID: case WMI_P2P_CFG_CMDID:
return "WMI_P2P_CFG_CMD"; return "WMI_P2P_CFG_CMD";
case WMI_PORT_ALLOCATE_CMDID:
return "WMI_PORT_ALLOCATE_CMD";
case WMI_PORT_DELETE_CMDID:
return "WMI_PORT_DELETE_CMD";
case WMI_START_LISTEN_CMDID: case WMI_START_LISTEN_CMDID:
return "WMI_START_LISTEN_CMD"; return "WMI_START_LISTEN_CMD";
case WMI_START_SEARCH_CMDID: case WMI_START_SEARCH_CMDID:
...@@ -479,6 +483,10 @@ static const char *eventid2name(u16 eventid) ...@@ -479,6 +483,10 @@ static const char *eventid2name(u16 eventid)
return "WMI_GET_PCP_CHANNEL_EVENT"; return "WMI_GET_PCP_CHANNEL_EVENT";
case WMI_P2P_CFG_DONE_EVENTID: case WMI_P2P_CFG_DONE_EVENTID:
return "WMI_P2P_CFG_DONE_EVENT"; return "WMI_P2P_CFG_DONE_EVENT";
case WMI_PORT_ALLOCATED_EVENTID:
return "WMI_PORT_ALLOCATED_EVENT";
case WMI_PORT_DELETED_EVENTID:
return "WMI_PORT_DELETED_EVENT";
case WMI_LISTEN_STARTED_EVENTID: case WMI_LISTEN_STARTED_EVENTID:
return "WMI_LISTEN_STARTED_EVENT"; return "WMI_LISTEN_STARTED_EVENT";
case WMI_SEARCH_STARTED_EVENTID: case WMI_SEARCH_STARTED_EVENTID:
......
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