From 933314582ee5db00123683cf4c4d713ec9add306 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:53:39 +0200 Subject: rt2x00: Simplify arguments to rt2x00 driver callback functions write_tx_desc shouldn't pass a rt2x00dev and skb pointer, instead it should use the same format as other TX frame callback functions, which is passing the data_entry pointer which contains all the information which is needed to work on a TX frame. Most callers of the kick_tx_queue and kill_tx_queue already have the data_queue pointer, so rather then sending the QID with the given function, when the driver requests a new pointer to the data_queue, it is more efficient to just send the data_queue pointer directly. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 25 +++++++++---------- drivers/net/wireless/rt2x00/rt2500pci.c | 25 +++++++++---------- drivers/net/wireless/rt2x00/rt2500usb.c | 9 +++---- drivers/net/wireless/rt2x00/rt2800pci.c | 41 +++++++++++++------------------ drivers/net/wireless/rt2x00/rt2800usb.c | 9 +++---- drivers/net/wireless/rt2x00/rt2x00.h | 9 +++---- drivers/net/wireless/rt2x00/rt2x00queue.c | 11 ++++----- drivers/net/wireless/rt2x00/rt2x00usb.c | 14 ++++------- drivers/net/wireless/rt2x00/rt2x00usb.h | 12 +++------ drivers/net/wireless/rt2x00/rt61pci.c | 39 ++++++++++++++--------------- drivers/net/wireless/rt2x00/rt73usb.c | 11 ++++----- 11 files changed, 90 insertions(+), 115 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 5063e01410e5..b86b6132a69c 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1007,12 +1007,11 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2400pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -1096,7 +1095,7 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt2400pci_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1112,24 +1111,24 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue) +static void rt2400pci_kick_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } -static void rt2400pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2400pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2x00pci_register_write(rt2x00dev, CSR14, 0); } else { rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c2a555d5376b..21f45810fd1e 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1161,12 +1161,11 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2500pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -1249,7 +1248,7 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt2500pci_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1265,24 +1264,24 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, rt2x00pci_register_write(rt2x00dev, CSR14, reg); } -static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue) +static void rt2500pci_kick_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue == QID_AC_BE)); - rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue == QID_AC_BK)); - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue == QID_ATIM)); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } -static void rt2500pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2500pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2x00pci_register_write(rt2x00dev, CSR14, 0); } else { rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 97cf72f8bc12..8722464944f5 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1041,12 +1041,11 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2500usb_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txd = (__le32 *) skb->data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *txd = (__le32 *) entry->skb->data; u32 word; /* @@ -1129,7 +1128,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt2500usb_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 4390f2b74b2e..af1c6914d7b4 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -571,12 +571,11 @@ static __le32 *rt2800pci_get_txwi(struct queue_entry *entry) return (__le32 *) entry->skb->data; } -static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2800pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -596,7 +595,7 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 0, word); rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_SD_LEN1, skb->len); + rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len); rt2x00_set_field32(&word, TXD_W1_LAST_SEC1, !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W1_BURST, @@ -627,41 +626,35 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, /* * TX data initialization */ -static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue_idx) +static void rt2800pci_kick_tx_queue(struct data_queue *queue) { - struct data_queue *queue; - unsigned int idx, qidx = 0; - - if (queue_idx > QID_HCCA && queue_idx != QID_MGMT) - return; - - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); - idx = queue->index[Q_INDEX]; + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; + unsigned int idx = queue->index[Q_INDEX]; + unsigned int qidx = 0; - if (queue_idx == QID_MGMT) + if (queue->qid == QID_MGMT) qidx = 5; else - qidx = queue_idx; + qidx = queue->qid; rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx); } -static void rt2800pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt2800pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0); return; } rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, ®); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (qid == QID_AC_BE)); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (qid == QID_AC_BK)); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (qid == QID_AC_VI)); - rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (qid == QID_AC_VO)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI)); + rt2x00_set_field32(®, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO)); rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg); } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 9ad28be294eb..02f95892aa07 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -329,12 +329,11 @@ static __le32 *rt2800usb_get_txwi(struct queue_entry *entry) return (__le32 *) (entry->skb->data + TXINFO_DESC_SIZE); } -static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt2800usb_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txi = (__le32 *) skb->data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *txi = (__le32 *) entry->skb->data; u32 word; /* @@ -342,7 +341,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, */ rt2x00_desc_read(txi, 0, &word); rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN, - skb->len - TXINFO_DESC_SIZE); + entry->skb->len - TXINFO_DESC_SIZE); rt2x00_set_field32(&word, TXINFO_W0_WIV, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXINFO_W0_QSEL, 2); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8c65244a847a..69308a0df74f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -559,18 +559,15 @@ struct rt2x00lib_ops { /* * TX control handlers */ - void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, + void (*write_tx_desc) (struct queue_entry *entry, struct txentry_desc *txdesc); void (*write_tx_data) (struct queue_entry *entry, struct txentry_desc *txdesc); void (*write_beacon) (struct queue_entry *entry, struct txentry_desc *txdesc); int (*get_tx_data_len) (struct queue_entry *entry); - void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue); - void (*kill_tx_queue) (struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue); + void (*kick_tx_queue) (struct data_queue *queue); + void (*kill_tx_queue) (struct data_queue *queue); /* * RX control handlers diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 18220953851e..189eaf72967e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -449,15 +449,14 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, struct txentry_desc *txdesc) { struct data_queue *queue = entry->queue; - struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc); + queue->rt2x00dev->ops->lib->write_tx_desc(entry, txdesc); /* * All processing on the frame has been completed, this means * it is now ready to be dumped to userspace through debugfs. */ - rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb); + rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb); } static void rt2x00queue_kick_tx_queue(struct queue_entry *entry, @@ -477,7 +476,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry, */ if (rt2x00queue_threshold(queue) || !test_bit(ENTRY_TXD_BURST, &txdesc->flags)) - rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid); + rt2x00dev->ops->lib->kick_tx_queue(queue); } int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, @@ -591,7 +590,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, intf->beacon->skb = NULL; if (!enable_beacon) { - rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_BEACON); + rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue); mutex_unlock(&intf->beacon_skb_mutex); return 0; } @@ -719,7 +718,7 @@ void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; txall_queue_for_each(rt2x00dev, queue) - rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, queue->qid); + rt2x00dev->ops->lib->kill_tx_queue(queue); } void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index f76014f732ce..52ed3f44c843 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -249,10 +249,8 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) } } -void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +void rt2x00usb_kick_tx_queue(struct data_queue *queue) { - struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); unsigned long irqflags; unsigned int index; unsigned int index_done; @@ -286,10 +284,8 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue); -void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +void rt2x00usb_kill_tx_queue(struct data_queue *queue) { - struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, qid); struct queue_entry_priv_usb *entry_priv; struct queue_entry_priv_usb_bcn *bcn_priv; unsigned int i; @@ -300,8 +296,8 @@ void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev, * the beacon guard byte. */ kill_guard = - (qid == QID_BEACON) && - (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)); + (queue->qid == QID_BEACON) && + (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &queue->rt2x00dev->flags)); /* * Cancel all entries. @@ -447,7 +443,7 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) * The USB version of kill_tx_queue also works * on the RX queue. */ - rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev, QID_RX); + rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx); } EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index d3d3ddc40875..c2d997f67b3e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -379,25 +379,21 @@ struct queue_entry_priv_usb_bcn { /** * rt2x00usb_kick_tx_queue - Kick data queue - * @rt2x00dev: Pointer to &struct rt2x00_dev - * @qid: Data queue to kick + * @queue: Data queue to kick * * This will walk through all entries of the queue and push all pending * frames to the hardware as a single burst. */ -void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid); +void rt2x00usb_kick_tx_queue(struct data_queue *queue); /** * rt2x00usb_kill_tx_queue - Kill data queue - * @rt2x00dev: Pointer to &struct rt2x00_dev - * @qid: Data queue to kill + * @queue: Data queue to kill * * This will walk through all entries of the queue and kill all * previously kicked frames before they can be send. */ -void rt2x00usb_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid); +void rt2x00usb_kill_tx_queue(struct data_queue *queue); /** * rt2x00usb_watchdog - Watchdog for USB communication diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index cff503faac65..ae4698e18729 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1766,12 +1766,11 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt61pci_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + struct queue_entry_priv_pci *entry_priv = entry->priv_data; __le32 *txd = entry_priv->desc; u32 word; @@ -1802,11 +1801,11 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, } rt2x00_desc_read(txd, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, skbdesc->entry->queue->qid); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->queue->qid); rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, skbdesc->entry->entry_idx); rt2x00_set_field32(&word, TXD_W5_TX_POWER, - TXPOWER_TO_DEV(rt2x00dev->tx_power)); + TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); @@ -1882,7 +1881,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt61pci_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. @@ -1918,34 +1917,34 @@ static void rt61pci_write_beacon(struct queue_entry *entry, entry->skb = NULL; } -static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid queue) +static void rt61pci_kick_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue == QID_AC_VI)); - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue == QID_AC_VO)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, (queue->qid == QID_AC_VO)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } -static void rt61pci_kill_tx_queue(struct rt2x00_dev *rt2x00dev, - const enum data_queue_qid qid) +static void rt61pci_kill_tx_queue(struct data_queue *queue) { + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; u32 reg; - if (qid == QID_BEACON) { + if (queue->qid == QID_BEACON) { rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0); return; } rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, (qid == QID_AC_BE)); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, (qid == QID_AC_BK)); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, (qid == QID_AC_VI)); - rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, (qid == QID_AC_VO)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI)); + rt2x00_set_field32(®, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index c65529678fbd..ab9389439d75 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1426,12 +1426,11 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, /* * TX descriptor initialization */ -static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb, +static void rt73usb_write_tx_desc(struct queue_entry *entry, struct txentry_desc *txdesc) { - struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); - __le32 *txd = (__le32 *) skb->data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); + __le32 *txd = (__le32 *) entry->skb->data; u32 word; /* @@ -1487,7 +1486,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_read(txd, 5, &word); rt2x00_set_field32(&word, TXD_W5_TX_POWER, - TXPOWER_TO_DEV(rt2x00dev->tx_power)); + TXPOWER_TO_DEV(entry->queue->rt2x00dev->tx_power)); rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); @@ -1526,7 +1525,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry, /* * Write the TX descriptor for the beacon. */ - rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc); + rt73usb_write_tx_desc(entry, txdesc); /* * Dump beacon to userspace through debugfs. -- cgit v1.2.3 From ee1e755f84dfd5d482076c642fac830aafdc482b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:54:02 +0200 Subject: rt2x00: Reduce indenting Cosmetic change, reduce indenting. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 52ed3f44c843..1d2eb461329f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -232,21 +232,22 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) struct queue_entry_priv_usb *entry_priv = entry->priv_data; u32 length; - if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) { - /* - * USB devices cannot blindly pass the skb->len as the - * length of the data to usb_fill_bulk_urb. Pass the skb - * to the driver to determine what the length should be. - */ - length = rt2x00dev->ops->lib->get_tx_data_len(entry); + if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) + return; + + /* + * USB devices cannot blindly pass the skb->len as the + * length of the data to usb_fill_bulk_urb. Pass the skb + * to the driver to determine what the length should be. + */ + length = rt2x00dev->ops->lib->get_tx_data_len(entry); - usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), - entry->skb->data, length, - rt2x00usb_interrupt_txdone, entry); + usb_fill_bulk_urb(entry_priv->urb, usb_dev, + usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), + entry->skb->data, length, + rt2x00usb_interrupt_txdone, entry); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); - } + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); } void rt2x00usb_kick_tx_queue(struct data_queue *queue) -- cgit v1.2.3 From 5eb7efe8a4807d98a277280e1317e5094eedfb6b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:54:21 +0200 Subject: rt2x00: Move direct access to queue->entries to rt2x00queue.c All access to queue->entries through the Q_INDEX/Q_INDEX_DONE variables must be done using spinlock protection. It is best to manage this completely from rt2x00queue.c. For safely looping through all entries in the queue, the function rt2x00queue_for_each_entry is added which will walk from from a index range in a safe manner. This also fixes rt2x00usb which walked the entries list from 0 to length to kill each entry (killing entries must be done from Q_INDEX_DONE to Q_INDEX to enforce TX status reporting to occur in the correct order. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 4 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 45 +++++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00queue.h | 16 +++++++ drivers/net/wireless/rt2x00/rt2x00usb.c | 75 +++++++++---------------------- 4 files changed, 83 insertions(+), 57 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index af1c6914d7b4..a5e58705b49b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -629,7 +629,7 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry, static void rt2800pci_kick_tx_queue(struct data_queue *queue) { struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; - unsigned int idx = queue->index[Q_INDEX]; + struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); unsigned int qidx = 0; if (queue->qid == QID_MGMT) @@ -637,7 +637,7 @@ static void rt2800pci_kick_tx_queue(struct data_queue *queue) else qidx = queue->qid; - rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), idx); + rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx); } static void rt2800pci_kill_tx_queue(struct data_queue *queue) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 189eaf72967e..7fb9b6179af1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -625,6 +625,51 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, return 0; } +void rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, + void (*fn)(struct queue_entry *entry)) +{ + unsigned long irqflags; + unsigned int index_start; + unsigned int index_end; + unsigned int i; + + if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) { + ERROR(queue->rt2x00dev, + "Entry requested from invalid index range (%d - %d)\n", + start, end); + return; + } + + /* + * Only protect the range we are going to loop over, + * if during our loop a extra entry is set to pending + * it should not be kicked during this run, since it + * is part of another TX operation. + */ + spin_lock_irqsave(&queue->lock, irqflags); + index_start = queue->index[start]; + index_end = queue->index[end]; + spin_unlock_irqrestore(&queue->lock, irqflags); + + /* + * Start from the TX done pointer, this guarentees that we will + * send out all frames in the correct order. + */ + if (index_start < index_end) { + for (i = index_start; i < index_end; i++) + fn(&queue->entries[i]); + } else { + for (i = index_start; i < queue->limit; i++) + fn(&queue->entries[i]); + + for (i = 0; i < index_end; i++) + fn(&queue->entries[i]); + } +} +EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry); + struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 2d3bf843735f..46a3be1d82b9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -570,6 +570,22 @@ struct data_queue_desc { #define txall_queue_for_each(__dev, __entry) \ queue_loop(__entry, (__dev)->tx, queue_end(__dev)) +/** + * rt2x00queue_for_each_entry - Loop through all entries in the queue + * @queue: Pointer to @data_queue + * @start: &enum queue_index Pointer to start index + * @end: &enum queue_index Pointer to end index + * @fn: The function to call for each &struct queue_entry + * + * This will walk through all entries in the queue, in chronological + * order. This means it will start at the current @start pointer + * and will walk through the queue until it reaches the @end pointer. + */ +void rt2x00queue_for_each_entry(struct data_queue *queue, + enum queue_index start, + enum queue_index end, + void (*fn)(struct queue_entry *entry)); + /** * rt2x00queue_empty - Check if the queue is empty. * @queue: Queue to check if empty. diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 1d2eb461329f..6cc7aa418d87 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -225,7 +225,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); } -static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) +static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -252,69 +252,34 @@ static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry) void rt2x00usb_kick_tx_queue(struct data_queue *queue) { - unsigned long irqflags; - unsigned int index; - unsigned int index_done; - unsigned int i; - - /* - * Only protect the range we are going to loop over, - * if during our loop a extra entry is set to pending - * it should not be kicked during this run, since it - * is part of another TX operation. - */ - spin_lock_irqsave(&queue->lock, irqflags); - index = queue->index[Q_INDEX]; - index_done = queue->index[Q_INDEX_DONE]; - spin_unlock_irqrestore(&queue->lock, irqflags); - - /* - * Start from the TX done pointer, this guarentees that we will - * send out all frames in the correct order. - */ - if (index_done < index) { - for (i = index_done; i < index; i++) - rt2x00usb_kick_tx_entry(&queue->entries[i]); - } else { - for (i = index_done; i < queue->limit; i++) - rt2x00usb_kick_tx_entry(&queue->entries[i]); - - for (i = 0; i < index; i++) - rt2x00usb_kick_tx_entry(&queue->entries[i]); - } + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00usb_kick_tx_entry); } EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue); -void rt2x00usb_kill_tx_queue(struct data_queue *queue) +static void rt2x00usb_kill_tx_entry(struct queue_entry *entry) { - struct queue_entry_priv_usb *entry_priv; - struct queue_entry_priv_usb_bcn *bcn_priv; - unsigned int i; - bool kill_guard; + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + struct queue_entry_priv_usb *entry_priv = entry->priv_data; + struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; - /* - * When killing the beacon queue, we must also kill - * the beacon guard byte. - */ - kill_guard = - (queue->qid == QID_BEACON) && - (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &queue->rt2x00dev->flags)); + if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + return; + + usb_kill_urb(entry_priv->urb); /* - * Cancel all entries. + * Kill guardian urb (if required by driver). */ - for (i = 0; i < queue->limit; i++) { - entry_priv = queue->entries[i].priv_data; - usb_kill_urb(entry_priv->urb); + if ((entry->queue->qid == QID_BEACON) && + (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) + usb_kill_urb(bcn_priv->guardian_urb); +} - /* - * Kill guardian urb (if required by driver). - */ - if (kill_guard) { - bcn_priv = queue->entries[i].priv_data; - usb_kill_urb(bcn_priv->guardian_urb); - } - } +void rt2x00usb_kill_tx_queue(struct data_queue *queue) +{ + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, + rt2x00usb_kill_tx_entry); } EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue); -- cgit v1.2.3 From 54e34fbb6fae67b3dba4c2600d3c65aca81635ae Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:54:41 +0200 Subject: rt2x00: Remove Q_INDEX_CRYPTO and ENTRY_OWNER_DEVICE_CRYPTO Q_INDEX_CRYPTO and ENTRY_OWNER_DEVICE_CRYPTO where initially added with the plan to implement hardware encryption for rt2500pci. However there are no plans to do so anymore as the crypto mechanism in rt2500pci is very different then any other Ralink device. So we can now safely remove the definitions, and don't think about this feature anymore. :) Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 7 +++---- drivers/net/wireless/rt2x00/rt2x00queue.h | 7 ------- 2 files changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index b0498e7e7aae..74f0d679883e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -338,16 +338,15 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, return -ENOMEM; temp = data + - sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n"); + sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\n"); queue_for_each(intf->rt2x00dev, queue) { spin_lock_irqsave(&queue->lock, irqflags); - temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, + temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, queue->count, queue->limit, queue->length, queue->index[Q_INDEX], - queue->index[Q_INDEX_DONE], - queue->index[Q_INDEX_CRYPTO]); + queue->index[Q_INDEX_DONE]); spin_unlock_irqrestore(&queue->lock, irqflags); } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 46a3be1d82b9..c451a50f7a01 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -360,9 +360,6 @@ struct txentry_desc { * @ENTRY_OWNER_DEVICE_DATA: This entry is owned by the device for data * transfer (either TX or RX depending on the queue). The entry should * only be touched after the device has signaled it is done with it. - * @ENTRY_OWNER_DEVICE_CRYPTO: This entry is owned by the device for data - * encryption or decryption. The entry should only be touched after - * the device has signaled it is done with it. * @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting * for the signal to start sending. * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured @@ -372,7 +369,6 @@ struct txentry_desc { enum queue_entry_flags { ENTRY_BCN_ASSIGNED, ENTRY_OWNER_DEVICE_DATA, - ENTRY_OWNER_DEVICE_CRYPTO, ENTRY_DATA_PENDING, ENTRY_DATA_IO_FAILED }; @@ -408,15 +404,12 @@ struct queue_entry { * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by * the hardware and for which we need to run the txdone handler. If this * entry is not owned by the hardware the queue is considered to be empty. - * @Q_INDEX_CRYPTO: Index pointer to the next entry which encryption/decription - * will be completed by the hardware next. * @Q_INDEX_MAX: Keep last, used in &struct data_queue to determine the size * of the index array. */ enum queue_index { Q_INDEX, Q_INDEX_DONE, - Q_INDEX_CRYPTO, Q_INDEX_MAX, }; -- cgit v1.2.3 From 21595bd50dd1ef16cf0dce33835caaf5ab458d4c Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:55:01 +0200 Subject: rt2x00: Fix rt2800 retry calculation The retry count for a frame is calculated by the realized MCS rate subtracting of the requested MCS rate. However during TX done reporting we accidently override the requested MCS rate with the realized MCS rate. This causes the retry count to be reset to 0 always, and feeding invalid rate information into minstrel_ht. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3a150d3a9d9f..8706702b69a2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -650,7 +650,6 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) txdesc.flags = 0; rt2x00_desc_read(txwi, 0, &word); mcs = rt2x00_get_field32(word, TXWI_W0_MCS); - mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); /* -- cgit v1.2.3 From b9a07ae9d9e09662013992088fd58ffbcb2f9a30 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:55:22 +0200 Subject: rt2x00: Merge rt2800{pci/usb} radio enabling/disabling code to rt2800lib The functions rt2800pci_enable_radio and rt2800usb_disable_radio are almost equal and can be merged into rt2800lib. This reduces the number of functions which must be exported from rt2800lib to the drivers at the same time. Also rt2800pci_disable_radio and rt2800usb_disable_radio are almost equal and can be merged into rt2800lib in a similar fashion. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 103 ++++++++++++++++++++++++++++++-- drivers/net/wireless/rt2x00/rt2800lib.h | 8 +-- drivers/net/wireless/rt2x00/rt2800pci.c | 69 +-------------------- drivers/net/wireless/rt2x00/rt2800usb.c | 72 +--------------------- 4 files changed, 107 insertions(+), 145 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 8706702b69a2..b2f9b04134eb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1655,7 +1655,7 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner); /* * Initialization functions. */ -int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) +static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; u16 eeprom; @@ -2025,7 +2025,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) return 0; } -EXPORT_SYMBOL_GPL(rt2800_init_registers); static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev) { @@ -2068,7 +2067,7 @@ static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev) return -EACCES; } -int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) +static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) { unsigned int i; u16 eeprom; @@ -2163,7 +2162,6 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) return 0; } -EXPORT_SYMBOL_GPL(rt2800_init_bbp); static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, bool bw40, u8 rfcsr24, u8 filter_target) @@ -2225,7 +2223,7 @@ static u8 rt2800_init_rx_filter(struct rt2x00_dev *rt2x00dev, return rfcsr24; } -int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) +static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) { u8 rfcsr; u8 bbp; @@ -2479,7 +2477,100 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) return 0; } -EXPORT_SYMBOL_GPL(rt2800_init_rfcsr); + +int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + u16 word; + + /* + * Initialize all registers. + */ + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || + rt2800_init_registers(rt2x00dev) || + rt2800_init_bbp(rt2x00dev) || + rt2800_init_rfcsr(rt2x00dev))) + return -EIO; + + /* + * Send signal to firmware during boot time. + */ + rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); + + if (rt2x00_is_usb(rt2x00dev) && + (rt2x00_rt(rt2x00dev, RT3070) || + rt2x00_rt(rt2x00dev, RT3071) || + rt2x00_rt(rt2x00dev, RT3572))) { + udelay(200); + rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); + udelay(10); + } + + /* + * Enable RX. + */ + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + udelay(50); + + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); + rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + /* + * Initialize LED control + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); + rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); + rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, + word & 0xff, (word >> 8) & 0xff); + + rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); + rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, + word & 0xff, (word >> 8) & 0xff); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_enable_radio); + +void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + + rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); + rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); + rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); + + /* Wait for DMA, ignore error */ + rt2800_wait_wpdma_ready(rt2x00dev); + + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 0); + rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); + + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); + rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); +} +EXPORT_SYMBOL_GPL(rt2800_disable_radio); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) { diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 3b572c63382d..deb10b14157b 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -140,6 +140,8 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1); +int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); + int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev, const u8 *data, const size_t len); int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, @@ -176,10 +178,8 @@ void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual); void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, const u32 count); -int rt2800_init_registers(struct rt2x00_dev *rt2x00dev); -int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev); -int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev); -int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); +int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev); +void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev); void rt2800_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index a5e58705b49b..4d93204b221f 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -399,78 +399,18 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev) static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev) { - u32 reg; - u16 word; - - /* - * Initialize all registers. - */ if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800pci_init_queues(rt2x00dev) || - rt2800_init_registers(rt2x00dev) || - rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800_init_bbp(rt2x00dev) || - rt2800_init_rfcsr(rt2x00dev))) + rt2800pci_init_queues(rt2x00dev))) return -EIO; - /* - * Send signal to firmware during boot time. - */ - rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); - - /* - * Enable RX. - */ - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 0); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_WP_DMA_BURST_SIZE, 2); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - /* - * Initialize LED control - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, - word & 0xff, (word >> 8) & 0xff); - - return 0; + return rt2800_enable_radio(rt2x00dev); } static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_RX_DMA_BUSY, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); + rt2800_disable_radio(rt2x00dev); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001280); @@ -486,9 +426,6 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00); - - /* Wait for DMA, ignore error */ - rt2800_wait_wpdma_ready(rt2x00dev); } static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 02f95892aa07..82ae58e0c5d7 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -101,19 +101,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev, msleep(10); rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0); - /* - * Send signal to firmware during boot time. - */ - rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0); - - if (rt2x00_rt(rt2x00dev, RT3070) || - rt2x00_rt(rt2x00dev, RT3071) || - rt2x00_rt(rt2x00dev, RT3572)) { - udelay(200); - rt2800_mcu_request(rt2x00dev, MCU_CURRENT, 0, 0, 0); - udelay(10); - } - return 0; } @@ -173,30 +160,10 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 word; - /* - * Initialize all registers. - */ - if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) || - rt2800_init_registers(rt2x00dev) || - rt2800_init_bbp(rt2x00dev) || - rt2800_init_rfcsr(rt2x00dev))) + if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev))) return -EIO; - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - udelay(50); - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 1); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 1); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_read(rt2x00dev, USB_DMA_CFG, ®); rt2x00_set_field32(®, USB_DMA_CFG_PHY_CLEAR, 0); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_EN, 0); @@ -211,45 +178,12 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); - rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_TX, 1); - rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, 1); - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); - - /* - * Initialize LED control - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff, - word & 0xff, (word >> 8) & 0xff); - - rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word); - rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff, - word & 0xff, (word >> 8) & 0xff); - - return 0; + return rt2800_enable_radio(rt2x00dev); } static void rt2800usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - u32 reg; - - rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0); - rt2x00_set_field32(®, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0); - rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); - - rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0); - rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0); - - /* Wait for DMA, ignore error */ - rt2800_wait_wpdma_ready(rt2x00dev); - + rt2800_disable_radio(rt2x00dev); rt2x00usb_disable_radio(rt2x00dev); } -- cgit v1.2.3 From 46323e112ce2a0fdaf2dd5389f95b248576b8fda Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:55:43 +0200 Subject: rt2x00: Fix channel configuration for RF3052 We missed a check for RF3052 in the config_channel configuration function. As a result the channel is not properly configured for RF3052 devices. This also requires rt2800_config_channel_rf3xxx to support 5GHz channels, so we must apply the TXPOWER_A_TO_DEV and TXPOWER_G_TO_DEV conversions during rt2800_config_channel() Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b2f9b04134eb..cbab2e126167 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1244,8 +1244,7 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, if (info->tx_power1 < 0) info->tx_power1 += 7; - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power1)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->tx_power1); rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, (info->tx_power2 >= 0)); @@ -1253,13 +1252,10 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, if (info->tx_power2 < 0) info->tx_power2 += 7; - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, - TXPOWER_A_TO_DEV(info->tx_power2)); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->tx_power2); } else { - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power1)); - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, - TXPOWER_G_TO_DEV(info->tx_power2)); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->tx_power1); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->tx_power2); } rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); @@ -1299,13 +1295,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, - TXPOWER_G_TO_DEV(info->tx_power1)); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->tx_power1); rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, - TXPOWER_G_TO_DEV(info->tx_power2)); + rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->tx_power2); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); @@ -1329,10 +1323,19 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, unsigned int tx_pin; u8 bbp; + if (rf->channel <= 14) { + info->tx_power1 = TXPOWER_G_TO_DEV(info->tx_power1); + info->tx_power2 = TXPOWER_G_TO_DEV(info->tx_power2); + } else { + info->tx_power1 = TXPOWER_A_TO_DEV(info->tx_power1); + info->tx_power2 = TXPOWER_A_TO_DEV(info->tx_power2); + } + if (rt2x00_rf(rt2x00dev, RF2020) || rt2x00_rf(rt2x00dev, RF3020) || rt2x00_rf(rt2x00dev, RF3021) || - rt2x00_rf(rt2x00dev, RF3022)) + rt2x00_rf(rt2x00dev, RF3022) || + rt2x00_rf(rt2x00dev, RF3052)) rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info); else rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); -- cgit v1.2.3 From 8d1331b37d5b656a7a8e561f8e9d7661dd00c910 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 23 Aug 2010 19:56:07 +0200 Subject: rt2x00: Fix max TX power settings During initialization each driver reads the default TX power for each individual channel. However mac80211 only accepts the maximum value (which is also handled as default value). As a result, the TX power of the device was being limited to the default value, which is often quite low compared to the real maximum acceptable value. This patch allows each driver to set the maximum value on a per-channel basis which is forwarded to mac80211. The default value will be preserved for now, in case we want to update mac80211 to differentiate between the maximum and default txpower. This fixes bug complaining about limited TX power values like: https://bugzilla.kernel.org/show_bug.cgi?id=16358 Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 6 ++- drivers/net/wireless/rt2x00/rt2500pci.c | 12 ++++-- drivers/net/wireless/rt2x00/rt2500usb.c | 12 ++++-- drivers/net/wireless/rt2x00/rt2800.h | 7 ++++ drivers/net/wireless/rt2x00/rt2800lib.c | 65 ++++++++++++++++++++------------- drivers/net/wireless/rt2x00/rt2x00.h | 5 ++- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 12 ++++-- drivers/net/wireless/rt2x00/rt73usb.c | 12 ++++-- 9 files changed, 86 insertions(+), 47 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b86b6132a69c..e3005ff5ae98 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1487,8 +1487,10 @@ static int rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = TXPOWER_FROM_DEV(MAX_TXPOWER); + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 21f45810fd1e..1e6a91b8d3df 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1801,12 +1801,16 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = DEFAULT_TXPOWER; + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = DEFAULT_TXPOWER; + } } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 8722464944f5..71d8d821c4e1 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1706,12 +1706,16 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = DEFAULT_TXPOWER; + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = DEFAULT_TXPOWER; + } } return 0; diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index cf1f16bfcd5e..5c006a795346 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1858,6 +1858,13 @@ struct mac_iveiv_entry { #define EEPROM_RSSI_A2_OFFSET2 FIELD16(0x00ff) #define EEPROM_RSSI_A2_LNA_A2 FIELD16(0xff00) +/* + * EEPROM Maximum TX power values + */ +#define EEPROM_MAX_TX_POWER 0x0027 +#define EEPROM_MAX_TX_POWER_24GHZ FIELD16(0x00ff) +#define EEPROM_MAX_TX_POWER_5GHZ FIELD16(0xff00) + /* * EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power. * This is delta in 40MHZ. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index cbab2e126167..ecbd07a78edb 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1239,23 +1239,23 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, * double meaning, and we should set a 7DBm boost flag. */ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A_7DBM_BOOST, - (info->tx_power1 >= 0)); + (info->default_power1 >= 0)); - if (info->tx_power1 < 0) - info->tx_power1 += 7; + if (info->default_power1 < 0) + info->default_power1 += 7; - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->tx_power1); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_A, info->default_power1); rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A_7DBM_BOOST, - (info->tx_power2 >= 0)); + (info->default_power2 >= 0)); - if (info->tx_power2 < 0) - info->tx_power2 += 7; + if (info->default_power2 < 0) + info->default_power2 += 7; - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->tx_power2); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_A, info->default_power2); } else { - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->tx_power1); - rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->tx_power2); + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER_G, info->default_power1); + rt2x00_set_field32(&rf->rf4, RF4_TXPOWER_G, info->default_power2); } rt2x00_set_field32(&rf->rf4, RF4_HT40, conf_is_ht40(conf)); @@ -1295,11 +1295,11 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 6, rfcsr); rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->tx_power1); + rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER, info->default_power1); rt2800_rfcsr_write(rt2x00dev, 12, rfcsr); rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->tx_power2); + rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER, info->default_power2); rt2800_rfcsr_write(rt2x00dev, 13, rfcsr); rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr); @@ -1324,11 +1324,11 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, u8 bbp; if (rf->channel <= 14) { - info->tx_power1 = TXPOWER_G_TO_DEV(info->tx_power1); - info->tx_power2 = TXPOWER_G_TO_DEV(info->tx_power2); + info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1); + info->default_power2 = TXPOWER_G_TO_DEV(info->default_power2); } else { - info->tx_power1 = TXPOWER_A_TO_DEV(info->tx_power1); - info->tx_power2 = TXPOWER_A_TO_DEV(info->tx_power2); + info->default_power1 = TXPOWER_A_TO_DEV(info->default_power1); + info->default_power2 = TXPOWER_A_TO_DEV(info->default_power2); } if (rt2x00_rf(rt2x00dev, RF2020) || @@ -2729,6 +2729,13 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) default_lna_gain); rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_A2, word); + rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &word); + if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_24GHZ) == 0xff) + rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_24GHZ, MAX_G_TXPOWER); + if (rt2x00_get_field16(word, EEPROM_MAX_TX_POWER_5GHZ) == 0xff) + rt2x00_set_field16(&word, EEPROM_MAX_TX_POWER_5GHZ, MAX_A_TXPOWER); + rt2x00_eeprom_write(rt2x00dev, EEPROM_MAX_TX_POWER, word); + return 0; } EXPORT_SYMBOL_GPL(rt2800_validate_eeprom); @@ -2968,9 +2975,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; struct channel_info *info; - char *tx_power1; - char *tx_power2; + char *default_power1; + char *default_power2; unsigned int i; + unsigned short max_power; u16 eeprom; /* @@ -3084,21 +3092,26 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); + rt2x00_eeprom_read(rt2x00dev, EEPROM_MAX_TX_POWER, &eeprom); + max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_24GHZ); + default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG1); + default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_BG2); for (i = 0; i < 14; i++) { - info[i].tx_power1 = TXPOWER_G_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_G_FROM_DEV(tx_power2[i]); + info[i].max_power = max_power; + info[i].default_power1 = TXPOWER_G_FROM_DEV(default_power1[i]); + info[i].default_power2 = TXPOWER_G_FROM_DEV(default_power2[i]); } if (spec->num_channels > 14) { - tx_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); - tx_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); + max_power = rt2x00_get_field16(eeprom, EEPROM_MAX_TX_POWER_5GHZ); + default_power1 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A1); + default_power2 = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A2); for (i = 14; i < spec->num_channels; i++) { - info[i].tx_power1 = TXPOWER_A_FROM_DEV(tx_power1[i]); - info[i].tx_power2 = TXPOWER_A_FROM_DEV(tx_power2[i]); + info[i].max_power = max_power; + info[i].default_power1 = TXPOWER_A_FROM_DEV(default_power1[i]); + info[i].default_power2 = TXPOWER_A_FROM_DEV(default_power2[i]); } } diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 69308a0df74f..762f6b4e7afc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -213,8 +213,9 @@ struct channel_info { unsigned int flags; #define GEOGRAPHY_ALLOWED 0x00000001 - short tx_power1; - short tx_power2; + short max_power; + short default_power1; + short default_power2; }; /* diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e692608bee8b..580595ba5683 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -711,7 +711,7 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, for (i = 0; i < spec->num_channels; i++) { rt2x00lib_channel(&channels[i], spec->channels[i].channel, - spec->channels_info[i].tx_power1, i); + spec->channels_info[i].max_power, i); } /* diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ae4698e18729..8f017ad8c3db 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2656,13 +2656,17 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } } return 0; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ab9389439d75..ee2c52fd0d73 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2090,13 +2090,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) spec->channels_info = info; tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START); - for (i = 0; i < 14; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 0; i < 14; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } if (spec->num_channels > 14) { tx_power = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START); - for (i = 14; i < spec->num_channels; i++) - info[i].tx_power1 = TXPOWER_FROM_DEV(tx_power[i]); + for (i = 14; i < spec->num_channels; i++) { + info[i].max_power = MAX_TXPOWER; + info[i].default_power1 = TXPOWER_FROM_DEV(tx_power[i]); + } } return 0; -- cgit v1.2.3 From f8d8b7a13d3d61f99bf3dc5c9650f87f9818d7a7 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Mon, 23 Aug 2010 23:02:22 +0200 Subject: rt2x00: fix "buffer size not provably correct" build warning rt2x00 debugfs interface doesn't check the size of the data coming from userspace, leading to a build warning. Fix That. v2: return EINVAL if input is too long Signed-off-by: Arnaud Patard Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 74f0d679883e..daf7f950a28f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -480,6 +480,9 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ if (index >= debug->__name.word_count) \ return -EINVAL; \ \ + if (length > sizeof(line)) \ + return -EINVAL; \ + \ if (copy_from_user(line, buf, length)) \ return -EFAULT; \ \ -- cgit v1.2.3 From a908a743822d2eed2d8394bb607bb9db5934dcfc Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 30 Aug 2010 21:12:24 +0200 Subject: rt2x00: Rename txentry_desc.queue -> txentry_desc.qid Variables containing queue ids are called qid everywhere else, hence rename the queue field in txentry_desc to qid as well. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.h | 4 ++-- drivers/net/wireless/rt2x00/rt61pci.c | 6 +++--- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ecbd07a78edb..25c44cfd7452 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -469,7 +469,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, txdesc->key_idx : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, txdesc->length); - rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1); + rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->qid + 1); rt2x00_desc_write(txwi, 1, word); /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7fb9b6179af1..ecf57635ae51 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -312,7 +312,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Initialize information from queue */ - txdesc->queue = entry->queue->qid; + txdesc->qid = entry->queue->qid; txdesc->cw_min = entry->queue->cw_min; txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index c451a50f7a01..0e38a911195d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -296,7 +296,7 @@ enum txentry_desc_flags { * Summary of information for the frame descriptor before sending a TX frame. * * @flags: Descriptor flags (See &enum queue_entry_flags). - * @queue: Queue identification (See &enum data_queue_qid). + * @qid: Queue identification (See &enum data_queue_qid). * @length: Length of the entire frame. * @header_length: Length of 802.11 header. * @length_high: PLCP length high word. @@ -322,7 +322,7 @@ enum txentry_desc_flags { struct txentry_desc { unsigned long flags; - enum data_queue_qid queue; + enum data_queue_qid qid; u16 length; u16 header_length; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8f017ad8c3db..18829b2eccc3 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1778,7 +1778,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); @@ -1809,7 +1809,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); - if (txdesc->queue != QID_BEACON) { + if (txdesc->qid != QID_BEACON) { rt2x00_desc_read(txd, 6, &word); rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); @@ -1856,7 +1856,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, */ skbdesc->desc = txd; skbdesc->desc_len = - (txdesc->queue == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE; + (txdesc->qid == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE; } /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ee2c52fd0d73..ac8f6d0b8f49 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1463,7 +1463,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 0, word); rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid); rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); -- cgit v1.2.3 From 2035c0cf8f637e88cdd338c15570a7ad42afc552 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Mon, 30 Aug 2010 21:12:47 +0200 Subject: rt2x00: Update rt2800 comments regarding AMPDU and PACKET_ID in TXWI Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 5c006a795346..70a5cb86405b 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1953,6 +1953,8 @@ struct mac_iveiv_entry { * TX_OP: 0:HT TXOP rule , 1:PIFS TX ,2:Backoff, 3:sifs * BW: Channel bandwidth 20MHz or 40 MHz * STBC: 1: STBC support MCS =0-7, 2,3 : RESERVED + * AMPDU: 1: this frame is eligible for AMPDU aggregation, the hw will + * aggregate consecutive frames with the same RA and QoS TID. */ #define TXWI_W0_FRAG FIELD32(0x00000001) #define TXWI_W0_MIMO_PS FIELD32(0x00000002) @@ -1976,7 +1978,9 @@ struct mac_iveiv_entry { * WIRELESS_CLI_ID: Client ID for WCID table access * MPDU_TOTAL_BYTE_COUNT: Length of 802.11 frame * PACKETID: Will be latched into the TX_STA_FIFO register once the according - * frame was processed. 0: Don't report tx status for this frame. + * frame was processed. If multiple frames are aggregated together + * (AMPDU==1) the reported tx status will always contain the packet + * id of the first frame. 0: Don't report tx status for this frame. */ #define TXWI_W1_ACK FIELD32(0x00000001) #define TXWI_W1_NSEQ FIELD32(0x00000002) -- cgit v1.2.3 From 5ffddc498c700bb45ea55efc37746cb28d601766 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:13:08 +0200 Subject: rt2x00: Add rt2800_wait_csr_ready Similar to rt2800_wait_wpdma_ready() we can add a function to waiting until the CSR is ready. This centralizes some additional code into rt2800lib. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 28 ++++++++++++++++++---------- drivers/net/wireless/rt2x00/rt2800lib.h | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 12 +----------- 3 files changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 25c44cfd7452..7c68bf35951f 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -255,6 +255,23 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2800_mcu_request); +int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i = 0; + u32 reg; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + if (reg && reg != ~0) + return 0; + msleep(1); + } + + ERROR(rt2x00dev, "Unstable hardware.\n"); + return -EBUSY; +} +EXPORT_SYMBOL_GPL(rt2800_wait_csr_ready); + int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) { unsigned int i; @@ -370,17 +387,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, /* * Wait for stable hardware. */ - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg && reg != ~0) - break; - msleep(1); - } - - if (i == REGISTER_BUSY_COUNT) { - ERROR(rt2x00dev, "Unstable hardware.\n"); + if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - } if (rt2x00_is_pci(rt2x00dev)) rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000002); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index deb10b14157b..986229c06c19 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -140,6 +140,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1); +int rt2800_wait_csr_ready(struct rt2x00_dev *rt2x00dev); int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev); int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 82ae58e0c5d7..b1a8e943750b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -122,22 +122,12 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - int i; /* * Wait until BBP and RF are ready. */ - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (reg && reg != ~0) - break; - msleep(1); - } - - if (i == REGISTER_BUSY_COUNT) { - ERROR(rt2x00dev, "Unstable hardware.\n"); + if (rt2800_wait_csr_ready(rt2x00dev)) return -EBUSY; - } rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); -- cgit v1.2.3 From 3613884d96b186f58a77af05122f84167604aad9 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:13:30 +0200 Subject: rt2x00: Validate TX status results with current data entry Instead of printing a warning when the PID, ACK, or WCID of an entry don't match the TX status report, we should skip the entry to search for the entry which actually does match the TX status data. This reduces the number of watchdog errors on the TX queues for rt2800usb, and seems to improve the reliability of the TX flow a bit. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 73 ++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 7c68bf35951f..1a8170068b1c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -581,6 +581,49 @@ void rt2800_process_rxwi(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_process_rxwi); +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; + + 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); + + /* + * 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)) { + rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); + return false; + } + + /* + * Validate if this TX status report is intended for + * this entry by comparing the WCID/ACK/PID fields. + */ + txwi = rt2800_drv_get_txwi(entry); + + rt2x00_desc_read(txwi, 1, &word); + 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) || (pid != tx_pid)) { + WARNING(entry->queue->rt2x00dev, + "TX status report missed for queue %d entry %d\n", + entry->queue->qid, entry->entry_idx); + rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN); + return false; + } + + return true; +} + void rt2800_txdone(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; @@ -589,8 +632,8 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) struct txdone_entry_desc txdesc; u32 word; u32 reg; - int wcid, ack, pid, tx_wcid, tx_ack, tx_pid; u16 mcs, real_mcs; + u8 pid; int i; /* @@ -607,18 +650,15 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) break; - 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); - /* * Skip this entry when it contains an invalid * queue identication number. */ - if (pid <= 0 || pid > QID_RX) + pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1; + if (pid >= QID_RX) continue; - queue = rt2x00queue_get_queue(rt2x00dev, pid - 1); + queue = rt2x00queue_get_queue(rt2x00dev, pid); if (unlikely(!queue)) continue; @@ -627,35 +667,22 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) * order. We first check that the queue is not empty. */ entry = NULL; + txwi = NULL; while (!rt2x00queue_empty(queue)) { entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - if (!test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) + if (rt2800_txdone_entry_check(entry, reg)) break; - - rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE); } if (!entry || rt2x00queue_empty(queue)) break; - /* - * Check if we got a match by looking at WCID/ACK/PID - * fields - */ - txwi = rt2800_drv_get_txwi(entry); - - rt2x00_desc_read(txwi, 1, &word); - 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) || (pid != tx_pid)) - WARNING(rt2x00dev, "invalid TX_STA_FIFO content"); /* * Obtain the status about this packet. */ txdesc.flags = 0; + txwi = rt2800_drv_get_txwi(entry); rt2x00_desc_read(txwi, 0, &word); mcs = rt2x00_get_field32(word, TXWI_W0_MCS); real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS); -- cgit v1.2.3 From b9eca24209a59ef0a8c3cbbbb94b8c76d4b3aae3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:13:54 +0200 Subject: rt2x00: Wakeup hardware before loading firmware According to the legacy drivers the AUTOWAKEUP_CFG register must be reset to 0 before loading the firmware. Instead of during rt2800{pci,usb}_write_firmware it must actually be done in rt2800_load_firmware() before resetting the WPDMA_GLO_CFG and PWR_PIN_CFG registers. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++++ drivers/net/wireless/rt2x00/rt2800pci.c | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 1a8170068b1c..a5455f46cec1 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -384,6 +384,12 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, unsigned int i; u32 reg; + /* + * If driver doesn't wake up firmware here, + * rt2800_load_firmware will hang forever when interface is up again. + */ + rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); + /* * Wait for stable hardware. */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 4d93204b221f..2bcb1507e3ac 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -196,8 +196,6 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, 0x00000000); - /* * enable Host program ram write selection */ -- cgit v1.2.3 From c600c826a6f4e35512955a5e9a22b0baa741b455 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:14:15 +0200 Subject: rt2x00: Don't set unicast/BSSID masks when clearning MAC or BSSID When configuring the MAC_ADDR or MAC_BSSID with an empty address, the UNICAST_TO_ME_MASK and BSS_ID_MASK must also be reset to prevent invalid interpretation of the addresses. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a5455f46cec1..f90e932b3cb4 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1135,19 +1135,23 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, } if (flags & CONFIG_UPDATE_MAC) { - reg = le32_to_cpu(conf->mac[1]); - rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); - conf->mac[1] = cpu_to_le32(reg); + if (!is_zero_ether_addr((const u8 *)conf->mac)) { + reg = le32_to_cpu(conf->mac[1]); + rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); + conf->mac[1] = cpu_to_le32(reg); + } rt2800_register_multiwrite(rt2x00dev, MAC_ADDR_DW0, conf->mac, sizeof(conf->mac)); } if (flags & CONFIG_UPDATE_BSSID) { - reg = le32_to_cpu(conf->bssid[1]); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); - rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); - conf->bssid[1] = cpu_to_le32(reg); + if (!is_zero_ether_addr((const u8 *)conf->bssid)) { + reg = le32_to_cpu(conf->bssid[1]); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); + rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7); + conf->bssid[1] = cpu_to_le32(reg); + } rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0, conf->bssid, sizeof(conf->bssid)); -- cgit v1.2.3 From e0540879db337b18ef7c580234038ff62c8cd381 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:14:38 +0200 Subject: rt2x00: Set PWR_PIN_CFG during initialization Add PWR_PIN_CFG initialization for rt2800usb at the same point as rt2800pci. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index b1a8e943750b..d275549a1fb9 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -132,6 +132,8 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, ®); rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000); + rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003); + rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_CSR, 1); rt2x00_set_field32(®, MAC_SYS_CTRL_RESET_BBP, 1); -- cgit v1.2.3 From 0e3afe5b20c4ccdeff5178c62b557a917945a828 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:14:56 +0200 Subject: rt2x00: Correctly kill beacon queue USB devices upload their beacon and then automatically send it out every beacon interval. However when killing a TX queue we only kill the URB and not the actual transmission of the beacon. This will reset the Beacon register to prevent any beacons from being transmitted. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 10 +++++++++- drivers/net/wireless/rt2x00/rt2800usb.c | 10 +++++++++- drivers/net/wireless/rt2x00/rt73usb.c | 10 +++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 71d8d821c4e1..a161e9e33b73 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1196,6 +1196,14 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry) return length; } +static void rt2500usb_kill_tx_queue(struct data_queue *queue) +{ + if (queue->qid == QID_BEACON) + rt2500usb_register_write(queue->rt2x00dev, TXRX_CSR19, 0); + + rt2x00usb_kill_tx_queue(queue); +} + /* * RX control handlers */ @@ -1794,7 +1802,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .write_beacon = rt2500usb_write_beacon, .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, - .kill_tx_queue = rt2x00usb_kill_tx_queue, + .kill_tx_queue = rt2500usb_kill_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, .config_shared_key = rt2500usb_config_key, .config_pairwise_key = rt2500usb_config_key, diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index d275549a1fb9..3dff56ec195a 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -335,6 +335,14 @@ static void rt2800usb_work_txdone(struct work_struct *work) } } +static void rt2800usb_kill_tx_queue(struct data_queue *queue) +{ + if (queue->qid == QID_BEACON) + rt2x00usb_register_write(queue->rt2x00dev, BCN_TIME_CFG, 0); + + rt2x00usb_kill_tx_queue(queue); +} + /* * RX control handlers */ @@ -533,7 +541,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .write_beacon = rt2800_write_beacon, .get_tx_data_len = rt2800usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, - .kill_tx_queue = rt2x00usb_kill_tx_queue, + .kill_tx_queue = rt2800usb_kill_tx_queue, .fill_rxdone = rt2800usb_fill_rxdone, .config_shared_key = rt2800_config_shared_key, .config_pairwise_key = rt2800_config_pairwise_key, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ac8f6d0b8f49..df0ef3f70f1e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1573,6 +1573,14 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry) return length; } +static void rt73usb_kill_tx_queue(struct data_queue *queue) +{ + if (queue->qid == QID_BEACON) + rt2x00usb_register_write(queue->rt2x00dev, TXRX_CSR9, 0); + + rt2x00usb_kill_tx_queue(queue); +} + /* * RX control handlers */ @@ -2262,7 +2270,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .write_beacon = rt73usb_write_beacon, .get_tx_data_len = rt73usb_get_tx_data_len, .kick_tx_queue = rt2x00usb_kick_tx_queue, - .kill_tx_queue = rt2x00usb_kill_tx_queue, + .kill_tx_queue = rt73usb_kill_tx_queue, .fill_rxdone = rt73usb_fill_rxdone, .config_shared_key = rt73usb_config_shared_key, .config_pairwise_key = rt73usb_config_pairwise_key, -- cgit v1.2.3 From 652a9dd2a0c07251e328519cc23f1316ab13ed51 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:15:19 +0200 Subject: rt2x00: Split watchdog check into a DMA and STATUS timeout The watchdog for rt2800usb triggers frequently causing all URB's to be canceled often enough to interrupt the normal TX flow. More research indicated that not the URB upload to the USB host were hanging, but instead the TX status reports. To correctly detect what is going on, we introduce Q_INDEX_DMA_DONE which is an index counter between Q_INDEX_DONE and Q_INDEX and indicates if the frame has been transfered to the device. This also requires the rt2x00queue timeout functions to be updated to differentiate between a DMA timeout (time between Q_INDEX and Q_INDEX_DMA_DONE timeout) and a STATUS timeout (time between Q_INDEX_DMA_DONE and Q_INDEX_DONE timeout) All Q_INDEX_DMA_DONE code was taken from the RFC from Helmut Schaa for the implementation for watchdog for rt2800pci. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00debug.c | 5 +++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 6 ++++++ drivers/net/wireless/rt2x00/rt2x00queue.c | 13 ++++++++----- drivers/net/wireless/rt2x00/rt2x00queue.h | 21 +++++++++++++++++---- drivers/net/wireless/rt2x00/rt2x00usb.c | 27 ++++++++++++++++++++++++--- 6 files changed, 59 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 762f6b4e7afc..0ae942cb66df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1070,6 +1070,7 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, */ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_dmadone(struct queue_entry *entry); void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc); void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index daf7f950a28f..54dc44bb415c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -338,14 +338,15 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, return -ENOMEM; temp = data + - sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\n"); + sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n"); queue_for_each(intf->rt2x00dev, queue) { spin_lock_irqsave(&queue->lock, irqflags); - temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, + temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, queue->count, queue->limit, queue->length, queue->index[Q_INDEX], + queue->index[Q_INDEX_DMA_DONE], queue->index[Q_INDEX_DONE]); spin_unlock_irqrestore(&queue->lock, irqflags); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 580595ba5683..053fdd3bd720 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -251,6 +251,12 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); +void rt2x00lib_dmadone(struct queue_entry *entry) +{ + rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE); +} +EXPORT_SYMBOL_GPL(rt2x00lib_dmadone); + void rt2x00lib_txdone(struct queue_entry *entry, struct txdone_entry_desc *txdesc) { diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index ecf57635ae51..6d41599a090c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -731,13 +731,13 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) if (queue->index[index] >= queue->limit) queue->index[index] = 0; + queue->last_action[index] = jiffies; + if (index == Q_INDEX) { queue->length++; - queue->last_index = jiffies; } else if (index == Q_INDEX_DONE) { queue->length--; queue->count++; - queue->last_index_done = jiffies; } spin_unlock_irqrestore(&queue->lock, irqflags); @@ -746,14 +746,17 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) static void rt2x00queue_reset(struct data_queue *queue) { unsigned long irqflags; + unsigned int i; spin_lock_irqsave(&queue->lock, irqflags); queue->count = 0; queue->length = 0; - queue->last_index = jiffies; - queue->last_index_done = jiffies; - memset(queue->index, 0, sizeof(queue->index)); + + for (i = 0; i < Q_INDEX_MAX; i++) { + queue->index[i] = 0; + queue->last_action[i] = jiffies; + } spin_unlock_irqrestore(&queue->lock, irqflags); } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 0e38a911195d..d81d85f34866 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -401,6 +401,8 @@ struct queue_entry { * * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is * owned by the hardware then the queue is considered to be full. + * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been + * transfered to the hardware. * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by * the hardware and for which we need to run the txdone handler. If this * entry is not owned by the hardware the queue is considered to be empty. @@ -409,6 +411,7 @@ struct queue_entry { */ enum queue_index { Q_INDEX, + Q_INDEX_DMA_DONE, Q_INDEX_DONE, Q_INDEX_MAX, }; @@ -445,13 +448,12 @@ struct data_queue { enum data_queue_qid qid; spinlock_t lock; - unsigned long last_index; - unsigned long last_index_done; unsigned int count; unsigned short limit; unsigned short threshold; unsigned short length; unsigned short index[Q_INDEX_MAX]; + unsigned long last_action[Q_INDEX_MAX]; unsigned short txop; unsigned short aifs; @@ -616,12 +618,23 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) } /** - * rt2x00queue_timeout - Check if a timeout occured for this queue + * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts * @queue: Queue to check. */ static inline int rt2x00queue_timeout(struct data_queue *queue) { - return time_after(queue->last_index, queue->last_index_done + (HZ / 10)); + return time_after(queue->last_action[Q_INDEX_DMA_DONE], + queue->last_action[Q_INDEX_DONE] + (HZ / 10)); +} + +/** + * rt2x00queue_timeout - Check if a timeout occured for DMA transfers + * @queue: Queue to check. + */ +static inline int rt2x00queue_dma_timeout(struct data_queue *queue) +{ + return time_after(queue->last_action[Q_INDEX], + queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10)); } /** diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 6cc7aa418d87..aec6440d364a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -212,6 +212,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; + /* + * Report the frame as DMA done + */ + rt2x00lib_dmadone(entry); + /* * Check if the frame was correctly uploaded */ @@ -283,13 +288,14 @@ void rt2x00usb_kill_tx_queue(struct data_queue *queue) } EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue); -static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue) +static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) { struct queue_entry *entry; struct queue_entry_priv_usb *entry_priv; unsigned short threshold = queue->threshold; - WARNING(queue->rt2x00dev, "TX queue %d timed out, invoke reset", queue->qid); + WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," + " invoke forced forced reset", queue->qid); /* * Temporarily disable the TX queue, this will force mac80211 @@ -331,13 +337,23 @@ static void rt2x00usb_watchdog_reset_tx(struct data_queue *queue) ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid); } +static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) +{ + WARNING(queue->rt2x00dev, "TX queue %d status timed out," + " invoke forced tx handler", queue->qid); + + ieee80211_queue_work(queue->rt2x00dev->hw, &queue->rt2x00dev->txdone_work); +} + void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; tx_queue_for_each(rt2x00dev, queue) { + if (rt2x00queue_dma_timeout(queue)) + rt2x00usb_watchdog_tx_dma(queue); if (rt2x00queue_timeout(queue)) - rt2x00usb_watchdog_reset_tx(queue); + rt2x00usb_watchdog_tx_status(queue); } } EXPORT_SYMBOL_GPL(rt2x00usb_watchdog); @@ -382,6 +398,11 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; + /* + * Report the frame as DMA done + */ + rt2x00lib_dmadone(entry); + /* * Check if the received data is simply too small * to be actually valid, or if the urb is signaling -- cgit v1.2.3 From cd35a3912188d006f251fff1028d84e1d1649ca2 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Mon, 30 Aug 2010 21:15:51 +0200 Subject: rt2x00: Cleanup rt2x00usb_watchdog_reset_tx rt2x00usb_watchdog_reset_tx performs the same task as rt2x00usb_kill_tx_queue, with the only difference is that it waits for all entries to be returned to the driver and for all frames the status has been reported to mac80211. We can easily split this task by calling rt2x00usb_kill_tx_queue, sleep for a short period and invoke the TX status reporting function. By adding the sleep() to the kill_entry we make sure that even during shutdown we guarentee the entry has been killed when the function returns. To make this work correctly the interrupt handlers have to be updated to prevent checking for the RADIO_ENABLED flag too early which prevents the ownership of the entry to be reset. Additionally a check for the DEVICE_PRESENT flag is not required but is nice to prevent race conditions when the device was unplugged. Additionally rather then calling rt2x00usb_work_txdone() for status reporting we let the driver perform the TX status reporting first. If this is not sufficient then rt2x00usb_work_txdone() will still be used to cleanup the mess. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 66 ++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 26 deletions(-) (limited to 'drivers/net/wireless/rt2x00') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index aec6440d364a..4c5ae3d45625 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -208,8 +208,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || - !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -227,7 +226,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); } static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) @@ -279,6 +280,14 @@ static void rt2x00usb_kill_tx_entry(struct queue_entry *entry) if ((entry->queue->qid == QID_BEACON) && (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))) usb_kill_urb(bcn_priv->guardian_urb); + + /* + * We need a short delay here to wait for + * the URB to be canceled + */ + do { + udelay(100); + } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)); } void rt2x00usb_kill_tx_queue(struct data_queue *queue) @@ -290,8 +299,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_kill_tx_queue); static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) { - struct queue_entry *entry; - struct queue_entry_priv_usb *entry_priv; + struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; unsigned short threshold = queue->threshold; WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," @@ -305,28 +313,33 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) * queue from being enabled during the txdone handler. */ queue->threshold = queue->limit; - ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid); + ieee80211_stop_queue(rt2x00dev->hw, queue->qid); /* - * Reset all currently uploaded TX frames. + * Kill all entries in the queue, afterwards we need to + * wait a bit for all URBs to be cancelled. */ - while (!rt2x00queue_empty(queue)) { - entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - entry_priv = entry->priv_data; - usb_kill_urb(entry_priv->urb); + rt2x00usb_kill_tx_queue(queue); - /* - * We need a short delay here to wait for - * the URB to be canceled - */ - do { - udelay(100); - } while (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)); + /* + * In case that a driver has overriden the txdone_work + * function, we invoke the TX done through there. + */ + rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work); - /* - * Invoke the TX done handler - */ - rt2x00usb_work_txdone_entry(entry); + /* + * Security measure: if the driver did override the + * txdone_work function, and the hardware did arrive + * in a state which causes it to malfunction, it is + * possible that the driver couldn't handle the txdone + * event correctly. So after giving the driver the + * chance to cleanup, we now force a cleanup of any + * leftovers. + */ + if (!rt2x00queue_empty(queue)) { + WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," + " status handling failed, invoke hard reset", queue->qid); + rt2x00usb_work_txdone(&rt2x00dev->txdone_work); } /* @@ -334,7 +347,7 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) * queue again. */ queue->threshold = threshold; - ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid); + ieee80211_wake_queue(rt2x00dev->hw, queue->qid); } static void rt2x00usb_watchdog_tx_status(struct data_queue *queue) @@ -394,8 +407,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct queue_entry *entry = (struct queue_entry *)urb->context; struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; - if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) || - !__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) + if (!__test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) return; /* @@ -415,7 +427,9 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Schedule the delayed work for reading the RX status * from the device. */ - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); } /* -- cgit v1.2.3