backport from wireless-drivers-next, replacing some existing patches in our tree (marked with '=' are those which were already present): f483039cf51a rt2x00: use simple_read_from_buffer() =5c656c71b1bf rt2800: move usb specific txdone/txstatus routines to rt2800lib =0b0d556e0ebb rt2800mmio: use txdone/txstatus routines from lib =5022efb50f62 rt2x00: do not check for txstatus timeout every time on tasklet =adf26a356f13 rt2x00: use different txstatus timeouts when flushing =0240564430c0 rt2800: flush and txstatus rework for rt2800mmio 6eba8fd22352 rt2x00: rt2400pci: mark expected switch fall-through 10bb92217747 rt2x00: rt2500pci: mark expected switch fall-through 916e6bbcfcff rt2x00: rt2800lib: mark expected switch fall-throughs 641dd8068ecb rt2x00: rt61pci: mark expected switch fall-through 750afb08ca71 cross-tree: phase out dma_zalloc_coherent() =c2e28ef7711f rt2x00: reduce tx power to nominal level on RT6352 a4296994eb80 rt2x00: Work around a firmware bug with shared keys 2587791d5758 rt2x00: no need to check return value of debugfs_create functions pending on linux-wireless: rt2x00: remove unneeded check rt2x00: remove confusing AGC register rt2800: enable TX_PIN_CFG_LNA_PE_ bits per band rt2800: enable TX_PIN_CFG_RFRX_EN only for MT7620 rt2800: comment and simplify AGC init for RT6352 rt2x00: do not print error when queue is full rt2800: partially restore old mmio txstatus behaviour rt2800: new flush implementation for SoC devices rt2800: move txstatus pending routine rt2800mmio: fetch tx status changes rt2800mmio: use timer and work for handling tx statuses timeouts rt2x00: remove last_nostatus_check rt2x00: remove not used entry field rt2x00mmio: remove legacy comment While at it also rename some existing patches now that there are separate folders with patches for each driver to make things a bit nicer to handle. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
		
			
				
	
	
		
			245 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 0b0d556e0ebb6c966bc993e21a22a156812d8fdf Mon Sep 17 00:00:00 2001
 | 
						|
From: Stanislaw Gruszka <sgruszka@redhat.com>
 | 
						|
Date: Wed, 26 Sep 2018 12:24:54 +0200
 | 
						|
Subject: [PATCH 03/28] rt2800mmio: use txdone/txstatus routines from lib
 | 
						|
 | 
						|
Use usb txdone/txstatus routines (now in rt2800libc) for mmio devices.
 | 
						|
 | 
						|
Note this also change how we handle INT_SOURCE_CSR_TX_FIFO_STATUS
 | 
						|
interrupt. Now it is disabled since IRQ routine till end of the txstatus
 | 
						|
tasklet (the same behaviour like others interrupts). Reason to do not
 | 
						|
disable this interrupt was not to miss any tx status from 16 entries
 | 
						|
FIFO register. Now, since we check for tx status timeout, we can
 | 
						|
allow to miss some tx statuses. However this will be improved in further
 | 
						|
patch where I also implement read status FIFO register in the tasklet.
 | 
						|
 | 
						|
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 | 
						|
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 | 
						|
---
 | 
						|
 .../net/wireless/ralink/rt2x00/rt2800mmio.c   | 180 +-----------------
 | 
						|
 .../net/wireless/ralink/rt2x00/rt2x00queue.c  |   1 +
 | 
						|
 2 files changed, 9 insertions(+), 172 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
 | 
						|
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c
 | 
						|
@@ -175,161 +175,6 @@ static void rt2800mmio_wakeup(struct rt2
 | 
						|
 	rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 | 
						|
 }
 | 
						|
 
 | 
						|
-static bool rt2800mmio_txdone_entry_check(struct queue_entry *entry, u32 status)
 | 
						|
-{
 | 
						|
-	__le32 *txwi;
 | 
						|
-	u32 word;
 | 
						|
-	int wcid, tx_wcid;
 | 
						|
-
 | 
						|
-	wcid = rt2x00_get_field32(status, TX_STA_FIFO_WCID);
 | 
						|
-
 | 
						|
-	txwi = rt2800_drv_get_txwi(entry);
 | 
						|
-	word = rt2x00_desc_read(txwi, 1);
 | 
						|
-	tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
 | 
						|
-
 | 
						|
-	return (tx_wcid == wcid);
 | 
						|
-}
 | 
						|
-
 | 
						|
-static bool rt2800mmio_txdone_find_entry(struct queue_entry *entry, void *data)
 | 
						|
-{
 | 
						|
-	u32 status = *(u32 *)data;
 | 
						|
-
 | 
						|
-	/*
 | 
						|
-	 * rt2800pci hardware might reorder frames when exchanging traffic
 | 
						|
-	 * with multiple BA enabled STAs.
 | 
						|
-	 *
 | 
						|
-	 * For example, a tx queue
 | 
						|
-	 *    [ STA1 | STA2 | STA1 | STA2 ]
 | 
						|
-	 * can result in tx status reports
 | 
						|
-	 *    [ STA1 | STA1 | STA2 | STA2 ]
 | 
						|
-	 * when the hw decides to aggregate the frames for STA1 into one AMPDU.
 | 
						|
-	 *
 | 
						|
-	 * To mitigate this effect, associate the tx status to the first frame
 | 
						|
-	 * in the tx queue with a matching wcid.
 | 
						|
-	 */
 | 
						|
-	if (rt2800mmio_txdone_entry_check(entry, status) &&
 | 
						|
-	    !test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
 | 
						|
-		/*
 | 
						|
-		 * Got a matching frame, associate the tx status with
 | 
						|
-		 * the frame
 | 
						|
-		 */
 | 
						|
-		entry->status = status;
 | 
						|
-		set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
 | 
						|
-		return true;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	/* Check the next frame */
 | 
						|
-	return false;
 | 
						|
-}
 | 
						|
-
 | 
						|
-static bool rt2800mmio_txdone_match_first(struct queue_entry *entry, void *data)
 | 
						|
-{
 | 
						|
-	u32 status = *(u32 *)data;
 | 
						|
-
 | 
						|
-	/*
 | 
						|
-	 * Find the first frame without tx status and assign this status to it
 | 
						|
-	 * regardless if it matches or not.
 | 
						|
-	 */
 | 
						|
-	if (!test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
 | 
						|
-		/*
 | 
						|
-		 * Got a matching frame, associate the tx status with
 | 
						|
-		 * the frame
 | 
						|
-		 */
 | 
						|
-		entry->status = status;
 | 
						|
-		set_bit(ENTRY_DATA_STATUS_SET, &entry->flags);
 | 
						|
-		return true;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	/* Check the next frame */
 | 
						|
-	return false;
 | 
						|
-}
 | 
						|
-static bool rt2800mmio_txdone_release_entries(struct queue_entry *entry,
 | 
						|
-					      void *data)
 | 
						|
-{
 | 
						|
-	if (test_bit(ENTRY_DATA_STATUS_SET, &entry->flags)) {
 | 
						|
-		rt2800_txdone_entry(entry, entry->status,
 | 
						|
-				    rt2800mmio_get_txwi(entry), true);
 | 
						|
-		return false;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	/* No more frames to release */
 | 
						|
-	return true;
 | 
						|
-}
 | 
						|
-
 | 
						|
-static bool rt2800mmio_txdone(struct rt2x00_dev *rt2x00dev)
 | 
						|
-{
 | 
						|
-	struct data_queue *queue;
 | 
						|
-	u32 status;
 | 
						|
-	u8 qid;
 | 
						|
-	int max_tx_done = 16;
 | 
						|
-
 | 
						|
-	while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
 | 
						|
-		qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
 | 
						|
-		if (unlikely(qid >= QID_RX)) {
 | 
						|
-			/*
 | 
						|
-			 * Unknown queue, this shouldn't happen. Just drop
 | 
						|
-			 * this tx status.
 | 
						|
-			 */
 | 
						|
-			rt2x00_warn(rt2x00dev, "Got TX status report with unexpected pid %u, dropping\n",
 | 
						|
-				    qid);
 | 
						|
-			break;
 | 
						|
-		}
 | 
						|
-
 | 
						|
-		queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
 | 
						|
-		if (unlikely(queue == NULL)) {
 | 
						|
-			/*
 | 
						|
-			 * The queue is NULL, this shouldn't happen. Stop
 | 
						|
-			 * processing here and drop the tx status
 | 
						|
-			 */
 | 
						|
-			rt2x00_warn(rt2x00dev, "Got TX status for an unavailable queue %u, dropping\n",
 | 
						|
-				    qid);
 | 
						|
-			break;
 | 
						|
-		}
 | 
						|
-
 | 
						|
-		if (unlikely(rt2x00queue_empty(queue))) {
 | 
						|
-			/*
 | 
						|
-			 * The queue is empty. Stop processing here
 | 
						|
-			 * and drop the tx status.
 | 
						|
-			 */
 | 
						|
-			rt2x00_warn(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
 | 
						|
-				    qid);
 | 
						|
-			break;
 | 
						|
-		}
 | 
						|
-
 | 
						|
-		/*
 | 
						|
-		 * Let's associate this tx status with the first
 | 
						|
-		 * matching frame.
 | 
						|
-		 */
 | 
						|
-		if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
 | 
						|
-						Q_INDEX, &status,
 | 
						|
-						rt2800mmio_txdone_find_entry)) {
 | 
						|
-			/*
 | 
						|
-			 * We cannot match the tx status to any frame, so just
 | 
						|
-			 * use the first one.
 | 
						|
-			 */
 | 
						|
-			if (!rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
 | 
						|
-							Q_INDEX, &status,
 | 
						|
-							rt2800mmio_txdone_match_first)) {
 | 
						|
-				rt2x00_warn(rt2x00dev, "No frame found for TX status on queue %u, dropping\n",
 | 
						|
-					    qid);
 | 
						|
-				break;
 | 
						|
-			}
 | 
						|
-		}
 | 
						|
-
 | 
						|
-		/*
 | 
						|
-		 * Release all frames with a valid tx status.
 | 
						|
-		 */
 | 
						|
-		rt2x00queue_for_each_entry(queue, Q_INDEX_DONE,
 | 
						|
-					   Q_INDEX, NULL,
 | 
						|
-					   rt2800mmio_txdone_release_entries);
 | 
						|
-
 | 
						|
-		if (--max_tx_done == 0)
 | 
						|
-			break;
 | 
						|
-	}
 | 
						|
-
 | 
						|
-	return !max_tx_done;
 | 
						|
-}
 | 
						|
-
 | 
						|
 static inline void rt2800mmio_enable_interrupt(struct rt2x00_dev *rt2x00dev,
 | 
						|
 					       struct rt2x00_field32 irq_field)
 | 
						|
 {
 | 
						|
@@ -349,14 +194,14 @@ static inline void rt2800mmio_enable_int
 | 
						|
 void rt2800mmio_txstatus_tasklet(unsigned long data)
 | 
						|
 {
 | 
						|
 	struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
 | 
						|
-	if (rt2800mmio_txdone(rt2x00dev))
 | 
						|
-		tasklet_schedule(&rt2x00dev->txstatus_tasklet);
 | 
						|
 
 | 
						|
-	/*
 | 
						|
-	 * No need to enable the tx status interrupt here as we always
 | 
						|
-	 * leave it enabled to minimize the possibility of a tx status
 | 
						|
-	 * register overflow. See comment in interrupt handler.
 | 
						|
-	 */
 | 
						|
+	rt2800_txdone(rt2x00dev);
 | 
						|
+
 | 
						|
+	rt2800_txdone_nostatus(rt2x00dev);
 | 
						|
+
 | 
						|
+	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
 | 
						|
+		rt2800mmio_enable_interrupt(rt2x00dev,
 | 
						|
+					    INT_SOURCE_CSR_TX_FIFO_STATUS);
 | 
						|
 }
 | 
						|
 EXPORT_SYMBOL_GPL(rt2800mmio_txstatus_tasklet);
 | 
						|
 
 | 
						|
@@ -440,10 +285,6 @@ static void rt2800mmio_txstatus_interrup
 | 
						|
 	 * because we can schedule the tasklet multiple times (when the
 | 
						|
 	 * interrupt fires again during tx status processing).
 | 
						|
 	 *
 | 
						|
-	 * Furthermore we don't disable the TX_FIFO_STATUS
 | 
						|
-	 * interrupt here but leave it enabled so that the TX_STA_FIFO
 | 
						|
-	 * can also be read while the tx status tasklet gets executed.
 | 
						|
-	 *
 | 
						|
 	 * Since we have only one producer and one consumer we don't
 | 
						|
 	 * need to lock the kfifo.
 | 
						|
 	 */
 | 
						|
@@ -485,13 +326,8 @@ irqreturn_t rt2800mmio_interrupt(int irq
 | 
						|
 	 */
 | 
						|
 	mask = ~reg;
 | 
						|
 
 | 
						|
-	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS)) {
 | 
						|
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
 | 
						|
 		rt2800mmio_txstatus_interrupt(rt2x00dev);
 | 
						|
-		/*
 | 
						|
-		 * Never disable the TX_FIFO_STATUS interrupt.
 | 
						|
-		 */
 | 
						|
-		rt2x00_set_field32(&mask, INT_MASK_CSR_TX_FIFO_STATUS, 1);
 | 
						|
-	}
 | 
						|
 
 | 
						|
 	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_PRE_TBTT))
 | 
						|
 		tasklet_hi_schedule(&rt2x00dev->pretbtt_tasklet);
 | 
						|
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
 | 
						|
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
 | 
						|
@@ -113,6 +113,7 @@ int rt2x00queue_map_txskb(struct queue_e
 | 
						|
 		return -ENOMEM;
 | 
						|
 
 | 
						|
 	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
 | 
						|
+	rt2x00lib_dmadone(entry);
 | 
						|
 	return 0;
 | 
						|
 }
 | 
						|
 EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
 |