wil6210: prevent double disconnect command issuing
authorVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Tue, 28 Oct 2014 14:50:08 +0000 (16:50 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 30 Oct 2014 19:26:50 +0000 (15:26 -0400)
Disconnect flow may be invoked either from upper layer request,
or from event reported by the firmware.

In case of firmware event, driver need to release resources for the station but
not send another disconnect WMI command.

In case of upper layer request, WMI_DISCONNECT_STA_CMDID command need to
be issued for the firmware to perform disconnect on the MAC layer. Eventually,
event is expected to confirm MAC disconnect, but it is better to not wait for
firmware event and release station resources immediately. FW may fail to
report disconnect for various reasons, so one could not rely on event always reported.

Introduce parameter to distinguish 2 cases above to prevent double WMI command
issuing.

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c

index d9f4b30dd343b01e1d58ac8c9deadbb246a82abd..4248fb3352d2f2dc4420101e8174b5e38d6b7752 100644 (file)
@@ -797,7 +797,7 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, mac);
+       wil6210_disconnect(wil, mac, false);
        mutex_unlock(&wil->mutex);
 
        return 0;
index 0e95557e177f89c6dd65e5575cf3be51939cd918..b3a84ae04ce39e93962291809d3ecbca3188c387 100644 (file)
@@ -74,7 +74,8 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
                __raw_writel(*s++, d++);
 }
 
-static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
+static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
+                              bool from_event)
 {
        uint i;
        struct net_device *ndev = wil_to_ndev(wil);
@@ -86,7 +87,10 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
 
        sta->data_port_open = false;
        if (sta->status != wil_sta_unused) {
-               wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
+               if (!from_event)
+                       wmi_disconnect_sta(wil, sta->addr,
+                                          WLAN_REASON_DEAUTH_LEAVING);
+
                switch (wdev->iftype) {
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_P2P_GO:
@@ -118,7 +122,8 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
        memset(&sta->stats, 0, sizeof(sta->stats));
 }
 
-static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
+static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+                               bool from_event)
 {
        int cid = -ENOENT;
        struct net_device *ndev = wil_to_ndev(wil);
@@ -133,10 +138,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
        }
 
        if (cid >= 0) /* disconnect 1 peer */
-               wil_disconnect_cid(wil, cid);
+               wil_disconnect_cid(wil, cid, from_event);
        else /* disconnect all */
                for (cid = 0; cid < WIL6210_MAX_CID; cid++)
-                       wil_disconnect_cid(wil, cid);
+                       wil_disconnect_cid(wil, cid, from_event);
 
        /* link state */
        switch (wdev->iftype) {
@@ -166,7 +171,7 @@ static void wil_disconnect_worker(struct work_struct *work)
                        struct wil6210_priv, disconnect_worker);
 
        mutex_lock(&wil->mutex);
-       _wil6210_disconnect(wil, NULL);
+       _wil6210_disconnect(wil, NULL, false);
        mutex_unlock(&wil->mutex);
 }
 
@@ -351,12 +356,22 @@ int wil_priv_init(struct wil6210_priv *wil)
        return 0;
 }
 
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
+/**
+ * wil6210_disconnect - disconnect one connection
+ * @wil: driver context
+ * @bssid: peer to disconnect, NULL to disconnect all
+ * @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.
+ */
+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+                       bool from_event)
 {
        wil_dbg_misc(wil, "%s()\n", __func__);
 
        del_timer_sync(&wil->connect_timer);
-       _wil6210_disconnect(wil, bssid);
+       _wil6210_disconnect(wil, bssid, from_event);
 }
 
 void wil_priv_deinit(struct wil6210_priv *wil)
@@ -368,7 +383,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
        cancel_work_sync(&wil->disconnect_worker);
        cancel_work_sync(&wil->fw_error_worker);
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, NULL);
+       wil6210_disconnect(wil, NULL, false);
        mutex_unlock(&wil->mutex);
        wmi_event_flush(wil);
        destroy_workqueue(wil->wmi_wq_conn);
@@ -553,7 +568,7 @@ int wil_reset(struct wil6210_priv *wil)
        WARN_ON(test_bit(wil_status_napi_en, &wil->status));
 
        cancel_work_sync(&wil->disconnect_worker);
-       wil6210_disconnect(wil, NULL);
+       wil6210_disconnect(wil, NULL, false);
 
        wil->status = 0; /* prevent NAPI from being scheduled */
 
index 18f8729a6b2c3c9fed7a370e4617cbf98dbe5360..3674e2732192a758af8c817c00fa08f51dc7a296 100644 (file)
@@ -584,7 +584,8 @@ void wil_wdev_free(struct wil6210_priv *wil);
 int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
 int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
 int wmi_pcp_stop(struct wil6210_priv *wil);
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid);
+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+                       bool from_event);
 
 int wil_rx_init(struct wil6210_priv *wil);
 void wil_rx_fini(struct wil6210_priv *wil);
index 4311df982c6074cf54e2fe43a8971f4aa355725e..9661fa1501676a8a763221b9d8a3dfcc75d03c40 100644 (file)
@@ -486,7 +486,7 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
        wil->sinfo_gen++;
 
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, evt->bssid);
+       wil6210_disconnect(wil, evt->bssid, true);
        mutex_unlock(&wil->mutex);
 }