 d4c999bb89
			
		
	
	d4c999bb89
	
	
	
		
			
			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>
		
			
				
	
	
		
			358 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			358 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 5c656c71b1bf5611ce8262bab338104e04d10b8d Mon Sep 17 00:00:00 2001
 | |
| From: Stanislaw Gruszka <sgruszka@redhat.com>
 | |
| Date: Wed, 26 Sep 2018 12:24:53 +0200
 | |
| Subject: [PATCH 02/28] rt2800: move usb specific txdone/txstatus routines to
 | |
|  rt2800lib
 | |
| 
 | |
| In order to reuse usb txdone/txstatus routines for mmio, move them
 | |
| to common rt2800lib.c file.
 | |
| 
 | |
| Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
 | |
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 | |
| ---
 | |
|  .../net/wireless/ralink/rt2x00/rt2800lib.c    | 138 +++++++++++++++++
 | |
|  .../net/wireless/ralink/rt2x00/rt2800lib.h    |   3 +
 | |
|  .../net/wireless/ralink/rt2x00/rt2800usb.c    | 143 +-----------------
 | |
|  3 files changed, 145 insertions(+), 139 deletions(-)
 | |
| 
 | |
| --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 | |
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 | |
| @@ -957,6 +957,47 @@ static void rt2800_rate_from_status(stru
 | |
|  	skbdesc->tx_rate_flags = flags;
 | |
|  }
 | |
|  
 | |
| +static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
 | |
| +{
 | |
| +	__le32 *txwi;
 | |
| +	u32 word;
 | |
| +	int wcid, ack, pid;
 | |
| +	int tx_wcid, tx_ack, tx_pid, is_agg;
 | |
| +
 | |
| +	/*
 | |
| +	 * This frames has returned with an IO error,
 | |
| +	 * so the status report is not intended for this
 | |
| +	 * frame.
 | |
| +	 */
 | |
| +	if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
 | |
| +		return false;
 | |
| +
 | |
| +	wcid	= rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
 | |
| +	ack	= rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
 | |
| +	pid	= rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
 | |
| +	is_agg	= rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);
 | |
| +
 | |
| +	/*
 | |
| +	 * Validate if this TX status report is intended for
 | |
| +	 * this entry by comparing the WCID/ACK/PID fields.
 | |
| +	 */
 | |
| +	txwi = rt2800_drv_get_txwi(entry);
 | |
| +
 | |
| +	word = rt2x00_desc_read(txwi, 1);
 | |
| +	tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
 | |
| +	tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
 | |
| +	tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
 | |
| +
 | |
| +	if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
 | |
| +		rt2x00_dbg(entry->queue->rt2x00dev,
 | |
| +			   "TX status report missed for queue %d entry %d\n",
 | |
| +			   entry->queue->qid, entry->entry_idx);
 | |
| +		return false;
 | |
| +	}
 | |
| +
 | |
| +	return true;
 | |
| +}
 | |
| +
 | |
|  void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
 | |
|  			 bool match)
 | |
|  {
 | |
| @@ -1059,6 +1100,103 @@ void rt2800_txdone_entry(struct queue_en
 | |
|  }
 | |
|  EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
 | |
|  
 | |
| +void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
 | |
| +{
 | |
| +	struct data_queue *queue;
 | |
| +	struct queue_entry *entry;
 | |
| +	u32 reg;
 | |
| +	u8 qid;
 | |
| +	bool match;
 | |
| +
 | |
| +	while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) {
 | |
| +		/*
 | |
| +		 * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
 | |
| +		 * guaranteed to be one of the TX QIDs .
 | |
| +		 */
 | |
| +		qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
 | |
| +		queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
 | |
| +
 | |
| +		if (unlikely(rt2x00queue_empty(queue))) {
 | |
| +			rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
 | |
| +				   qid);
 | |
| +			break;
 | |
| +		}
 | |
| +
 | |
| +		entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 | |
| +
 | |
| +		if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
 | |
| +			     !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
 | |
| +			rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
 | |
| +				    entry->entry_idx, qid);
 | |
| +			break;
 | |
| +		}
 | |
| +
 | |
| +		match = rt2800_txdone_entry_check(entry, reg);
 | |
| +		rt2800_txdone_entry(entry, reg, rt2800_drv_get_txwi(entry), match);
 | |
| +	}
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(rt2800_txdone);
 | |
| +
 | |
| +static inline bool rt2800_entry_txstatus_timeout(struct queue_entry *entry)
 | |
| +{
 | |
| +	bool tout;
 | |
| +
 | |
| +	if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
 | |
| +		return false;
 | |
| +
 | |
| +	tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500));
 | |
| +	if (unlikely(tout))
 | |
| +		rt2x00_dbg(entry->queue->rt2x00dev,
 | |
| +			   "TX status timeout for entry %d in queue %d\n",
 | |
| +			   entry->entry_idx, entry->queue->qid);
 | |
| +	return tout;
 | |
| +
 | |
| +}
 | |
| +
 | |
| +bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
 | |
| +{
 | |
| +	struct data_queue *queue;
 | |
| +	struct queue_entry *entry;
 | |
| +
 | |
| +	tx_queue_for_each(rt2x00dev, queue) {
 | |
| +		entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 | |
| +		if (rt2800_entry_txstatus_timeout(entry))
 | |
| +			return true;
 | |
| +	}
 | |
| +	return false;
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(rt2800_txstatus_timeout);
 | |
| +
 | |
| +void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
 | |
| +{
 | |
| +	struct data_queue *queue;
 | |
| +	struct queue_entry *entry;
 | |
| +
 | |
| +	/*
 | |
| +	 * Process any trailing TX status reports for IO failures,
 | |
| +	 * we loop until we find the first non-IO error entry. This
 | |
| +	 * can either be a frame which is free, is being uploaded,
 | |
| +	 * or has completed the upload but didn't have an entry
 | |
| +	 * in the TX_STAT_FIFO register yet.
 | |
| +	 */
 | |
| +	tx_queue_for_each(rt2x00dev, queue) {
 | |
| +		while (!rt2x00queue_empty(queue)) {
 | |
| +			entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 | |
| +
 | |
| +			if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
 | |
| +			    !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
 | |
| +				break;
 | |
| +
 | |
| +			if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
 | |
| +			    rt2800_entry_txstatus_timeout(entry))
 | |
| +				rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
 | |
| +			else
 | |
| +				break;
 | |
| +		}
 | |
| +	}
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(rt2800_txdone_nostatus);
 | |
| +
 | |
|  static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
 | |
|  					  unsigned int index)
 | |
|  {
 | |
| --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
 | |
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
 | |
| @@ -195,6 +195,9 @@ void rt2800_process_rxwi(struct queue_en
 | |
|  
 | |
|  void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi,
 | |
|  			 bool match);
 | |
| +void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
 | |
| +void rt2800_txdone_nostatus(struct rt2x00_dev *rt2x00dev);
 | |
| +bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev);
 | |
|  
 | |
|  void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
 | |
|  void rt2800_clear_beacon(struct queue_entry *entry);
 | |
| --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
 | |
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
 | |
| @@ -116,35 +116,6 @@ static bool rt2800usb_txstatus_pending(s
 | |
|  	return false;
 | |
|  }
 | |
|  
 | |
| -static inline bool rt2800usb_entry_txstatus_timeout(struct queue_entry *entry)
 | |
| -{
 | |
| -	bool tout;
 | |
| -
 | |
| -	if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
 | |
| -		return false;
 | |
| -
 | |
| -	tout = time_after(jiffies, entry->last_action + msecs_to_jiffies(500));
 | |
| -	if (unlikely(tout))
 | |
| -		rt2x00_dbg(entry->queue->rt2x00dev,
 | |
| -			   "TX status timeout for entry %d in queue %d\n",
 | |
| -			   entry->entry_idx, entry->queue->qid);
 | |
| -	return tout;
 | |
| -
 | |
| -}
 | |
| -
 | |
| -static bool rt2800usb_txstatus_timeout(struct rt2x00_dev *rt2x00dev)
 | |
| -{
 | |
| -	struct data_queue *queue;
 | |
| -	struct queue_entry *entry;
 | |
| -
 | |
| -	tx_queue_for_each(rt2x00dev, queue) {
 | |
| -		entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 | |
| -		if (rt2800usb_entry_txstatus_timeout(entry))
 | |
| -			return true;
 | |
| -	}
 | |
| -	return false;
 | |
| -}
 | |
| -
 | |
|  #define TXSTATUS_READ_INTERVAL 1000000
 | |
|  
 | |
|  static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
 | |
| @@ -171,7 +142,7 @@ static bool rt2800usb_tx_sta_fifo_read_c
 | |
|  	}
 | |
|  
 | |
|  	/* Check if there is any entry that timedout waiting on TX status */
 | |
| -	if (rt2800usb_txstatus_timeout(rt2x00dev))
 | |
| +	if (rt2800_txstatus_timeout(rt2x00dev))
 | |
|  		queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
 | |
|  
 | |
|  	if (rt2800usb_txstatus_pending(rt2x00dev)) {
 | |
| @@ -501,123 +472,17 @@ static int rt2800usb_get_tx_data_len(str
 | |
|  /*
 | |
|   * TX control handlers
 | |
|   */
 | |
| -static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
 | |
| -{
 | |
| -	__le32 *txwi;
 | |
| -	u32 word;
 | |
| -	int wcid, ack, pid;
 | |
| -	int tx_wcid, tx_ack, tx_pid, is_agg;
 | |
| -
 | |
| -	/*
 | |
| -	 * This frames has returned with an IO error,
 | |
| -	 * so the status report is not intended for this
 | |
| -	 * frame.
 | |
| -	 */
 | |
| -	if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
 | |
| -		return false;
 | |
| -
 | |
| -	wcid	= rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
 | |
| -	ack	= rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
 | |
| -	pid	= rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
 | |
| -	is_agg	= rt2x00_get_field32(reg, TX_STA_FIFO_TX_AGGRE);
 | |
| -
 | |
| -	/*
 | |
| -	 * Validate if this TX status report is intended for
 | |
| -	 * this entry by comparing the WCID/ACK/PID fields.
 | |
| -	 */
 | |
| -	txwi = rt2800usb_get_txwi(entry);
 | |
| -
 | |
| -	word = rt2x00_desc_read(txwi, 1);
 | |
| -	tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
 | |
| -	tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
 | |
| -	tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
 | |
| -
 | |
| -	if (wcid != tx_wcid || ack != tx_ack || (!is_agg && pid != tx_pid)) {
 | |
| -		rt2x00_dbg(entry->queue->rt2x00dev,
 | |
| -			   "TX status report missed for queue %d entry %d\n",
 | |
| -			   entry->queue->qid, entry->entry_idx);
 | |
| -		return false;
 | |
| -	}
 | |
| -
 | |
| -	return true;
 | |
| -}
 | |
| -
 | |
| -static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
 | |
| -{
 | |
| -	struct data_queue *queue;
 | |
| -	struct queue_entry *entry;
 | |
| -	u32 reg;
 | |
| -	u8 qid;
 | |
| -	bool match;
 | |
| -
 | |
| -	while (kfifo_get(&rt2x00dev->txstatus_fifo, ®)) {
 | |
| -		/*
 | |
| -		 * TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus qid is
 | |
| -		 * guaranteed to be one of the TX QIDs .
 | |
| -		 */
 | |
| -		qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
 | |
| -		queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
 | |
| -
 | |
| -		if (unlikely(rt2x00queue_empty(queue))) {
 | |
| -			rt2x00_dbg(rt2x00dev, "Got TX status for an empty queue %u, dropping\n",
 | |
| -				   qid);
 | |
| -			break;
 | |
| -		}
 | |
| -
 | |
| -		entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 | |
| -
 | |
| -		if (unlikely(test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
 | |
| -			     !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))) {
 | |
| -			rt2x00_warn(rt2x00dev, "Data pending for entry %u in queue %u\n",
 | |
| -				    entry->entry_idx, qid);
 | |
| -			break;
 | |
| -		}
 | |
| -
 | |
| -		match = rt2800usb_txdone_entry_check(entry, reg);
 | |
| -		rt2800_txdone_entry(entry, reg, rt2800usb_get_txwi(entry), match);
 | |
| -	}
 | |
| -}
 | |
| -
 | |
| -static void rt2800usb_txdone_nostatus(struct rt2x00_dev *rt2x00dev)
 | |
| -{
 | |
| -	struct data_queue *queue;
 | |
| -	struct queue_entry *entry;
 | |
| -
 | |
| -	/*
 | |
| -	 * Process any trailing TX status reports for IO failures,
 | |
| -	 * we loop until we find the first non-IO error entry. This
 | |
| -	 * can either be a frame which is free, is being uploaded,
 | |
| -	 * or has completed the upload but didn't have an entry
 | |
| -	 * in the TX_STAT_FIFO register yet.
 | |
| -	 */
 | |
| -	tx_queue_for_each(rt2x00dev, queue) {
 | |
| -		while (!rt2x00queue_empty(queue)) {
 | |
| -			entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 | |
| -
 | |
| -			if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
 | |
| -			    !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
 | |
| -				break;
 | |
| -
 | |
| -			if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags) ||
 | |
| -			    rt2800usb_entry_txstatus_timeout(entry))
 | |
| -				rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
 | |
| -			else
 | |
| -				break;
 | |
| -		}
 | |
| -	}
 | |
| -}
 | |
| -
 | |
|  static void rt2800usb_work_txdone(struct work_struct *work)
 | |
|  {
 | |
|  	struct rt2x00_dev *rt2x00dev =
 | |
|  	    container_of(work, struct rt2x00_dev, txdone_work);
 | |
|  
 | |
|  	while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo) ||
 | |
| -	       rt2800usb_txstatus_timeout(rt2x00dev)) {
 | |
| +	       rt2800_txstatus_timeout(rt2x00dev)) {
 | |
|  
 | |
| -		rt2800usb_txdone(rt2x00dev);
 | |
| +		rt2800_txdone(rt2x00dev);
 | |
|  
 | |
| -		rt2800usb_txdone_nostatus(rt2x00dev);
 | |
| +		rt2800_txdone_nostatus(rt2x00dev);
 | |
|  
 | |
|  		/*
 | |
|  		 * The hw may delay sending the packet after DMA complete
 |