From d496f07eeee98f74d6aba3f7db5671d06864ed52 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 24 Feb 2011 20:47:32 +0100 Subject: [PATCH] carl9170 firmware: integrate TX_AMPDU & DELAYED_TX This patch fixes a few outstanding issues with the two options and integrates the features into the default build. Signed-off-by: Christian Lamparter --- carlfw/Kconfig | 18 --------- carlfw/include/carl9170.h | 13 ++----- carlfw/include/dma.h | 13 ++----- carlfw/include/wl.h | 14 +------ carlfw/src/dma.c | 8 +--- carlfw/src/hostif.c | 2 +- carlfw/src/wlan.c | 78 ++++++++++++++++++++------------------- 7 files changed, 50 insertions(+), 96 deletions(-) diff --git a/carlfw/Kconfig b/carlfw/Kconfig index 4386ddb..3b7de61 100644 --- a/carlfw/Kconfig +++ b/carlfw/Kconfig @@ -133,24 +133,6 @@ config CARL9170FW_PSM Firmware will automatically turn it on again, when the PRETBTT event fires. -config CARL9170FW_DELAYED_TX - def_bool n - prompt "Delay and reorder TX" - depends on CARL9170FW_EXPERIMENTAL - ---help--- - Delay incoming TX' from the application until wlan_complete - has finished. - - This feature is necessary to keep A-MPDUs partially ordered. - - Doesn't work 100% yet, but in most cases other HW designs can - deal with the fallout. - -config CARL9170FW_TX_AMPDU - def_bool n - prompt "Firmware-supported ampdu scheduling" - depends on CARL9170FW_EXPERIMENTAL - config CARL9170FW_WOL_OPTION def_bool n prompt "Wakeup on WLAN" diff --git a/carlfw/include/carl9170.h b/carlfw/include/carl9170.h index 1a5c6cb..b05d8be 100644 --- a/carlfw/include/carl9170.h +++ b/carlfw/include/carl9170.h @@ -93,13 +93,11 @@ struct firmware_context_struct { struct { /* Hardware DMA queues */ struct dma_queue tx_queue[__AR9170_NUM_TX_QUEUES]; /* wlan tx queue */ + struct dma_queue tx_retry; struct dma_queue rx_queue; /* wlan rx queue */ -#ifdef CONFIG_CARL9170FW_DELAYED_TX - struct dma_queue tx_delay[__AR9170_NUM_TX_QUEUES]; - struct dma_queue tx_retry; - unsigned int tx_trigger; -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ + /* tx aggregate scheduling */ + struct carl9170_tx_superframe *ampdu_prev[__AR9170_NUM_TX_QUEUES]; /* Hardware DMA queue unstuck/fix detection */ unsigned int last_tx_desc_num[__AR9170_NUM_TX_QUEUES]; @@ -117,11 +115,6 @@ struct firmware_context_struct { /* tx sequence control counters */ unsigned int sequence[CARL9170_INTF_NUM]; -#ifdef CONFIG_CARL9170FW_TX_AMPDU - /* tx aggregate scheduling */ - struct carl9170_tx_superframe *ampdu_prev[__AR9170_NUM_TX_QUEUES]; -#endif /* CONFIG_CARL9170FW_TX_AMPDU */ - #ifdef CONFIG_CARL9170FW_CAB_QUEUE /* CAB */ struct dma_queue cab_queue[CARL9170_INTF_NUM]; diff --git a/carlfw/include/dma.h b/carlfw/include/dma.h index 565c48d..7041736 100644 --- a/carlfw/include/dma.h +++ b/carlfw/include/dma.h @@ -46,17 +46,11 @@ struct dma_desc { struct dma_desc *nextAddr; /* Next TD address */ } __packed __aligned(4); -/* (Up, Dn, 5x Tx, Rx), USB Int, (5x delayed Tx + retry), CAB, BA */ -#define AR9170_TERMINATOR_NUMBER_B 8 +/* Up, Dn, 5x Tx, retry, Rx, [USB Int], (CAB), (BA) */ +#define AR9170_TERMINATOR_NUMBER_B 9 #define AR9170_TERMINATOR_NUMBER_INT 1 -#ifdef CONFIG_CARL9170FW_DELAYED_TX -#define AR9170_TERMINATOR_NUMBER_DELAY 6 -#else -#define AR9170_TERMINATOR_NUMBER_DELAY 0 -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ - #ifdef CONFIG_CARL9170FW_CAB_QUEUE #define AR9170_TERMINATOR_NUMBER_CAB CARL9170_INTF_NUM #else @@ -70,7 +64,6 @@ struct dma_desc { #endif /* CONFIG_CARL9170FW_HANDLE_BACK_REQ */ #define AR9170_TERMINATOR_NUMBER (AR9170_TERMINATOR_NUMBER_B + \ AR9170_TERMINATOR_NUMBER_INT + \ - AR9170_TERMINATOR_NUMBER_DELAY + \ AR9170_TERMINATOR_NUMBER_CAB + \ AR9170_TERMINATOR_NUMBER_BA) @@ -121,11 +114,11 @@ struct carl9170_sram_reserved { * | - Up (to USB host) * | - Down (from USB host) * | - TX (5x, to wifi) + * | - AMPDU TX retry * | - RX (from wifi) * | - CAB Queue * | - FW cmd & req descriptor * | - BlockAck descriptor - * | - Delayed TX (5x) * | total: AR9170_TERMINATOR_NUMBER * +-- * | block descriptors (dma_desc) diff --git a/carlfw/include/wl.h b/carlfw/include/wl.h index ff04536..7428d1a 100644 --- a/carlfw/include/wl.h +++ b/carlfw/include/wl.h @@ -52,22 +52,10 @@ static inline __inline struct dma_desc *get_wlan_txq_addr(const unsigned int q) return getp(AR9170_MAC_REG_DMA_TXQ_CURR_ADDR + (q << 3)); } -static inline __inline void _wlan_trigger(const uint32_t queue_bit) -{ - set(AR9170_MAC_REG_DMA_TRIGGER, queue_bit); -} - -#ifdef CONFIG_CARL9170FW_DELAYED_TX static inline __inline void wlan_trigger(const uint32_t queue_bit) { - fw.wlan.tx_trigger |= queue_bit; -} -#else -static inline __inline void wlan_trigger(const uint32_t queue_bit) -{ - _wlan_trigger(queue_bit); + set(AR9170_MAC_REG_DMA_TRIGGER, queue_bit); } -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ static inline __inline uint8_t ar9170_get_rx_macstatus_status(struct dma_desc *desc) { diff --git a/carlfw/src/dma.c b/carlfw/src/dma.c index 73b1096..92a8a68 100644 --- a/carlfw/src/dma.c +++ b/carlfw/src/dma.c @@ -78,6 +78,7 @@ void dma_init_descriptors(void) fw.pta.down_queue.head = fw.pta.down_queue.terminator = &dma_mem.terminator[i++]; for (j = 0; j < __AR9170_NUM_TX_QUEUES; j++) fw.wlan.tx_queue[j].head = fw.wlan.tx_queue[j].terminator = &dma_mem.terminator[i++]; + fw.wlan.tx_retry.head = fw.wlan.tx_retry.terminator = &dma_mem.terminator[i++]; fw.wlan.rx_queue.head = fw.wlan.rx_queue.terminator = &dma_mem.terminator[i++]; fw.usb.int_desc = &dma_mem.terminator[i++]; @@ -96,13 +97,6 @@ void dma_init_descriptors(void) fw.wlan.ba_desc = &dma_mem.terminator[i++]; #endif /* CONFIG_CARL9170FW_HANDLE_BACK_REQ */ -#ifdef CONFIG_CARL9170FW_DELAYED_TX - fw.wlan.tx_retry.head = fw.wlan.tx_retry.terminator = &dma_mem.terminator[i++]; - - for (j = 0; j < __AR9170_NUM_TX_QUEUES; j++) - 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", diff --git a/carlfw/src/hostif.c b/carlfw/src/hostif.c index 5a1c62f..d032c0f 100644 --- a/carlfw/src/hostif.c +++ b/carlfw/src/hostif.c @@ -101,7 +101,7 @@ static void handle_upload(void) down_trigger(); #else dma_reclaim(&fw.wlan.rx_queue, desc); - _wlan_trigger(AR9170_DMA_TRIGGER_RXQ); + wlan_trigger(AR9170_DMA_TRIGGER_RXQ); #endif /* CONFIG_CARL9170FW_LOOPBACK */ } } diff --git a/carlfw/src/wlan.c b/carlfw/src/wlan.c index e503640..0e0b1dd 100644 --- a/carlfw/src/wlan.c +++ b/carlfw/src/wlan.c @@ -226,28 +226,50 @@ static inline bool compare_ether_address(const void *_d0, const void *_d1) return !((d0[0] ^ d1[0]) | (unsigned short)(d0[1] ^ d1[1])); } -#ifdef CONFIG_CARL9170FW_TX_AMPDU +/* This function will only work on uint32_t-aligned pointers! */ +static bool same_hdr(const void *_d0, const void *_d1) +{ + const uint32_t *d0 = _d0; + const uint32_t *d1 = _d1; + + /* BUG_ON((unsigned long)d0 & 3 || (unsigned long)d1 & 3)) */ + return !((d0[0] ^ d1[0]) | /* FC + DU */ + (d0[1] ^ d1[1]) | /* addr1 */ + (d0[2] ^ d1[2]) | (d0[3] ^ d1[3]) | /* addr2 + addr3 */ + (d0[4] ^ d1[4])); /* addr3 */ +} + +static inline bool same_aggr(struct ieee80211_hdr *a, struct ieee80211_hdr *b) +{ + return (get_tid(a) == get_tid(b)) || same_hdr(a, b); +} + +static void wlan_tx_ampdu_end(unsigned int qidx) +{ + struct carl9170_tx_superframe *ht_prev = fw.wlan.ampdu_prev[qidx]; + + fw.wlan.ampdu_prev[qidx] = NULL; + if (ht_prev) + ht_prev->f.hdr.mac.ba_end = 1; +} + static void wlan_tx_ampdu(struct carl9170_tx_superframe *super) { unsigned int qidx = super->s.queue; struct carl9170_tx_superframe *ht_prev = fw.wlan.ampdu_prev[qidx]; if (!super->f.hdr.mac.ampdu) { - fw.wlan.ampdu_prev[qidx] = NULL; - - if (ht_prev) - ht_prev->f.hdr.mac.ba_end = 1; + wlan_tx_ampdu_end(qidx); } else { fw.wlan.ampdu_prev[qidx] = super; - if (ht_prev && (get_tid(&super->f.data.i3e) != get_tid(&ht_prev->f.data.i3e) || - !compare_ether_address(super->f.data.i3e.addr1, ht_prev->f.data.i3e.addr1))) + if (ht_prev && + !same_aggr(&super->f.data.i3e, &ht_prev->f.data.i3e)) ht_prev->f.hdr.mac.ba_end = 1; else super->f.hdr.mac.ba_end = 0; } } -#endif /* CONFIG_CARL9170FW_TX_AMPDU */ /* for all tries */ static void __wlan_tx(struct dma_desc *desc) @@ -271,9 +293,7 @@ static void __wlan_tx(struct dma_desc *desc) read_tsf(tsf); } -#ifdef CONFIG_CARL9170FW_TX_AMPDU wlan_tx_ampdu(super); -#endif /* CONFIG_CARL9170FW_TX_AMPDU */ #if (defined CONFIG_CARL9170FW_LOOPBACK) || (defined CONFIG_CARL9170FW_DISCARD) wlan_tx_complete(super, true); @@ -397,11 +417,7 @@ static bool wlan_tx_status(struct dma_queue *queue, */ dma_unlink_head(queue); -#ifdef CONFIG_CARL9170FW_DELAYED_TX dma_put(&fw.wlan.tx_retry, desc); -#else - __wlan_tx(desc); -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ return true; } } else { @@ -447,7 +463,8 @@ static bool wlan_tx_status(struct dma_queue *queue, static void handle_tx_completion(void) { struct dma_desc *desc; - unsigned int i; + unsigned int map = 0; + int i; for (i = 0; i < __AR9170_NUM_TX_QUEUES; i++) { __while_desc_bits(desc, &fw.wlan.tx_queue[i], AR9170_OWN_BITS_SW) { @@ -457,15 +474,15 @@ static void handle_tx_completion(void) } } -#ifdef CONFIG_CARL9170FW_DELAYED_TX for_each_desc(desc, &fw.wlan.tx_retry) __wlan_tx(desc); - for_each_desc(desc, &fw.wlan.tx_delay[i]) - _wlan_tx(desc); -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ - wlan_trigger(BIT(i)); + wlan_tx_ampdu_end(i); + if (!queue_empty(&fw.wlan.tx_queue[i])) + map |= BIT(i); + } + wlan_trigger(map); } void __hot wlan_tx(struct dma_desc *desc) @@ -485,13 +502,6 @@ void __hot wlan_tx(struct dma_desc *desc) } #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ -#ifdef CONFIG_CARL9170FW_DELAYED_TX - if (!queue_empty(&fw.wlan.tx_queue[super->s.queue])) { - dma_put(&fw.wlan.tx_delay[super->s.queue], desc); - return; - } -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ - _wlan_tx(desc); wlan_trigger(BIT(super->s.queue)); } @@ -865,7 +875,7 @@ static void handle_rx(void) up_trigger(); } else { dma_reclaim(&fw.wlan.rx_queue, desc); - _wlan_trigger(AR9170_DMA_TRIGGER_RXQ); + wlan_trigger(AR9170_DMA_TRIGGER_RXQ); } } } @@ -1039,13 +1049,6 @@ static void wlan_janitor(void) } #endif /* CONFIG_CARL9170FW_CAB_QUEUE */ -#ifdef CONFIG_CARL9170FW_DELAYED_TX - if (fw.wlan.tx_trigger) { - _wlan_trigger(fw.wlan.tx_trigger); - fw.wlan.tx_trigger = 0; - } -#endif /* CONFIG_CARL9170FW_DELAYED_TX */ - wlan_send_buffered_tx_status(); #ifdef CONFIG_CARL9170FW_HANDLE_BACK_REQ @@ -1250,6 +1253,7 @@ static void wlan_mac_reset(void) * set(AR9170_PHY_REG_CCA_THRESHOLD, 0x0); */ + val = AR9170_DMA_TRIGGER_RXQ; /* Reinitialize all WLAN TX DMA queues. */ for (i = 0; i < __AR9170_NUM_TX_QUEUES; i++) { struct dma_desc *iter; @@ -1258,7 +1262,7 @@ static void wlan_mac_reset(void) set_wlan_txq_dma_addr(i, (uint32_t) iter); if (!is_terminator(&fw.wlan.tx_queue[i], iter)) - wlan_trigger(BIT(i)); + val |= BIT(i); DBG("Q:%d l:%d h:%p t:%p cu:%p it:%p ct:%x st:%x\n", i, queue_len(&fw.wlan.tx_queue[i]), fw.wlan.tx_queue[i].head, fw.wlan.tx_queue[i].terminator, @@ -1269,7 +1273,7 @@ static void wlan_mac_reset(void) AR9170_MAC_INT_RETRY_FAIL; set(AR9170_MAC_REG_DMA_RXQ_ADDR, (uint32_t) fw.wlan.rx_queue.head); - wlan_trigger(AR9170_DMA_TRIGGER_RXQ); + wlan_trigger(val); } #else static void wlan_mac_reset(void) -- 2.31.1