From: Christian Lamparter Date: Mon, 16 Aug 2010 19:44:31 +0000 (+0200) Subject: carl9170 firmware: Support multiple CAB queues X-Git-Tag: 1.8.6~2 X-Git-Url: https://jxself.org/git/?a=commitdiff_plain;h=65dd584c008fdc28e8398bacfdb311b19ae80507;p=carl9170fw.git carl9170 firmware: Support multiple CAB queues Signed-off-by: Christian Lamparter --- diff --git a/carlfw/Kconfig b/carlfw/Kconfig index c8f3cca..bacb6f2 100644 --- a/carlfw/Kconfig +++ b/carlfw/Kconfig @@ -152,6 +152,12 @@ config CARL9170FW_DELAYED_TX Doesn't work 100% yet, but in most cases other HW designs can deal with the fallout. +config CARL9170FW_VIFS_NUM + default 0 + int + prompt "Number of additional pseudo virtual interfaces" + depends on CARL9170FW_EXPERIMENTAL + config CARL9170FW_BROKEN_FEATURES def_bool n prompt "Broken Featurs" @@ -184,12 +190,6 @@ config CARL9170FW_WATCHDOG_BUTTON depends on CARL9170FW_BROKEN && CARL9170FW_WATCHDOG && CARL9170FW_GPIO_INTERRUPT prompt "Trigger Watchdog by pressing the WPS button" -config CARL9170FW_VIFS_NUM - default 0 - int - prompt "Number of additional pseudo virtual interfaces" - depends on CARL9170FW_BROKEN_FEATURES - choice CARL9170FW_UART_CLOCK prompt "UART Clock" depends on CARL9170FW_DEBUG_UART diff --git a/carlfw/include/carl9170.h b/carlfw/include/carl9170.h index 220f2a1..6b19303 100644 --- a/carlfw/include/carl9170.h +++ b/carlfw/include/carl9170.h @@ -103,9 +103,9 @@ struct firmware_context_struct { #ifdef CONFIG_CARL9170FW_CAB_QUEUE /* CAB */ - struct dma_queue cab_queue; - unsigned int cab_queue_len, - cab_flush_time; + 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; #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ diff --git a/carlfw/include/dma.h b/carlfw/include/dma.h index 9913f3a..91da865 100644 --- a/carlfw/include/dma.h +++ b/carlfw/include/dma.h @@ -58,7 +58,7 @@ struct dma_desc { #endif /* CONFIG_CARL9170FW_DELAYED_TX */ #ifdef CONFIG_CARL9170FW_CAB_QUEUE -#define AR9170_TERMINATOR_NUMBER_CAB 1 +#define AR9170_TERMINATOR_NUMBER_CAB CARL9170_INTF_NUM #else #define AR9170_TERMINATOR_NUMBER_CAB 0 #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ diff --git a/carlfw/include/wl.h b/carlfw/include/wl.h index 47dda50..fa3cb22 100644 --- a/carlfw/include/wl.h +++ b/carlfw/include/wl.h @@ -261,6 +261,9 @@ void wlan_timer(void); void handle_wlan(void); void wlan_tx_stuck(const struct carl9170_cmd *cmd, struct carl9170_rsp *rsp); +void wlan_cab_flush_queue(const unsigned int vif); +void wlan_cab_modify_dtim_beacon(const unsigned int vif); + static inline void __check_wlantx(void) { BUILD_BUG_ON(sizeof(struct carl9170_tx_superdesc) != CARL9170_TX_SUPERDESC_LEN); diff --git a/carlfw/src/cmd.c b/carlfw/src/cmd.c index e04e8da..587a826 100644 --- a/carlfw/src/cmd.c +++ b/carlfw/src/cmd.c @@ -82,9 +82,15 @@ void handle_cmd(struct carl9170_rsp *resp) #ifdef CONFIG_CARL9170FW_CAB_QUEUE case CARL9170_CMD_FLUSH_CAB: resp->hdr.len = 0; - fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_ARMED; - fw.wlan.cab_flush_time = get_clock_counter() + - CARL9170_TBTT_DELTA; + + if (cmd->cab_flush.mode & CARL9170_CAB_FLUSH_CAB_TRIGGER) { + wlan_cab_modify_dtim_beacon(cmd->cab_flush.vif_id); + 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; + } break; #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ diff --git a/carlfw/src/dma.c b/carlfw/src/dma.c index dc4d278..6b40e05 100644 --- a/carlfw/src/dma.c +++ b/carlfw/src/dma.c @@ -82,7 +82,14 @@ void dma_init_descriptors(void) fw.usb.int_desc = &dma_mem.terminator[i++]; #ifdef CONFIG_CARL9170FW_CAB_QUEUE - fw.wlan.cab_queue.head = fw.wlan.cab_queue.terminator = &dma_mem.terminator[i++]; + /* GCC bug ? */ +# if (CARL9170_INTF_NUM != 2) + for (j = 0; j < CARL9170_INTF_NUM; j++) + fw.wlan.cab_queue[j].head = fw.wlan.cab_queue[j].terminator = &dma_mem.terminator[i++]; +#else + fw.wlan.cab_queue[0].head = fw.wlan.cab_queue[0].terminator = &dma_mem.terminator[i++]; + fw.wlan.cab_queue[1].head = fw.wlan.cab_queue[1].terminator = &dma_mem.terminator[i++]; +#endif #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ #ifdef CONFIG_CARL9170FW_HANDLE_BACK_REQ @@ -96,6 +103,8 @@ void dma_init_descriptors(void) fw.wlan.tx_delay[j].head = fw.wlan.tx_delay[j].terminator = &dma_mem.terminator[i++]; #endif /* CONFIG_CARL9170FW_DELAYED_TX */ + BUILD_BUG_ON(AR9170_TERMINATOR_NUMBER != j); + DBG("Blocks:%d [tx:%d, rx:%d] Terminators:%d/%d\n", AR9170_BLOCK_NUMBER, AR9170_TX_BLOCK_NUMBER, AR9170_RX_BLOCK_NUMBER, AR9170_TERMINATOR_NUMBER, i); diff --git a/carlfw/src/wlan.c b/carlfw/src/wlan.c index 279aedd..367dfab 100644 --- a/carlfw/src/wlan.c +++ b/carlfw/src/wlan.c @@ -357,7 +357,7 @@ static bool wlan_tx_status(struct dma_queue *queue, #ifdef CONFIG_CARL9170FW_CAB_QUEUE if (unlikely(super->s.cab)) - fw.wlan.cab_queue_len--; + fw.wlan.cab_queue_len[super->s.vif_id]--; #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ /* recycle freed descriptors */ @@ -407,8 +407,8 @@ void __hot wlan_tx(struct dma_desc *desc) #ifdef CONFIG_CARL9170FW_CAB_QUEUE if (unlikely(super->s.cab)) { - fw.wlan.cab_queue_len++; - dma_put(&fw.wlan.cab_queue, desc); + fw.wlan.cab_queue_len[super->s.vif_id]++; + dma_put(&fw.wlan.cab_queue[super->s.vif_id], desc); return; } #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ @@ -598,6 +598,36 @@ static void handle_rx(void) } #ifdef CONFIG_CARL9170FW_CAB_QUEUE +void wlan_cab_flush_queue(const unsigned int vif) +{ + struct dma_queue *cab_queue = &fw.wlan.cab_queue[vif]; + struct dma_desc *desc; + + /* move queued frames into the main tx queues */ + for_each_desc(desc, cab_queue) { + struct carl9170_tx_superframe *super = get_super(desc); + if (!queue_empty(cab_queue)) { + /* + * Set MOREDATA flag for all, + * but the last queued frame. + * see: 802.11-2007 11.2.1.5 f) + * + * This is actually the reason to why + * we need to prevent the reentry. + */ + + super->f.data.i3e.frame_control |= + cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } else { + super->f.data.i3e.frame_control &= + cpu_to_le16(~IEEE80211_FCTL_MOREDATA); + } + + /* ready to roll! */ + _wlan_tx(desc); + } +} + static uint8_t *beacon_find_ie(uint8_t ie) { struct ieee80211_mgmt *mgmt = getp(AR9170_MAC_REG_BCN_ADDR); @@ -624,60 +654,7 @@ static uint8_t *beacon_find_ie(uint8_t ie) return NULL; } -static void wlan_cab_flush_queue(void) -{ - struct dma_desc *desc; - uint8_t *_ie; - struct ieee80211_tim_ie *ie; - - /* - * 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. - */ - if (unlikely(fw.wlan.cab_flush_trigger == CARL9170_CAB_TRIGGER_DEFER)) - return ; - - _ie = beacon_find_ie(WLAN_EID_TIM); - if (unlikely(!_ie)) - return ; - - ie = (struct ieee80211_tim_ie *) &_ie[2]; - - /* Ideally, check here for == AR9170_CAB_TRIGGER_ARMED */ - if (fw.wlan.cab_flush_trigger) { - /* move queued frames into the main tx queues */ - for_each_desc(desc, &fw.wlan.cab_queue) { - struct carl9170_tx_superframe *super = get_super(desc); - - if (!queue_empty(&fw.wlan.cab_queue)) { - /* - * Set MOREDATA flag for all, - * but the last queued frame. - * see: 802.11-2007 11.2.1.5 f) - * - * This is actually the reason to why - * we need to prevent the reentry. - */ - - super->f.data.i3e.frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } else { - super->f.data.i3e.frame_control &= - cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - } - - /* ready to roll! */ - _wlan_tx(desc); - } - } - - /* Transfer finished - waiting for tx status */ - fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_DEFER; -} - -static void wlan_cab_modify_dtim_beacon(void) +void wlan_cab_modify_dtim_beacon(const unsigned int vif) { uint8_t *_ie; struct ieee80211_tim_ie *ie; @@ -685,16 +662,18 @@ static void wlan_cab_modify_dtim_beacon(void) _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) && (ie->dtim_count == 0)) { + 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 == 0) && (fw.wlan.cab_flush_trigger)) { + } else if ((fw.wlan.cab_queue_len[vif] == 0) && (fw.wlan.cab_flush_trigger)) { /* undo all chances to the beacon structure */ ie->bitmap_ctrl &= ~0x1; fw.wlan.cab_flush_trigger = CARL9170_CAB_TRIGGER_EMPTY; } + /* Triggered by CARL9170_CAB_TRIGGER_ARMED || CARL9170_CAB_TRIGGER_DEFER */ if (fw.wlan.cab_flush_trigger) { /* Set the almighty Multicast Traffic Indication Bit. */ ie->bitmap_ctrl |= 0x1; @@ -707,16 +686,6 @@ static void handle_beacon_config(void) { uint32_t bcn_count; -#ifdef CONFIG_CARL9170FW_CAB_QUEUE - /* - * The application has now updated the relevant beacon data. - * Now it should be the perfect time to apply the DTIM - * multicast information. - */ - - wlan_cab_modify_dtim_beacon(); -#endif /* CONFIG_CARL9170FW_CAB_QUEUE */ - bcn_count = get(AR9170_MAC_REG_BCN_COUNT); send_cmd_to_host(4, CARL9170_RSP_BEACON_CONFIG, 0x00, (uint8_t *) &bcn_count); @@ -736,7 +705,6 @@ static void handle_pretbtt(void) #else send_cmd_to_host(0, CARL9170_RSP_PRETBTT, 0x00, NULL); #endif /* CONFIG_CARL9170FW_PSM */ - } static void handle_atim(void) @@ -763,7 +731,7 @@ static void handle_radar(void) static void wlan_janitor(void) { #ifdef CONFIG_CARL9170FW_CAB_QUEUE - if (unlikely(fw.wlan.cab_flush_trigger)) { + if (unlikely(fw.wlan.cab_flush_trigger == CARL9170_CAB_TRIGGER_ARMED)) { /* * This is hardcoded into carl9170usb driver. * @@ -774,9 +742,16 @@ static void wlan_janitor(void) * 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(); + if (is_after_msecs(fw.wlan.cab_flush_time, (CARL9170_TBTT_DELTA))) { + wlan_cab_flush_queue(fw.wlan.cab_flush_vif); + + /* + * 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 = CARL9170_CAB_TRIGGER_DEFER; } } #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ diff --git a/include/shared/fwcmd.h b/include/shared/fwcmd.h index be62c9c..f1c8f9e 100644 --- a/include/shared/fwcmd.h +++ b/include/shared/fwcmd.h @@ -152,9 +152,13 @@ struct carl9170_psm { #define CARL9170_PSM_SIZE 4 struct carl9170_cab_flush_cmd { - __le32 vif_id; /* currently unused */ + __le32 vif_id; + __le32 mode; } __packed; -#define CARL9170_CAB_FLUSH_CMD_SIZE 4 +#define CARL9170_CAB_FLUSH_CMD_SIZE 8 + +#define CARL9170_CAB_FLUSH_DRAIN 0 +#define CARL9170_CAB_FLUSH_CAB_TRIGGER 1 struct carl9170_cmd_head { union { diff --git a/include/shared/fwdesc.h b/include/shared/fwdesc.h index 86b998b..2bd4320 100644 --- a/include/shared/fwdesc.h +++ b/include/shared/fwdesc.h @@ -92,8 +92,8 @@ struct carl9170fw_desc_head { #define CARL9170FW_DESC_HEAD_SIZE \ (sizeof(struct carl9170fw_desc_head)) -#define CARL9170FW_OTUS_DESC_MIN_VER 4 -#define CARL9170FW_OTUS_DESC_CUR_VER 4 +#define CARL9170FW_OTUS_DESC_MIN_VER 5 +#define CARL9170FW_OTUS_DESC_CUR_VER 5 struct carl9170fw_otus_desc { struct carl9170fw_desc_head head; __le32 feature_set; diff --git a/include/shared/hw.h b/include/shared/hw.h index 1497312..13b7b75 100644 --- a/include/shared/hw.h +++ b/include/shared/hw.h @@ -375,8 +375,8 @@ #define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xd90) #define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xd94) -#define AR9170_BCN_READY 0x01 -#define AR9170_BCN_LOCK 0x02 +#define AR9170_BCN_CTRL_READY 0x01 +#define AR9170_BCN_CTRL_LOCK 0x02 #define AR9170_MAC_REG_BCN_CURR_ADDR (AR9170_MAC_REG_BASE + 0xd98) #define AR9170_MAC_REG_BCN_COUNT (AR9170_MAC_REG_BASE + 0xd9c)