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"
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];
/* 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];
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
#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)
* | - 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)
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)
{
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++];
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",
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 */
}
}
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)
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);
*/
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 {
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) {
}
}
-#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)
}
#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));
}
up_trigger();
} else {
dma_reclaim(&fw.wlan.rx_queue, desc);
- _wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
+ wlan_trigger(AR9170_DMA_TRIGGER_RXQ);
}
}
}
}
#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
* 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;
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,
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)