From 93192408781150af7e10a1d0970b9497940579dc Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 24 Aug 2010 02:44:50 +0200 Subject: [PATCH] carl9170 firmware: revamp Content After Beacon handling Commit "carl9170 firmware: Support multiple CAB queues" introduced a regression. The CAB queue was drained too early and therefore the bc/mc buffered frames were sent out at the wrong dtim period. This patch takes care of the stated regression, but it also fixes yet another, this time a more theoretical race in multi AP mode. Signed-off-by: Christian Lamparter --- carlfw/include/carl9170.h | 9 +++--- carlfw/src/cmd.c | 3 +- carlfw/src/wlan.c | 67 +++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 30 deletions(-) diff --git a/carlfw/include/carl9170.h b/carlfw/include/carl9170.h index 6b19303..2ae4f63 100644 --- a/carlfw/include/carl9170.h +++ b/carlfw/include/carl9170.h @@ -45,8 +45,9 @@ struct carl9170_bar_ctx { #ifdef CONFIG_CARL9170FW_CAB_QUEUE enum carl9170_cab_trigger { CARL9170_CAB_TRIGGER_EMPTY = 0, - CARL9170_CAB_TRIGGER_ARMED = BIT(0), - CARL9170_CAB_TRIGGER_DEFER = BIT(1), + CARL9170_CAB_TRIGGER_READY = BIT(0), + CARL9170_CAB_TRIGGER_ARMED = BIT(1), + CARL9170_CAB_TRIGGER_DEFER = BIT(2), }; #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ @@ -105,8 +106,8 @@ struct firmware_context_struct { /* CAB */ struct dma_queue cab_queue[CARL9170_INTF_NUM]; unsigned int cab_queue_len[CARL9170_INTF_NUM]; - unsigned int cab_flush_time, cab_flush_vif; - enum carl9170_cab_trigger cab_flush_trigger; + unsigned int cab_flush_time; + enum carl9170_cab_trigger cab_flush_trigger[CARL9170_INTF_NUM]; #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ /* tx status */ diff --git a/carlfw/src/cmd.c b/carlfw/src/cmd.c index 281ae9c..5cfd870 100644 --- a/carlfw/src/cmd.c +++ b/carlfw/src/cmd.c @@ -90,8 +90,7 @@ void handle_cmd(struct carl9170_rsp *resp) set(AR9170_MAC_REG_BCN_CTRL, AR9170_BCN_CTRL_READY); } else { wlan_cab_flush_queue(cmd->cab_flush.vif_id); - if (fw.wlan.cab_flush_vif == cmd->cab_flush.vif_id) - fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_EMPTY; + fw.wlan.cab_flush_trigger[i] = CARL9170_CAB_TRIGGER_EMPTY; } break; #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ diff --git a/carlfw/src/wlan.c b/carlfw/src/wlan.c index cd169ff..de13dbf 100644 --- a/carlfw/src/wlan.c +++ b/carlfw/src/wlan.c @@ -659,19 +659,18 @@ void wlan_cab_modify_dtim_beacon(const unsigned int vif) _ie = beacon_find_ie(WLAN_EID_TIM); if (likely(_ie)) { ie = (struct ieee80211_tim_ie *) &_ie[2]; - fw.wlan.cab_flush_vif = vif; if (!queue_empty(&fw.wlan.cab_queue[vif]) && (ie->dtim_count == 0)) { /* schedule DTIM transfer */ - fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_ARMED; - } else if ((fw.wlan.cab_queue_len[vif] == 0) && (fw.wlan.cab_flush_trigger)) { + fw.wlan.cab_flush_trigger[vif] = CARL9170_CAB_TRIGGER_ARMED; + } else if ((fw.wlan.cab_queue_len[vif] == 0) && (fw.wlan.cab_flush_trigger[vif])) { /* undo all chances to the beacon structure */ ie->bitmap_ctrl &= ~0x1; - fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_EMPTY; + fw.wlan.cab_flush_trigger[vif] = CARL9170_CAB_TRIGGER_EMPTY; } - /* Triggered by CARL9170_CAB_TRIGGER_ARMED || CARL9170_CAB_TRIGGER_DEFER */ - if (fw.wlan.cab_flush_trigger) { + /* Triggered by CARL9170_CAB_TRIGGER_ARMED || CARL9170_CAB_TRIGGER_READY || CARL9170_CAB_TRIGGER_DEFER */ + if (fw.wlan.cab_flush_trigger[vif]) { /* Set the almighty Multicast Traffic Indication Bit. */ ie->bitmap_ctrl |= 0x1; } @@ -691,6 +690,21 @@ static void handle_beacon_config(void) static void handle_pretbtt(void) { #ifdef CONFIG_CARL9170FW_CAB_QUEUE +#if CARL9170_INTF_NUM != 2 + /* GCC BUG ? */ + unsigned int i; + + for (i = 0; i < CARL9170_INTF_NUM; i++) { + if (unlikely(fw.wlan.cab_flush_trigger[i] == CARL9170_CAB_TRIGGER_ARMED)) + fw.wlan.cab_flush_trigger[i] = CARL9170_CAB_TRIGGER_READY; + } +#else + if (unlikely(fw.wlan.cab_flush_trigger[0] == CARL9170_CAB_TRIGGER_ARMED)) + fw.wlan.cab_flush_trigger[0] = CARL9170_CAB_TRIGGER_READY; + if (unlikely(fw.wlan.cab_flush_trigger[1] == CARL9170_CAB_TRIGGER_ARMED)) + fw.wlan.cab_flush_trigger[1] = CARL9170_CAB_TRIGGER_READY; +#endif + fw.wlan.cab_flush_time = get_clock_counter(); #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ @@ -728,28 +742,33 @@ static void handle_radar(void) static void wlan_janitor(void) { #ifdef CONFIG_CARL9170FW_CAB_QUEUE - if (unlikely(fw.wlan.cab_flush_trigger == CARL9170_CAB_TRIGGER_ARMED)) { - /* - * This is hardcoded into carl9170usb driver. - * - * The driver must set the PRETBTT event to beacon_interval - - * CARL9170_PRETBTT_KUS (usually 6) Kus. - * - * But still, we can only do so much about 802.11-2007 9.3.2.1 & - * 11.2.1.6. Let's hope the current solution is adequate enough. - */ - - if (is_after_msecs(fw.wlan.cab_flush_time, (CARL9170_TBTT_DELTA))) { - wlan_cab_flush_queue(fw.wlan.cab_flush_vif); + unsigned int i; + for (i = 0; i < CARL9170_INTF_NUM; i++) { + if (unlikely(fw.wlan.cab_flush_trigger[i] == CARL9170_CAB_TRIGGER_READY)) { /* - * This prevents the code from sending new BC/MC frames - * which were queued after the previous buffered traffic - * has been sent out... They will have to wait until the - * next DTIM beacon comes along. + * This is hardcoded into carl9170usb driver. + * + * The driver must set the PRETBTT event to beacon_interval - + * CARL9170_PRETBTT_KUS (usually 6) Kus. + * + * But still, we can only do so much about 802.11-2007 9.3.2.1 & + * 11.2.1.6. Let's hope the current solution is adequate enough. */ - fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_DEFER; + + if (is_after_msecs(fw.wlan.cab_flush_time, (CARL9170_TBTT_DELTA))) { + wlan_cab_flush_queue(i); + + /* + * This prevents the code from sending new BC/MC frames + * which were queued after the previous buffered traffic + * has been sent out... They will have to wait until the + * next DTIM beacon comes along. + */ + fw.wlan.cab_flush_trigger[i] = CARL9170_CAB_TRIGGER_DEFER; + } } + } #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ -- 2.31.1