wl12xx: make event handling support multirole
authorEliad Peller <eliad@wizery.com>
Mon, 10 Oct 2011 08:12:57 +0000 (10:12 +0200)
committerLuciano Coelho <coelho@ti.com>
Tue, 11 Oct 2011 12:04:23 +0000 (15:04 +0300)
Some events don't indicate the role they are intended for.
In these cases, iterate through all the relevant vifs,
and pass the event to each one of them.

This is only a workaround. future fw releases should indicate
the relevant role_id for such events.

Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/wl12xx.h

index 486c8ee0101abeb8c6f7bc06cc56f29d4245f504..dbc40bb49bcd9f97dbc9f7901c86530a49d077b6 100644 (file)
@@ -162,10 +162,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 }
 
 static void wl1271_event_rssi_trigger(struct wl1271 *wl,
-                                     struct ieee80211_vif *vif,
+                                     struct wl12xx_vif *wlvif,
                                      struct event_mailbox *mbox)
 {
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
        enum nl80211_cqm_rssi_threshold_event event;
        s8 metric = mbox->rssi_snr_trigger_metric[0];
 
@@ -183,11 +183,13 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl,
 
 static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 {
+       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
        if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
                if (!wlvif->sta.ba_rx_bitmap)
                        return;
-               ieee80211_stop_rx_ba_session(wl->vif, wlvif->sta.ba_rx_bitmap,
-                                            wl->vif->bss_conf.bssid);
+               ieee80211_stop_rx_ba_session(vif, wlvif->sta.ba_rx_bitmap,
+                                            vif->bss_conf.bssid);
        } else {
                u8 hlid;
                struct wl1271_link *lnk;
@@ -197,7 +199,7 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
                        if (!lnk->ba_bitmap)
                                continue;
 
-                       ieee80211_stop_rx_ba_session(wl->vif,
+                       ieee80211_stop_rx_ba_session(vif,
                                                     lnk->ba_bitmap,
                                                     lnk->addr);
                }
@@ -207,12 +209,21 @@ static void wl1271_stop_ba_event(struct wl1271 *wl, struct wl12xx_vif *wlvif)
 static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
                                               u8 enable)
 {
+       struct ieee80211_vif *vif;
+       struct wl12xx_vif *wlvif;
+
        if (enable) {
                /* disable dynamic PS when requested by the firmware */
-               ieee80211_disable_dyn_ps(wl->vif);
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       vif = wl12xx_wlvif_to_vif(wlvif);
+                       ieee80211_disable_dyn_ps(vif);
+               }
                set_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
        } else {
-               ieee80211_enable_dyn_ps(wl->vif);
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       vif = wl12xx_wlvif_to_vif(wlvif);
+                       ieee80211_enable_dyn_ps(vif);
+               }
                clear_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags);
                wl1271_recalc_rx_streaming(wl);
        }
@@ -228,12 +239,11 @@ static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
 
 static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
 {
-       struct ieee80211_vif *vif = wl->vif; /* TODO: get as param */
-       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+       struct ieee80211_vif *vif;
+       struct wl12xx_vif *wlvif;
        int ret;
        u32 vector;
        bool beacon_loss = false;
-       bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
        bool disconnect_sta = false;
        unsigned long sta_bitmap = 0;
 
@@ -266,8 +276,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                }
        }
 
-       if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
-           wlvif->bss_type == BSS_TYPE_STA_BSS)
+       if (vector & SOFT_GEMINI_SENSE_EVENT_ID)
                wl12xx_event_soft_gemini_sense(wl,
                                               mbox->soft_gemini_sense_info);
 
@@ -280,40 +289,54 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
         * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
         *
         */
-       if ((vector & BSS_LOSE_EVENT_ID) && !is_ap) {
+       if (vector & BSS_LOSE_EVENT_ID) {
+               /* TODO: check for multi-role */
                wl1271_info("Beacon loss detected.");
 
                /* indicate to the stack, that beacons have been lost */
                beacon_loss = true;
        }
 
-       if ((vector & PS_REPORT_EVENT_ID) && !is_ap) {
+       if (vector & PS_REPORT_EVENT_ID) {
                wl1271_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
-               ret = wl1271_event_ps_report(wl, wlvif, mbox, &beacon_loss);
-               if (ret < 0)
-                       return ret;
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       ret = wl1271_event_ps_report(wl, wlvif,
+                                                    mbox, &beacon_loss);
+                       if (ret < 0)
+                               return ret;
+               }
        }
 
-       if ((vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID) && !is_ap)
-               wl1271_event_pspoll_delivery_fail(wl, wlvif);
+       if (vector & PSPOLL_DELIVERY_FAILURE_EVENT_ID)
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       wl1271_event_pspoll_delivery_fail(wl, wlvif);
+               }
 
        if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
+               /* TODO: check actual multi-role support */
                wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
-               if (wl->vif)
-                       wl1271_event_rssi_trigger(wl, vif, mbox);
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       wl1271_event_rssi_trigger(wl, wlvif, mbox);
+               }
        }
 
-       if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
+       if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) {
+               u8 role_id = mbox->role_id;
                wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
-                            "ba_allowed = 0x%x", mbox->rx_ba_allowed);
+                            "ba_allowed = 0x%x, role_id=%d",
+                            mbox->rx_ba_allowed, role_id);
 
-               wlvif->ba_allowed = !!mbox->rx_ba_allowed;
+               wl12xx_for_each_wlvif(wl, wlvif) {
+                       if (role_id != 0xff && role_id != wlvif->role_id)
+                               continue;
 
-               if (wl->vif && !wlvif->ba_allowed)
-                       wl1271_stop_ba_event(wl, wlvif);
+                       wlvif->ba_allowed = !!mbox->rx_ba_allowed;
+                       if (!wlvif->ba_allowed)
+                               wl1271_stop_ba_event(wl, wlvif);
+               }
        }
 
-       if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) {
+       if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) {
                wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. "
                                          "status = 0x%x",
                                          mbox->channel_switch_status);
@@ -322,48 +345,63 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                 * 1) channel switch complete with status=0
                 * 2) channel switch failed status=1
                 */
-               if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) &&
-                   (wl->vif))
-                       ieee80211_chswitch_done(wl->vif,
-                               mbox->channel_switch_status ? false : true);
+               if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) {
+                       /* TODO: configure only the relevant vif */
+                       wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                               struct ieee80211_vif *vif =
+                                       wl12xx_wlvif_to_vif(wlvif);
+                               bool success = mbox->channel_switch_status ?
+                                       false : true;
+
+                               ieee80211_chswitch_done(vif, success);
+                       }
+               }
        }
 
        if ((vector & DUMMY_PACKET_EVENT_ID)) {
                wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
-               if (wl->vif)
-                       wl1271_tx_dummy_packet(wl);
+               wl1271_tx_dummy_packet(wl);
        }
 
        /*
         * "TX retries exceeded" has a different meaning according to mode.
         * In AP mode the offending station is disconnected.
         */
-       if ((vector & MAX_TX_RETRY_EVENT_ID) && is_ap) {
+       if (vector & MAX_TX_RETRY_EVENT_ID) {
                wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
                sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
                disconnect_sta = true;
        }
 
-       if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
+       if (vector & INACTIVE_STA_EVENT_ID) {
                wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
                sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
                disconnect_sta = true;
        }
 
-       if (is_ap && disconnect_sta) {
+       if (disconnect_sta) {
                u32 num_packets = wl->conf.tx.max_tx_retries;
                struct ieee80211_sta *sta;
                const u8 *addr;
                int h;
 
                for_each_set_bit(h, &sta_bitmap, WL12XX_MAX_LINKS) {
-                       if (!test_bit(h, wlvif->ap.sta_hlid_map))
+                       bool found = false;
+                       /* find the ap vif connected to this sta */
+                       wl12xx_for_each_wlvif_ap(wl, wlvif) {
+                               if (!test_bit(h, wlvif->ap.sta_hlid_map))
+                                       continue;
+                               found = true;
+                               break;
+                       }
+                       if (!found)
                                continue;
 
+                       vif = wl12xx_wlvif_to_vif(wlvif);
                        addr = wl->links[h].addr;
 
                        rcu_read_lock();
-                       sta = ieee80211_find_sta(wl->vif, addr);
+                       sta = ieee80211_find_sta(vif, addr);
                        if (sta) {
                                wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
                                ieee80211_report_low_ack(sta, num_packets);
@@ -372,8 +410,11 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                }
        }
 
-       if (wl->vif && beacon_loss)
-               ieee80211_connection_loss(wl->vif);
+       if (beacon_loss)
+               wl12xx_for_each_wlvif_sta(wl, wlvif) {
+                       vif = wl12xx_wlvif_to_vif(wlvif);
+                       ieee80211_connection_loss(vif);
+               }
 
        return 0;
 }
index fd78f8c1ebcc7ac8f07a2db14030137adda410eb..de9a2b639403a2bcaa5fe1cb0255b1313d2b215f 100644 (file)
@@ -661,6 +661,16 @@ struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif)
 #define wl12xx_for_each_wlvif(wl, wlvif) \
                list_for_each_entry(wlvif, &wl->wlvif_list, list)
 
+#define wl12xx_for_each_wlvif_bss_type(wl, wlvif, _bss_type)   \
+               wl12xx_for_each_wlvif(wl, wlvif)                \
+                       if (wlvif->bss_type == _bss_type)
+
+#define wl12xx_for_each_wlvif_sta(wl, wlvif)   \
+               wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_STA_BSS)
+
+#define wl12xx_for_each_wlvif_ap(wl, wlvif)    \
+               wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS)
+
 int wl1271_plt_start(struct wl1271 *wl);
 int wl1271_plt_stop(struct wl1271 *wl);
 int wl1271_recalc_rx_streaming(struct wl1271 *wl);