aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rt2x00')
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c132
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c132
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c78
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h158
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c169
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c151
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c99
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h110
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c60
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ht.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c77
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c239
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h41
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c282
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c159
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h62
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c88
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h36
27 files changed, 1373 insertions, 762 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 9ec6691adf0d..54ca49ad3472 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -633,6 +633,88 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev,
}
/*
+ * Queue handlers.
+ */
+static void rt2400pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2400pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2400pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static bool rt2400pci_get_entry_state(struct queue_entry *entry)
@@ -878,17 +960,6 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
- rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -987,10 +1058,6 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2400pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt2400pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1122,32 +1189,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
-static void rt2400pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
-}
-
-static void rt2400pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
- } else {
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
-}
-
/*
* RX control handlers
*/
@@ -1281,13 +1322,13 @@ static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2400pci_txdone(rt2x00dev, QID_AC_BE);
+ rt2400pci_txdone(rt2x00dev, QID_AC_VO);
/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2400pci_txdone(rt2x00dev, QID_AC_BK);
+ rt2400pci_txdone(rt2x00dev, QID_AC_VI);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
@@ -1625,10 +1666,11 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.link_stats = rt2400pci_link_stats,
.reset_tuner = rt2400pci_reset_tuner,
.link_tuner = rt2400pci_link_tuner,
+ .start_queue = rt2400pci_start_queue,
+ .kick_queue = rt2400pci_kick_queue,
+ .stop_queue = rt2400pci_stop_queue,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_beacon = rt2400pci_write_beacon,
- .kick_tx_queue = rt2400pci_kick_tx_queue,
- .kill_tx_queue = rt2400pci_kill_tx_queue,
.fill_rxdone = rt2400pci_fill_rxdone,
.config_filter = rt2400pci_config_filter,
.config_intf = rt2400pci_config_intf,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 3e7f20346243..a9ff26a27724 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -723,6 +723,88 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt2500pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_ATIM:
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 0);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 0);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static bool rt2500pci_get_entry_state(struct queue_entry *entry)
@@ -1033,17 +1115,6 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
- rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
-}
-
static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -1142,10 +1213,6 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2500pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt2500pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1276,32 +1343,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
}
-static void rt2500pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, (queue->qid == QID_ATIM));
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
-}
-
-static void rt2500pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, CSR14, 0);
- } else {
- rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
- rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
- rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
- }
-}
-
/*
* RX control handlers
*/
@@ -1414,13 +1455,13 @@ static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance)
* 4 - Priority ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
- rt2500pci_txdone(rt2x00dev, QID_AC_BE);
+ rt2500pci_txdone(rt2x00dev, QID_AC_VO);
/*
* 5 - Tx ring transmit done interrupt.
*/
if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
- rt2500pci_txdone(rt2x00dev, QID_AC_BK);
+ rt2500pci_txdone(rt2x00dev, QID_AC_VI);
/* Enable interrupts again. */
rt2x00dev->ops->lib->set_device_state(rt2x00dev,
@@ -1922,10 +1963,11 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.link_stats = rt2500pci_link_stats,
.reset_tuner = rt2500pci_reset_tuner,
.link_tuner = rt2500pci_link_tuner,
+ .start_queue = rt2500pci_start_queue,
+ .kick_queue = rt2500pci_kick_queue,
+ .stop_queue = rt2500pci_stop_queue,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_beacon = rt2500pci_write_beacon,
- .kick_tx_queue = rt2500pci_kick_tx_queue,
- .kill_tx_queue = rt2500pci_kill_tx_queue,
.fill_rxdone = rt2500pci_fill_rxdone,
.config_filter = rt2500pci_config_filter,
.config_intf = rt2500pci_config_intf,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 8152fec31753..6b3b1de46792 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -739,6 +739,55 @@ static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev,
}
/*
+ * Queue handlers.
+ */
+static void rt2500usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ break;
+ case QID_BEACON:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2500usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u16 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+ break;
+ case QID_BEACON:
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Initialization functions.
*/
static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
@@ -931,17 +980,6 @@ static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u16 reg;
-
- rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
- rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
-}
-
static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1017,10 +1055,6 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt2500usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt2500usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1203,14 +1237,6 @@ 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
*/
@@ -1811,11 +1837,13 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt2500usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt2500usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_beacon = rt2500usb_write_beacon,
.get_tx_data_len = rt2500usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_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/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index a81c4371835b..4c55e8525cad 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -46,8 +46,11 @@
* RF2020 2.4G B/G
* RF3021 2.4G 1T2R
* RF3022 2.4G 2T2R
- * RF3052 2.4G 2T2R
- * RF3320 2.4G 1T1R
+ * RF3052 2.4G/5G 2T2R
+ * RF2853 2.4G/5G 3T3R
+ * RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
+ * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
+ * RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
*/
#define RF2820 0x0001
#define RF2850 0x0002
@@ -58,7 +61,10 @@
#define RF3021 0x0007
#define RF3022 0x0008
#define RF3052 0x0009
+#define RF2853 0x000a
#define RF3320 0x000b
+#define RF3322 0x000c
+#define RF3853 0x000d
/*
* Chipset revisions.
@@ -207,10 +213,10 @@
/*
* WMM_AIFSN_CFG: Aifsn for each EDCA AC
- * AIFSN0: AC_BE
- * AIFSN1: AC_BK
- * AIFSN2: AC_VI
- * AIFSN3: AC_VO
+ * AIFSN0: AC_VO
+ * AIFSN1: AC_VI
+ * AIFSN2: AC_BE
+ * AIFSN3: AC_BK
*/
#define WMM_AIFSN_CFG 0x0214
#define WMM_AIFSN_CFG_AIFSN0 FIELD32(0x0000000f)
@@ -220,10 +226,10 @@
/*
* WMM_CWMIN_CSR: CWmin for each EDCA AC
- * CWMIN0: AC_BE
- * CWMIN1: AC_BK
- * CWMIN2: AC_VI
- * CWMIN3: AC_VO
+ * CWMIN0: AC_VO
+ * CWMIN1: AC_VI
+ * CWMIN2: AC_BE
+ * CWMIN3: AC_BK
*/
#define WMM_CWMIN_CFG 0x0218
#define WMM_CWMIN_CFG_CWMIN0 FIELD32(0x0000000f)
@@ -233,10 +239,10 @@
/*
* WMM_CWMAX_CSR: CWmax for each EDCA AC
- * CWMAX0: AC_BE
- * CWMAX1: AC_BK
- * CWMAX2: AC_VI
- * CWMAX3: AC_VO
+ * CWMAX0: AC_VO
+ * CWMAX1: AC_VI
+ * CWMAX2: AC_BE
+ * CWMAX3: AC_BK
*/
#define WMM_CWMAX_CFG 0x021c
#define WMM_CWMAX_CFG_CWMAX0 FIELD32(0x0000000f)
@@ -245,18 +251,18 @@
#define WMM_CWMAX_CFG_CWMAX3 FIELD32(0x0000f000)
/*
- * AC_TXOP0: AC_BK/AC_BE TXOP register
- * AC0TXOP: AC_BK in unit of 32us
- * AC1TXOP: AC_BE in unit of 32us
+ * AC_TXOP0: AC_VO/AC_VI TXOP register
+ * AC0TXOP: AC_VO in unit of 32us
+ * AC1TXOP: AC_VI in unit of 32us
*/
#define WMM_TXOP0_CFG 0x0220
#define WMM_TXOP0_CFG_AC0TXOP FIELD32(0x0000ffff)
#define WMM_TXOP0_CFG_AC1TXOP FIELD32(0xffff0000)
/*
- * AC_TXOP1: AC_VO/AC_VI TXOP register
- * AC2TXOP: AC_VI in unit of 32us
- * AC3TXOP: AC_VO in unit of 32us
+ * AC_TXOP1: AC_BE/AC_BK TXOP register
+ * AC2TXOP: AC_BE in unit of 32us
+ * AC3TXOP: AC_BK in unit of 32us
*/
#define WMM_TXOP1_CFG 0x0224
#define WMM_TXOP1_CFG_AC2TXOP FIELD32(0x0000ffff)
@@ -282,7 +288,7 @@
#define MCU_CMD_CFG 0x022c
/*
- * AC_BK register offsets
+ * AC_VO register offsets
*/
#define TX_BASE_PTR0 0x0230
#define TX_MAX_CNT0 0x0234
@@ -290,7 +296,7 @@
#define TX_DTX_IDX0 0x023c
/*
- * AC_BE register offsets
+ * AC_VI register offsets
*/
#define TX_BASE_PTR1 0x0240
#define TX_MAX_CNT1 0x0244
@@ -298,7 +304,7 @@
#define TX_DTX_IDX1 0x024c
/*
- * AC_VI register offsets
+ * AC_BE register offsets
*/
#define TX_BASE_PTR2 0x0250
#define TX_MAX_CNT2 0x0254
@@ -306,7 +312,7 @@
#define TX_DTX_IDX2 0x025c
/*
- * AC_VO register offsets
+ * AC_BK register offsets
*/
#define TX_BASE_PTR3 0x0260
#define TX_MAX_CNT3 0x0264
@@ -699,8 +705,18 @@
/*
* CH_TIME_CFG: count as channel busy
+ * EIFS_BUSY: Count EIFS as channel busy
+ * NAV_BUSY: Count NAS as channel busy
+ * RX_BUSY: Count RX as channel busy
+ * TX_BUSY: Count TX as channel busy
+ * TMR_EN: Enable channel statistics timer
*/
#define CH_TIME_CFG 0x110c
+#define CH_TIME_CFG_EIFS_BUSY FIELD32(0x00000010)
+#define CH_TIME_CFG_NAV_BUSY FIELD32(0x00000008)
+#define CH_TIME_CFG_RX_BUSY FIELD32(0x00000004)
+#define CH_TIME_CFG_TX_BUSY FIELD32(0x00000002)
+#define CH_TIME_CFG_TMR_EN FIELD32(0x00000001)
/*
* PBF_LIFE_TIMER: TX/RX MPDU timestamp timer (free run) Unit: 1us
@@ -1841,32 +1857,51 @@ struct mac_iveiv_entry {
#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
/*
- * EEPROM ANTENNA config
+ * EEPROM NIC Configuration 0
* RXPATH: 1: 1R, 2: 2R, 3: 3R
- * TXPATH: 1: 1T, 2: 2T
- */
-#define EEPROM_ANTENNA 0x001a
-#define EEPROM_ANTENNA_RXPATH FIELD16(0x000f)
-#define EEPROM_ANTENNA_TXPATH FIELD16(0x00f0)
-#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0f00)
-
-/*
- * EEPROM NIC config
- * CARDBUS_ACCEL: 0 - enable, 1 - disable
- */
-#define EEPROM_NIC 0x001b
-#define EEPROM_NIC_HW_RADIO FIELD16(0x0001)
-#define EEPROM_NIC_DYNAMIC_TX_AGC FIELD16(0x0002)
-#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0004)
-#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0008)
-#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0010)
-#define EEPROM_NIC_BW40M_SB_BG FIELD16(0x0020)
-#define EEPROM_NIC_BW40M_SB_A FIELD16(0x0040)
-#define EEPROM_NIC_WPS_PBC FIELD16(0x0080)
-#define EEPROM_NIC_BW40M_BG FIELD16(0x0100)
-#define EEPROM_NIC_BW40M_A FIELD16(0x0200)
-#define EEPROM_NIC_ANT_DIVERSITY FIELD16(0x0800)
-#define EEPROM_NIC_DAC_TEST FIELD16(0x8000)
+ * TXPATH: 1: 1T, 2: 2T, 3: 3T
+ * RF_TYPE: RFIC type
+ */
+#define EEPROM_NIC_CONF0 0x001a
+#define EEPROM_NIC_CONF0_RXPATH FIELD16(0x000f)
+#define EEPROM_NIC_CONF0_TXPATH FIELD16(0x00f0)
+#define EEPROM_NIC_CONF0_RF_TYPE FIELD16(0x0f00)
+
+/*
+ * EEPROM NIC Configuration 1
+ * HW_RADIO: 0: disable, 1: enable
+ * EXTERNAL_TX_ALC: 0: disable, 1: enable
+ * EXTERNAL_LNA_2G: 0: disable, 1: enable
+ * EXTERNAL_LNA_5G: 0: disable, 1: enable
+ * CARDBUS_ACCEL: 0: enable, 1: disable
+ * BW40M_SB_2G: 0: disable, 1: enable
+ * BW40M_SB_5G: 0: disable, 1: enable
+ * WPS_PBC: 0: disable, 1: enable
+ * BW40M_2G: 0: enable, 1: disable
+ * BW40M_5G: 0: enable, 1: disable
+ * BROADBAND_EXT_LNA: 0: disable, 1: enable
+ * ANT_DIVERSITY: 00: Disable, 01: Diversity,
+ * 10: Main antenna, 11: Aux antenna
+ * INTERNAL_TX_ALC: 0: disable, 1: enable
+ * BT_COEXIST: 0: disable, 1: enable
+ * DAC_TEST: 0: disable, 1: enable
+ */
+#define EEPROM_NIC_CONF1 0x001b
+#define EEPROM_NIC_CONF1_HW_RADIO FIELD16(0x0001)
+#define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC FIELD16(0x0002)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G FIELD16(0x0004)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_5G FIELD16(0x0008)
+#define EEPROM_NIC_CONF1_CARDBUS_ACCEL FIELD16(0x0010)
+#define EEPROM_NIC_CONF1_BW40M_SB_2G FIELD16(0x0020)
+#define EEPROM_NIC_CONF1_BW40M_SB_5G FIELD16(0x0040)
+#define EEPROM_NIC_CONF1_WPS_PBC FIELD16(0x0080)
+#define EEPROM_NIC_CONF1_BW40M_2G FIELD16(0x0100)
+#define EEPROM_NIC_CONF1_BW40M_5G FIELD16(0x0200)
+#define EEPROM_NIC_CONF1_BROADBAND_EXT_LNA FIELD16(0x400)
+#define EEPROM_NIC_CONF1_ANT_DIVERSITY FIELD16(0x1800)
+#define EEPROM_NIC_CONF1_INTERNAL_TX_ALC FIELD16(0x2000)
+#define EEPROM_NIC_CONF1_BT_COEXIST FIELD16(0x4000)
+#define EEPROM_NIC_CONF1_DAC_TEST FIELD16(0x8000)
/*
* EEPROM frequency
@@ -1888,9 +1923,9 @@ struct mac_iveiv_entry {
* POLARITY_GPIO_4: Polarity GPIO4 setting.
* LED_MODE: Led mode.
*/
-#define EEPROM_LED1 0x001e
-#define EEPROM_LED2 0x001f
-#define EEPROM_LED3 0x0020
+#define EEPROM_LED_AG_CONF 0x001e
+#define EEPROM_LED_ACT_CONF 0x001f
+#define EEPROM_LED_POLARITY 0x0020
#define EEPROM_LED_POLARITY_RDY_BG FIELD16(0x0001)
#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
@@ -1902,6 +1937,17 @@ struct mac_iveiv_entry {
#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
/*
+ * EEPROM NIC Configuration 2
+ * RX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
+ * TX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
+ * CRYSTAL: 00: Reserved, 01: One crystal, 10: Two crystal, 11: Reserved
+ */
+#define EEPROM_NIC_CONF2 0x0021
+#define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f)
+#define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0)
+#define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600)
+
+/*
* EEPROM LNA
*/
#define EEPROM_LNA 0x0022
@@ -1951,7 +1997,7 @@ struct mac_iveiv_entry {
/*
* EEPROM TXpower delta: 20MHZ AND 40 MHZ use different power.
- * This is delta in 40MHZ.
+ * This is delta in 40MHZ.
* VALUE: Tx Power dalta value (MAX=4)
* TYPE: 1: Plus the delta value, 0: minus the delta value
* TXPOWER: Enable:
@@ -2007,9 +2053,9 @@ struct mac_iveiv_entry {
#define MCU_CURRENT 0x36
#define MCU_LED 0x50
#define MCU_LED_STRENGTH 0x51
-#define MCU_LED_1 0x52
-#define MCU_LED_2 0x53
-#define MCU_LED_3 0x54
+#define MCU_LED_AG_CONF 0x52
+#define MCU_LED_ACT_CONF 0x53
+#define MCU_LED_LED_POLARITY 0x54
#define MCU_RADAR 0x60
#define MCU_BOOT_SIGNAL 0x72
#define MCU_BBP_SIGNAL 0x80
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 75631614aba3..54917a281398 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -772,6 +772,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;
/*
@@ -806,11 +807,13 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with TXWI to register.
+ * Write entire beacon with TXWI and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2800_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -1625,6 +1628,13 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
}
msleep(1);
+
+ /*
+ * Clear channel statistic counters
+ */
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &reg);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
}
static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
@@ -1930,8 +1940,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
rt2800_register_write(rt2x00dev, TX_SW_CFG2,
0x0000002c);
else
@@ -2259,6 +2269,17 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, INT_TIMER_CFG_PRE_TBTT_TIMER, 6 << 4);
rt2800_register_write(rt2x00dev, INT_TIMER_CFG, reg);
+ /*
+ * Set up channel statistics timer
+ */
+ rt2800_register_read(rt2x00dev, CH_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_EIFS_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_NAV_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_RX_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_TX_BUSY, 1);
+ rt2x00_set_field32(&reg, CH_TIME_CFG_TMR_EN, 1);
+ rt2800_register_write(rt2x00dev, CH_TIME_CFG, reg);
+
return 0;
}
@@ -2376,10 +2397,10 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2x00_rt(rt2x00dev, RT3390)) {
rt2800_bbp_read(rt2x00dev, 138, &value);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
value |= 0x20;
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
value &= ~0x02;
rt2800_bbp_write(rt2x00dev, 138, value);
@@ -2591,8 +2612,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_DAC_TEST))
rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
else
rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
@@ -2665,10 +2686,10 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt(rt2x00dev, RT3090)) {
rt2800_bbp_read(rt2x00dev, 138, &bbp);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) == 1)
rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) == 1)
rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
rt2800_bbp_write(rt2x00dev, 138, bbp);
@@ -2767,16 +2788,16 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Initialize LED control
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED1, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_1, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_AG_CONF, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_AG_CONF, 0xff,
word & 0xff, (word >> 8) & 0xff);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED2, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_2, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_ACT_CONF, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_ACT_CONF, 0xff,
word & 0xff, (word >> 8) & 0xff);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_LED3, &word);
- rt2800_mcu_request(rt2x00dev, MCU_LED_3, 0xff,
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED_POLARITY, &word);
+ rt2800_mcu_request(rt2x00dev, MCU_LED_LED_POLARITY, 0xff,
word & 0xff, (word >> 8) & 0xff);
return 0;
@@ -2870,38 +2891,41 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &word);
if (word == 0xffff) {
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_TXPATH, 1);
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_TXPATH, 1);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RF_TYPE, RF2820);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
* There is a max of 2 RX streams for RT28x0 series
*/
- if (rt2x00_get_field16(word, EEPROM_ANTENNA_RXPATH) > 2)
- rt2x00_set_field16(&word, EEPROM_ANTENNA_RXPATH, 2);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ if (rt2x00_get_field16(word, EEPROM_NIC_CONF0_RXPATH) > 2)
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF0_RXPATH, 2);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF0, word);
}
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &word);
if (word == 0xffff) {
- rt2x00_set_field16(&word, EEPROM_NIC_HW_RADIO, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_DYNAMIC_TX_AGC, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_SB_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);
- rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_HW_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_TX_ALC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_SB_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_WPS_PBC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_2G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BW40M_5G, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BROADBAND_EXT_LNA, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_ANT_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_INTERNAL_TX_ALC, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_BT_COEXIST, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CONF1_DAC_TEST, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC_CONF1, word);
EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
}
@@ -2916,9 +2940,9 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
LED_MODE_TXRX_ACTIVITY);
rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);
rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);
- rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_AG_CONF, 0x5555);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_ACT_CONF, 0x2221);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED_POLARITY, 0xa9f8);
EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);
}
@@ -2982,12 +3006,12 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read EEPROM word for configuration.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
/*
* Identify RF chipset.
*/
- value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);
rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
rt2x00_set_chip(rt2x00dev, rt2x00_get_field32(reg, MAC_CSR0_CHIPSET),
@@ -3023,9 +3047,9 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Identify default antenna configuration.
*/
rt2x00dev->default_ant.tx =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH);
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH);
rt2x00dev->default_ant.rx =
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH);
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH);
/*
* Read frequency offset and RF programming sequence.
@@ -3036,17 +3060,17 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Read external LNA informations.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
/*
* Detect if this device has an hardware controlled radio.
*/
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
/*
@@ -3258,7 +3282,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00dev->hw->max_report_rates = 7;
rt2x00dev->hw->max_rate_tries = 1;
- rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF0, &eeprom);
/*
* Initialize hw_mode information.
@@ -3302,11 +3326,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40;
- if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) >= 2)
spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
spec->ht.cap |=
- rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<
+ rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH) <<
IEEE80211_HT_CAP_RX_STBC_SHIFT;
spec->ht.ampdu_factor = 3;
@@ -3314,10 +3338,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->ht.mcs.tx_params =
IEEE80211_HT_MCS_TX_DEFINED |
IEEE80211_HT_MCS_TX_RX_DIFF |
- ((rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) - 1) <<
+ ((rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_TXPATH) - 1) <<
IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
- switch (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH)) {
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RXPATH)) {
case 3:
spec->ht.mcs.rx_mask[2] = 0xff;
case 2:
@@ -3536,6 +3560,37 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(rt2800_ampdu_action);
+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_conf *conf = &hw->conf;
+ u32 idle, busy, busy_ext;
+
+ if (idx != 0)
+ return -ENOENT;
+
+ survey->channel = conf->channel;
+
+ rt2800_register_read(rt2x00dev, CH_IDLE_STA, &idle);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA, &busy);
+ rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
+
+ if (idle || busy) {
+ survey->filled = SURVEY_INFO_CHANNEL_TIME |
+ SURVEY_INFO_CHANNEL_TIME_BUSY |
+ SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
+
+ survey->channel_time = (idle + busy) / 1000;
+ survey->channel_time_busy = busy / 1000;
+ survey->channel_time_ext_busy = busy_ext / 1000;
+ }
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(rt2800_get_survey);
+
MODULE_AUTHOR(DRV_PROJECT ", Bartlomiej Zolnierkiewicz");
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2800 library");
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 81cbc92e7857..e3c995a9dec4 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -199,5 +199,7 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw);
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
+ struct survey_info *survey);
#endif /* RT2800LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index b989b0d3ed49..aa97971a38af 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -186,6 +186,77 @@ static inline void rt2800pci_read_eeprom_efuse(struct rt2x00_dev *rt2x00dev)
#endif /* CONFIG_PCI */
/*
+ * Queue handlers.
+ */
+static void rt2800pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ };
+}
+
+static void rt2800pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ struct queue_entry *entry;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
+ break;
+ case QID_MGMT:
+ entry = rt2x00queue_get_entry(queue, Q_INDEX);
+ rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2800pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -323,17 +394,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
- (state == STATE_RADIO_RX_ON));
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -477,10 +537,6 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800pci_disable_radio(rt2x00dev);
rt2800pci_set_state(rt2x00dev, STATE_SLEEP);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt2800pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -566,41 +622,6 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry,
}
/*
- * TX data initialization
- */
-static void rt2800pci_kick_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
- unsigned int qidx;
-
- if (queue->qid == QID_MGMT)
- qidx = 5;
- else
- qidx = queue->qid;
-
- rt2800_register_write(rt2x00dev, TX_CTX_IDX(qidx), entry->entry_idx);
-}
-
-static void rt2800pci_kill_tx_queue(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, 0);
- return;
- }
-
- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, (queue->qid == QID_AC_VO));
- rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-}
-
-/*
* RX control handlers
*/
static void rt2800pci_fill_rxdone(struct queue_entry *entry,
@@ -667,14 +688,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
u32 status;
u8 qid;
- while (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
- /* Now remove the tx status from the FIFO */
- if (kfifo_out(&rt2x00dev->txstatus_fifo, &status,
- sizeof(status)) != sizeof(status)) {
- WARN_ON(1);
- break;
- }
-
+ while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
if (qid >= QID_RX) {
/*
@@ -682,7 +696,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* this tx status.
*/
WARNING(rt2x00dev, "Got TX status report with "
- "unexpected pid %u, dropping", qid);
+ "unexpected pid %u, dropping\n", qid);
break;
}
@@ -693,7 +707,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* processing here and drop the tx status
*/
WARNING(rt2x00dev, "Got TX status for an unavailable "
- "queue %u, dropping", qid);
+ "queue %u, dropping\n", qid);
break;
}
@@ -703,7 +717,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
* and drop the tx status.
*/
WARNING(rt2x00dev, "Got TX status for an empty "
- "queue %u, dropping", qid);
+ "queue %u, dropping\n", qid);
break;
}
@@ -782,14 +796,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
- if (kfifo_is_full(&rt2x00dev->txstatus_fifo)) {
- WARNING(rt2x00dev, "TX status FIFO overrun,"
- " drop tx status report.\n");
- break;
- }
-
- if (kfifo_in(&rt2x00dev->txstatus_fifo, &status,
- sizeof(status)) != sizeof(status)) {
+ if (!kfifo_put(&rt2x00dev->txstatus_fifo, &status)) {
WARNING(rt2x00dev, "TX status FIFO overrun,"
"drop tx status report.\n");
break;
@@ -944,6 +951,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
+ .get_survey = rt2800_get_survey,
};
static const struct rt2800_ops rt2800pci_rt2800_ops = {
@@ -976,11 +984,12 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
+ .start_queue = rt2800pci_start_queue,
+ .kick_queue = rt2800pci_kick_queue,
+ .stop_queue = rt2800pci_stop_queue,
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
- .kick_tx_queue = rt2800pci_kick_tx_queue,
- .kill_tx_queue = rt2800pci_kill_tx_queue,
.fill_rxdone = rt2800pci_fill_rxdone,
.config_shared_key = rt2800_config_shared_key,
.config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 935b76d3ce4f..b97a4a54ff4c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -50,6 +50,55 @@ module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
/*
+ * Queue handlers.
+ */
+static void rt2800usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt2800usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ break;
+ case QID_BEACON:
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -107,17 +156,6 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Device state switch handlers.
*/
-static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX,
- (state == STATE_RADIO_RX_ON));
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-}
-
static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -214,10 +252,6 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
rt2800usb_disable_radio(rt2x00dev);
rt2800usb_set_state(rt2x00dev, STATE_SLEEP);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt2800usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -253,7 +287,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
WARNING(rt2x00dev, "TX HW queue 0 timed out,"
- " invoke forced kick");
+ " invoke forced kick\n");
rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012);
@@ -269,7 +303,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
WARNING(rt2x00dev, "TX HW queue 1 timed out,"
- " invoke forced kick");
+ " invoke forced kick\n");
rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
@@ -335,7 +369,10 @@ static void rt2800usb_write_tx_desc(struct queue_entry *entry,
static void rt2800usb_write_tx_data(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
- u8 padding_len;
+ unsigned int len;
+ int err;
+
+ rt2800_write_tx_data(entry, txdesc);
/*
* pad(1~3 bytes) is added after each 802.11 payload.
@@ -344,9 +381,14 @@ static void rt2800usb_write_tx_data(struct queue_entry *entry,
* | TXINFO | TXWI | 802.11 header | L2 pad | payload | pad | USB end pad |
* |<------------- tx_pkt_len ------------->|
*/
- rt2800_write_tx_data(entry, txdesc);
- padding_len = roundup(entry->skb->len + 4, 4) - entry->skb->len;
- memset(skb_put(entry->skb, padding_len), 0, padding_len);
+ len = roundup(entry->skb->len, 4) + 4;
+ err = skb_padto(entry->skb, len);
+ if (unlikely(err)) {
+ WARNING(entry->queue->rt2x00dev, "TX SKB padding error, out of memory\n");
+ return;
+ }
+
+ entry->skb->len = len;
}
/*
@@ -389,14 +431,6 @@ 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
*/
@@ -562,6 +596,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.rfkill_poll = rt2x00mac_rfkill_poll,
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
+ .get_survey = rt2800_get_survey,
};
static const struct rt2800_ops rt2800usb_rt2800_ops = {
@@ -591,12 +626,14 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.watchdog = rt2800usb_watchdog,
+ .start_queue = rt2800usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt2800usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_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/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index e72117f3fdf5..84aaf393da43 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -66,7 +66,7 @@
#ifdef CONFIG_RT2X00_DEBUG
#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
- DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args);
+ DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args)
#else
#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
do { } while (0)
@@ -347,6 +347,10 @@ struct link {
struct delayed_work watchdog_work;
};
+enum rt2x00_delayed_flags {
+ DELAYED_UPDATE_BEACON,
+};
+
/*
* Interface structure
* Per interface configuration details, this structure
@@ -354,22 +358,6 @@ struct link {
*/
struct rt2x00_intf {
/*
- * All fields within the rt2x00_intf structure
- * must be protected with a spinlock.
- */
- spinlock_t lock;
-
- /*
- * MAC of the device.
- */
- u8 mac[ETH_ALEN];
-
- /*
- * BBSID of the AP to associate with.
- */
- u8 bssid[ETH_ALEN];
-
- /*
* beacon->skb must be protected with the mutex.
*/
struct mutex beacon_skb_mutex;
@@ -384,8 +372,7 @@ struct rt2x00_intf {
/*
* Actions that needed rescheduling.
*/
- unsigned int delayed_flags;
-#define DELAYED_UPDATE_BEACON 0x00000001
+ unsigned long delayed_flags;
/*
* Software sequence counter, this is only required
@@ -567,7 +554,15 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);
+
+ /*
+ * Data queue handlers.
+ */
void (*watchdog) (struct rt2x00_dev *rt2x00dev);
+ void (*start_queue) (struct data_queue *queue);
+ void (*kick_queue) (struct data_queue *queue);
+ void (*stop_queue) (struct data_queue *queue);
+ void (*flush_queue) (struct data_queue *queue);
/*
* TX control handlers
@@ -579,8 +574,6 @@ struct rt2x00lib_ops {
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 data_queue *queue);
- void (*kill_tx_queue) (struct data_queue *queue);
/*
* RX control handlers
@@ -902,7 +895,7 @@ struct rt2x00_dev {
/*
* FIFO for storing tx status reports between isr and tasklet.
*/
- struct kfifo txstatus_fifo;
+ DECLARE_KFIFO_PTR(txstatus_fifo, u32);
/*
* Tasklet for processing tx status reports (rt2800pci).
@@ -1068,6 +1061,78 @@ struct data_queue *rt2x00queue_get_queue(struct rt2x00_dev *rt2x00dev,
struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
+/**
+ * rt2x00queue_pause_queue - Pause a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will pause the data queue locally, preventing
+ * new frames to be added to the queue (while the hardware is
+ * still allowed to run).
+ */
+void rt2x00queue_pause_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_unpause_queue - unpause a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will unpause the data queue locally, allowing
+ * new frames to be added to the queue again.
+ */
+void rt2x00queue_unpause_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_start_queue - Start a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will start handling all pending frames in the queue.
+ */
+void rt2x00queue_start_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_stop_queue - Halt a data queue
+ * @queue: Pointer to &struct data_queue.
+ *
+ * This function will stop all pending frames in the queue.
+ */
+void rt2x00queue_stop_queue(struct data_queue *queue);
+
+/**
+ * rt2x00queue_flush_queue - Flush a data queue
+ * @queue: Pointer to &struct data_queue.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will flush the queue. After this call
+ * the queue is guarenteed to be empty.
+ */
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop);
+
+/**
+ * rt2x00queue_start_queues - Start all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to start them
+ */
+void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00queue_stop_queues - Halt all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ *
+ * This function will loop through all available queues to stop
+ * any pending frames.
+ */
+void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00queue_flush_queues - Flush all data queues
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @drop: True to drop all pending frames.
+ *
+ * This function will loop through all available queues to flush
+ * any pending frames.
+ */
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop);
+
/*
* Debugfs handlers.
*/
@@ -1093,6 +1158,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_dmastart(struct queue_entry *entry);
void rt2x00lib_dmadone(struct queue_entry *entry);
void rt2x00lib_txdone(struct queue_entry *entry,
struct txdone_entry_desc *txdesc);
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index a238e908c854..e7f67d5eda52 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -62,13 +62,13 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
* This will prevent the device being confused when it wants
* to ACK frames or consideres itself associated.
*/
- memset(&conf.mac, 0, sizeof(conf.mac));
+ memset(conf.mac, 0, sizeof(conf.mac));
if (mac)
- memcpy(&conf.mac, mac, ETH_ALEN);
+ memcpy(conf.mac, mac, ETH_ALEN);
- memset(&conf.bssid, 0, sizeof(conf.bssid));
+ memset(conf.bssid, 0, sizeof(conf.bssid));
if (bssid)
- memcpy(&conf.bssid, bssid, ETH_ALEN);
+ memcpy(conf.bssid, bssid, ETH_ALEN);
flags |= CONFIG_UPDATE_TYPE;
if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
@@ -146,8 +146,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
* else the changes will be ignored by the device.
*/
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00dev->ops->lib->set_device_state(rt2x00dev,
- STATE_RADIO_RX_OFF);
+ rt2x00queue_stop_queue(rt2x00dev->rx);
/*
* Write new antenna setup to device and reset the link tuner.
@@ -161,8 +160,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
memcpy(active, &config, sizeof(config));
if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
- rt2x00dev->ops->lib->set_device_state(rt2x00dev,
- STATE_RADIO_RX_ON);
+ rt2x00queue_start_queue(rt2x00dev->rx);
}
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 64dfb1f6823e..c92db3264741 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -339,12 +339,13 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file,
return -ENOMEM;
temp = data +
- sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
+ sprintf(data, "qid\tflags\t\tcount\tlimit\tlength\tindex\tdma done\tdone\n");
queue_for_each(intf->rt2x00dev, queue) {
spin_lock_irqsave(&queue->index_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\t0x%.8x\t%d\t%d\t%d\t%d\t%d\t\t%d\n",
+ queue->qid, (unsigned int)queue->flags,
queue->count, queue->limit, queue->length,
queue->index[Q_INDEX],
queue->index[Q_INDEX_DMA_DONE],
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index bd3afc92f434..9597a03242cc 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -66,9 +66,9 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
set_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags);
/*
- * Enable RX.
+ * Enable queues.
*/
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00queue_start_queues(rt2x00dev);
rt2x00link_start_tuner(rt2x00dev);
/*
@@ -76,11 +76,6 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_start_watchdog(rt2x00dev);
- /*
- * Start the TX queues.
- */
- ieee80211_wake_queues(rt2x00dev->hw);
-
return 0;
}
@@ -90,21 +85,16 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
return;
/*
- * Stop the TX queues in mac80211.
- */
- ieee80211_stop_queues(rt2x00dev->hw);
- rt2x00queue_stop_queues(rt2x00dev);
-
- /*
* Stop watchdog monitoring.
*/
rt2x00link_stop_watchdog(rt2x00dev);
/*
- * Disable RX.
+ * Stop all queues
*/
rt2x00link_stop_tuner(rt2x00dev);
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00queue_stop_queues(rt2x00dev);
+ rt2x00queue_flush_queues(rt2x00dev, true);
/*
* Disable radio.
@@ -120,19 +110,6 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
{
struct rt2x00_dev *rt2x00dev = data;
struct rt2x00_intf *intf = vif_to_intf(vif);
- int delayed_flags;
-
- /*
- * Copy all data we need during this action under the protection
- * of a spinlock. Otherwise race conditions might occur which results
- * into an invalid configuration.
- */
- spin_lock(&intf->lock);
-
- delayed_flags = intf->delayed_flags;
- intf->delayed_flags = 0;
-
- spin_unlock(&intf->lock);
/*
* It is possible the radio was disabled while the work had been
@@ -143,7 +120,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return;
- if (delayed_flags & DELAYED_UPDATE_BEACON)
+ if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
rt2x00queue_update_beacon(rt2x00dev, vif, true);
}
@@ -236,8 +213,16 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
+void rt2x00lib_dmastart(struct queue_entry *entry)
+{
+ set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
+ rt2x00queue_index_inc(entry->queue, Q_INDEX);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
+
void rt2x00lib_dmadone(struct queue_entry *entry)
{
+ set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
}
@@ -249,7 +234,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
unsigned int header_length, i;
u8 rate_idx, rate_flags, retry_rates;
u8 skbdesc_flags = skbdesc->flags;
@@ -403,7 +387,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* is reenabled when the txdone handler has finished.
*/
if (!rt2x00queue_threshold(entry->queue))
- ieee80211_wake_queue(rt2x00dev->hw, qid);
+ rt2x00queue_unpause_queue(entry->queue);
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
@@ -566,10 +550,8 @@ submit_entry:
entry->flags = 0;
rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) {
+ test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00dev->ops->lib->clear_entry(entry);
- rt2x00queue_index_inc(entry->queue, Q_INDEX);
- }
}
EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
@@ -818,8 +800,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Allocate tx status FIFO for driver use.
*/
- if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->txstatus_tasklet) {
+ if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) {
/*
* Allocate txstatus fifo and tasklet, we use a size of 512
* for the kfifo which is big enough to store 512/4=128 tx
@@ -833,9 +814,10 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
return status;
/* tasklet for processing the tx status reports. */
- tasklet_init(&rt2x00dev->txstatus_tasklet,
- rt2x00dev->ops->lib->txstatus_tasklet,
- (unsigned long)rt2x00dev);
+ if (rt2x00dev->ops->lib->txstatus_tasklet)
+ tasklet_init(&rt2x00dev->txstatus_tasklet,
+ rt2x00dev->ops->lib->txstatus_tasklet,
+ (unsigned long)rt2x00dev);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index f0e1eb72befc..be0ff78c1b16 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -58,6 +58,7 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
if (!fw || !fw->size || !fw->data) {
ERROR(rt2x00dev, "Failed to read Firmware.\n");
+ release_firmware(fw);
return -ENOENT;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index c637bcaec5f8..b7ad46ecaa1d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -40,8 +40,6 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
if (tx_info->control.sta)
txdesc->mpdu_density =
tx_info->control.sta->ht_cap.ampdu_density;
- else
- txdesc->mpdu_density = 0;
txdesc->ba_size = 7; /* FIXME: What value is needed? */
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 2cf68f82674b..a105c500627b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -178,15 +178,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
/**
- * rt2x00queue_stop_queues - Halt all data queues
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- *
- * This function will loop through all available queues to stop
- * any pending outgoing frames.
- */
-void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev);
-
-/**
* rt2x00queue_init_queues - Initialize all data queues
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index 829bf4be9bc3..f3da051df39e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -104,7 +104,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
enum data_queue_qid qid = skb_get_queue_mapping(skb);
- struct data_queue *queue;
+ struct data_queue *queue = NULL;
/*
* Mac80211 might be calling this function while we are trying
@@ -153,7 +153,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
goto exit_fail;
if (rt2x00queue_threshold(queue))
- ieee80211_stop_queue(rt2x00dev->hw, qid);
+ rt2x00queue_pause_queue(queue);
return NETDEV_TX_OK;
@@ -268,13 +268,12 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
else
rt2x00dev->intf_sta_count++;
- spin_lock_init(&intf->lock);
spin_lock_init(&intf->seqlock);
mutex_init(&intf->beacon_skb_mutex);
intf->beacon = entry;
/*
- * The MAC adddress must be configured after the device
+ * The MAC address must be configured after the device
* has been initialized. Otherwise the device can reset
* the MAC registers.
* The BSSID address must only be configured in AP mode,
@@ -282,9 +281,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
* STA interfaces at this time, since this can cause
* invalid behavior in the device.
*/
- memcpy(&intf->mac, vif->addr, ETH_ALEN);
rt2x00lib_config_intf(rt2x00dev, intf, vif->type,
- intf->mac, NULL);
+ vif->addr, NULL);
/*
* Some filters depend on the current working mode. We can force
@@ -352,7 +350,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
* if for any reason the link tuner must be reset, this will be
* handled by rt2x00lib_config().
*/
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_OFF);
+ rt2x00queue_stop_queue(rt2x00dev->rx);
/*
* When we've just turned on the radio, we want to reprogram
@@ -370,7 +368,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant);
/* Turn RX back on */
- rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_ON);
+ rt2x00queue_start_queue(rt2x00dev->rx);
return 0;
}
@@ -445,9 +443,7 @@ static void rt2x00mac_set_tim_iter(void *data, u8 *mac,
vif->type != NL80211_IFTYPE_WDS)
return;
- spin_lock(&intf->lock);
- intf->delayed_flags |= DELAYED_UPDATE_BEACON;
- spin_unlock(&intf->lock);
+ set_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags);
}
int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
@@ -472,17 +468,17 @@ EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
{
if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY)
- memcpy(&crypto->key,
+ memcpy(crypto->key,
&key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY],
sizeof(crypto->key));
if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
- memcpy(&crypto->tx_mic,
+ memcpy(crypto->tx_mic,
&key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
sizeof(crypto->tx_mic));
if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY)
- memcpy(&crypto->rx_mic,
+ memcpy(crypto->rx_mic,
&key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
sizeof(crypto->rx_mic));
}
@@ -492,7 +488,6 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_key_conf *key)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- struct rt2x00_intf *intf = vif_to_intf(vif);
int (*set_key) (struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key);
@@ -516,7 +511,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (rt2x00dev->intf_sta_count)
crypto.bssidx = 0;
else
- crypto.bssidx = intf->mac[5] & (rt2x00dev->ops->max_ap_intf - 1);
+ crypto.bssidx = vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1);
crypto.cipher = rt2x00crypto_key_to_cipher(key);
if (crypto.cipher == CIPHER_NONE)
@@ -534,7 +529,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (crypto.cipher == CIPHER_TKIP)
memcpy_tkip(&crypto, &key->key[0], key->keylen);
else
- memcpy(&crypto.key, &key->key[0], key->keylen);
+ memcpy(crypto.key, &key->key[0], key->keylen);
/*
* Each BSS has a maximum of 4 shared keys.
* Shared key index values:
@@ -614,22 +609,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return;
- spin_lock(&intf->lock);
-
- /*
- * conf->bssid can be NULL if coming from the internal
- * beacon update routine.
- */
- if (changes & BSS_CHANGED_BSSID)
- memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);
-
- spin_unlock(&intf->lock);
-
/*
- * Call rt2x00_config_intf() outside of the spinlock context since
- * the call will sleep for USB drivers. By using the ieee80211_if_conf
- * values as arguments we make keep access to rt2x00_intf thread safe
- * even without the lock.
+ * Update the BSSID.
*/
if (changes & BSS_CHANGED_BSSID)
rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,
@@ -718,36 +699,8 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct data_queue *queue;
- unsigned int i = 0;
-
- ieee80211_stop_queues(hw);
-
- /*
- * Run over all queues to kick them, this will force
- * any pending frames to be transmitted.
- */
- tx_queue_for_each(rt2x00dev, queue) {
- rt2x00dev->ops->lib->kick_tx_queue(queue);
- }
-
- /**
- * All queues have been kicked, now wait for each queue
- * to become empty. With a bit of luck, we only have to wait
- * for the first queue to become empty, because while waiting
- * for the that queue, the other queues will have transmitted
- * all their frames as well (since they were already kicked).
- */
- tx_queue_for_each(rt2x00dev, queue) {
- for (i = 0; i < 10; i++) {
- if (rt2x00queue_empty(queue))
- break;
- msleep(100);
- }
-
- if (!rt2x00queue_empty(queue))
- WARNING(rt2x00dev, "Failed to flush queue %d", queue->qid);
- }
- ieee80211_wake_queues(hw);
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 868ca19b13ea..ace0b668c04e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -82,6 +82,13 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
skbdesc->desc_len = entry->queue->desc_size;
/*
+ * DMA is already done, notify rt2x00lib that
+ * it finished successfully.
+ */
+ rt2x00lib_dmastart(entry);
+ rt2x00lib_dmadone(entry);
+
+ /*
* Send the frame to rt2x00lib for further processing.
*/
rt2x00lib_rxdone(entry);
@@ -279,7 +286,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
- if (pci_dev->is_pcie)
+ if (pci_is_pcie(pci_dev))
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
else
rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
@@ -356,12 +363,12 @@ int rt2x00pci_resume(struct pci_dev *pci_dev)
struct rt2x00_dev *rt2x00dev = hw->priv;
if (pci_set_power_state(pci_dev, PCI_D0) ||
- pci_enable_device(pci_dev) ||
- pci_restore_state(pci_dev)) {
+ pci_enable_device(pci_dev)) {
ERROR(rt2x00dev, "Failed to resume device.\n");
return -EIO;
}
+ pci_restore_state(pci_dev);
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00pci_resume);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index b854d62ff99b..746ce8fe8cf4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -64,7 +64,7 @@ static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev,
const void *value,
const u32 length)
{
- memcpy_toio(rt2x00dev->csr.base + offset, value, length);
+ __iowrite32_copy(rt2x00dev->csr.base + offset, value, length >> 2);
}
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index a3d79c7a21c6..ca82b3a91697 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -199,15 +199,18 @@ void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
void rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int header_length)
{
- unsigned int l2pad = L2PAD_SIZE(header_length);
+ /*
+ * L2 padding is only present if the skb contains more than just the
+ * IEEE 802.11 header.
+ */
+ unsigned int l2pad = (skb->len > header_length) ?
+ L2PAD_SIZE(header_length) : 0;
if (!l2pad)
return;
- memmove(skb->data + header_length, skb->data + header_length + l2pad,
- skb->len - header_length - l2pad);
-
- skb_trim(skb, skb->len - l2pad);
+ memmove(skb->data + l2pad, skb->data, header_length);
+ skb_pull(skb, l2pad);
}
static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
@@ -468,7 +471,7 @@ static void rt2x00queue_kick_tx_queue(struct data_queue *queue,
*/
if (rt2x00queue_threshold(queue) ||
!test_bit(ENTRY_TXD_BURST, &txdesc->flags))
- queue->rt2x00dev->ops->lib->kick_tx_queue(queue);
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
}
int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
@@ -582,7 +585,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
rt2x00queue_free_skb(intf->beacon);
if (!enable_beacon) {
- rt2x00dev->ops->lib->kill_tx_queue(intf->beacon->queue);
+ rt2x00queue_stop_queue(intf->beacon->queue);
mutex_unlock(&intf->beacon_skb_mutex);
return 0;
}
@@ -735,6 +738,210 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ /*
+ * For TX queues, we have to disable the queue
+ * inside mac80211.
+ */
+ ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
+
+void rt2x00queue_unpause_queue(struct data_queue *queue)
+{
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ !test_bit(QUEUE_STARTED, &queue->flags) ||
+ !test_and_clear_bit(QUEUE_PAUSED, &queue->flags))
+ return;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ /*
+ * For TX queues, we have to enable the queue
+ * inside mac80211.
+ */
+ ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
+ break;
+ case QID_RX:
+ /*
+ * For RX we need to kick the queue now in order to
+ * receive frames.
+ */
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_unpause_queue);
+
+void rt2x00queue_start_queue(struct data_queue *queue)
+{
+ mutex_lock(&queue->status_lock);
+
+ if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+ test_and_set_bit(QUEUE_STARTED, &queue->flags)) {
+ mutex_unlock(&queue->status_lock);
+ return;
+ }
+
+ set_bit(QUEUE_PAUSED, &queue->flags);
+
+ queue->rt2x00dev->ops->lib->start_queue(queue);
+
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_start_queue);
+
+void rt2x00queue_stop_queue(struct data_queue *queue)
+{
+ mutex_lock(&queue->status_lock);
+
+ if (!test_and_clear_bit(QUEUE_STARTED, &queue->flags)) {
+ mutex_unlock(&queue->status_lock);
+ return;
+ }
+
+ rt2x00queue_pause_queue(queue);
+
+ queue->rt2x00dev->ops->lib->stop_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
+
+void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+ bool started;
+ bool tx_queue =
+ (queue->qid == QID_AC_VO) ||
+ (queue->qid == QID_AC_VI) ||
+ (queue->qid == QID_AC_BE) ||
+ (queue->qid == QID_AC_BK);
+
+ mutex_lock(&queue->status_lock);
+
+ /*
+ * If the queue has been started, we must stop it temporarily
+ * to prevent any new frames to be queued on the device. If
+ * we are not dropping the pending frames, the queue must
+ * only be stopped in the software and not the hardware,
+ * otherwise the queue will never become empty on its own.
+ */
+ started = test_bit(QUEUE_STARTED, &queue->flags);
+ if (started) {
+ /*
+ * Pause the queue
+ */
+ rt2x00queue_pause_queue(queue);
+
+ /*
+ * If we are not supposed to drop any pending
+ * frames, this means we must force a start (=kick)
+ * to the queue to make sure the hardware will
+ * start transmitting.
+ */
+ if (!drop && tx_queue)
+ queue->rt2x00dev->ops->lib->kick_queue(queue);
+ }
+
+ /*
+ * Check if driver supports flushing, we can only guarentee
+ * full support for flushing if the driver is able
+ * to cancel all pending frames (drop = true).
+ */
+ if (drop && queue->rt2x00dev->ops->lib->flush_queue)
+ queue->rt2x00dev->ops->lib->flush_queue(queue);
+
+ /*
+ * When we don't want to drop any frames, or when
+ * the driver doesn't fully flush the queue correcly,
+ * we must wait for the queue to become empty.
+ */
+ for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++)
+ msleep(10);
+
+ /*
+ * The queue flush has failed...
+ */
+ if (unlikely(!rt2x00queue_empty(queue)))
+ WARNING(queue->rt2x00dev, "Queue %d failed to flush", queue->qid);
+
+ /*
+ * Restore the queue to the previous status
+ */
+ if (started)
+ rt2x00queue_unpause_queue(queue);
+
+ mutex_unlock(&queue->status_lock);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
+
+void rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * rt2x00queue_start_queue will call ieee80211_wake_queue
+ * for each queue after is has been properly initialized.
+ */
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_start_queue(queue);
+
+ rt2x00queue_start_queue(rt2x00dev->rx);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_start_queues);
+
+void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ /*
+ * rt2x00queue_stop_queue will call ieee80211_stop_queue
+ * as well, but we are completely shutting doing everything
+ * now, so it is much safer to stop all TX queues at once,
+ * and use rt2x00queue_stop_queue for cleaning up.
+ */
+ ieee80211_stop_queues(rt2x00dev->hw);
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_stop_queue(queue);
+
+ rt2x00queue_stop_queue(rt2x00dev->rx);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_stop_queues);
+
+void rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue)
+ rt2x00queue_flush_queue(queue, drop);
+
+ rt2x00queue_flush_queue(rt2x00dev->rx, drop);
+}
+EXPORT_SYMBOL_GPL(rt2x00queue_flush_queues);
+
static void rt2x00queue_reset(struct data_queue *queue)
{
unsigned long irqflags;
@@ -753,14 +960,6 @@ static void rt2x00queue_reset(struct data_queue *queue)
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
-void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
-{
- struct data_queue *queue;
-
- txall_queue_for_each(rt2x00dev, queue)
- rt2x00dev->ops->lib->kill_tx_queue(queue);
-}
-
void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
@@ -769,11 +968,8 @@ void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
queue_for_each(rt2x00dev, queue) {
rt2x00queue_reset(queue);
- for (i = 0; i < queue->limit; i++) {
+ for (i = 0; i < queue->limit; i++)
rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
- if (queue->qid == QID_RX)
- rt2x00queue_index_inc(queue, Q_INDEX);
- }
}
}
@@ -902,6 +1098,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
struct data_queue *queue, enum data_queue_qid qid)
{
+ mutex_init(&queue->status_lock);
spin_lock_init(&queue->index_lock);
queue->rt2x00dev = rt2x00dev;
@@ -944,7 +1141,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
/*
* Initialize queue parameters.
* RX: qid = QID_RX
- * TX: qid = QID_AC_BE + index
+ * TX: qid = QID_AC_VO + index
* TX: cw_min: 2^5 = 32.
* TX: cw_max: 2^10 = 1024.
* BCN: qid = QID_BEACON
@@ -952,7 +1149,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
*/
rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);
- qid = QID_AC_BE;
+ qid = QID_AC_VO;
tx_queue_for_each(rt2x00dev, queue)
rt2x00queue_init(rt2x00dev, queue, qid++);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 29b051ac6401..fab8e2687f29 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -45,10 +45,10 @@
/**
* enum data_queue_qid: Queue identification
*
+ * @QID_AC_VO: AC VO queue
+ * @QID_AC_VI: AC VI queue
* @QID_AC_BE: AC BE queue
* @QID_AC_BK: AC BK queue
- * @QID_AC_VI: AC VI queue
- * @QID_AC_VO: AC VO queue
* @QID_HCCA: HCCA queue
* @QID_MGMT: MGMT queue (prio queue)
* @QID_RX: RX queue
@@ -57,10 +57,10 @@
* @QID_ATIM: Atim queue (value unspeficied, don't send it to device)
*/
enum data_queue_qid {
- QID_AC_BE = 0,
- QID_AC_BK = 1,
- QID_AC_VI = 2,
- QID_AC_VO = 3,
+ QID_AC_VO = 0,
+ QID_AC_VI = 1,
+ QID_AC_BE = 2,
+ QID_AC_BK = 3,
QID_HCCA = 4,
QID_MGMT = 13,
QID_RX = 14,
@@ -340,12 +340,16 @@ struct txentry_desc {
* @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured
* while transfering the data to the hardware. No TX status report will
* be expected from the hardware.
+ * @ENTRY_DATA_STATUS_PENDING: The entry has been send to the device and
+ * returned. It is now waiting for the status reporting before the
+ * entry can be reused again.
*/
enum queue_entry_flags {
ENTRY_BCN_ASSIGNED,
ENTRY_OWNER_DEVICE_DATA,
ENTRY_DATA_PENDING,
- ENTRY_DATA_IO_FAILED
+ ENTRY_DATA_IO_FAILED,
+ ENTRY_DATA_STATUS_PENDING,
};
/**
@@ -392,12 +396,32 @@ enum queue_index {
};
/**
+ * enum data_queue_flags: Status flags for data queues
+ *
+ * @QUEUE_STARTED: The queue has been started. Fox RX queues this means the
+ * device might be DMA'ing skbuffers. TX queues will accept skbuffers to
+ * be transmitted and beacon queues will start beaconing the configured
+ * beacons.
+ * @QUEUE_PAUSED: The queue has been started but is currently paused.
+ * When this bit is set, the queue has been stopped in mac80211,
+ * preventing new frames to be enqueued. However, a few frames
+ * might still appear shortly after the pausing...
+ */
+enum data_queue_flags {
+ QUEUE_STARTED,
+ QUEUE_PAUSED,
+};
+
+/**
* struct data_queue: Data queue
*
* @rt2x00dev: Pointer to main &struct rt2x00dev where this queue belongs to.
* @entries: Base address of the &struct queue_entry which are
* part of this queue.
* @qid: The queue identification, see &enum data_queue_qid.
+ * @flags: Entry flags, see &enum queue_entry_flags.
+ * @status_lock: The mutex for protecting the start/stop/flush
+ * handling on this queue.
* @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or
* @index_crypt needs to be changed this lock should be grabbed to prevent
* index corruption due to concurrency.
@@ -421,8 +445,11 @@ struct data_queue {
struct queue_entry *entries;
enum data_queue_qid qid;
+ unsigned long flags;
+ struct mutex status_lock;
spinlock_t index_lock;
+
unsigned int count;
unsigned short limit;
unsigned short threshold;
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index ed71be95136d..e8259ae48ced 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -83,8 +83,6 @@ enum dev_state {
*/
STATE_RADIO_ON,
STATE_RADIO_OFF,
- STATE_RADIO_RX_ON,
- STATE_RADIO_RX_OFF,
STATE_RADIO_IRQ_ON,
STATE_RADIO_IRQ_OFF,
STATE_RADIO_IRQ_ON_ISR,
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 9ac14598e2a0..1a9937d5aff6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -195,7 +195,8 @@ static void rt2x00usb_work_txdone(struct work_struct *work)
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
rt2x00usb_work_txdone_entry(entry);
@@ -235,8 +236,10 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
u32 length;
+ int status;
- if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))
+ if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
+ test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
return;
/*
@@ -251,106 +254,15 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
entry->skb->data, length,
rt2x00usb_interrupt_txdone, entry);
- if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
}
-void rt2x00usb_kick_tx_queue(struct data_queue *queue)
-{
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_kick_tx_entry);
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_kick_tx_queue);
-
-static void rt2x00usb_kill_tx_entry(struct queue_entry *entry)
-{
- 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;
-
- if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return;
-
- usb_kill_urb(entry_priv->urb);
-
- /*
- * Kill guardian urb (if required by driver).
- */
- if ((entry->queue->qid == QID_BEACON) &&
- (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
- 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);
-
-static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- unsigned short threshold = queue->threshold;
-
- WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
- " invoke forced forced reset", queue->qid);
-
- /*
- * Temporarily disable the TX queue, this will force mac80211
- * to use the other queues until this queue has been restored.
- *
- * Set the queue threshold to the queue limit. This prevents the
- * queue from being enabled during the txdone handler.
- */
- queue->threshold = queue->limit;
- ieee80211_stop_queue(rt2x00dev->hw, queue->qid);
-
- /*
- * Kill all entries in the queue, afterwards we need to
- * wait a bit for all URBs to be cancelled.
- */
- rt2x00usb_kill_tx_queue(queue);
-
- /*
- * 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);
-
- /*
- * The queue has been reset, and mac80211 is allowed to use the
- * queue again.
- */
- queue->threshold = threshold;
- ieee80211_wake_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_empty(queue)) {
- if (rt2x00queue_dma_timeout(queue))
- rt2x00usb_watchdog_tx_dma(queue);
- if (rt2x00queue_status_timeout(queue))
- rt2x00usb_watchdog_tx_status(queue);
- }
- }
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
-
/*
* RX data handlers.
*/
@@ -365,7 +277,8 @@ static void rt2x00usb_work_rxdone(struct work_struct *work)
while (!rt2x00queue_empty(rt2x00dev->rx)) {
entry = rt2x00queue_get_entry(rt2x00dev->rx, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
/*
@@ -410,6 +323,154 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work);
}
+static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct queue_entry_priv_usb *entry_priv = entry->priv_data;
+ int status;
+
+ if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ return;
+
+ rt2x00lib_dmastart(entry);
+
+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,
+ usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint),
+ entry->skb->data, entry->skb->len,
+ rt2x00usb_interrupt_rxdone, entry);
+
+ status = usb_submit_urb(entry_priv->urb, GFP_ATOMIC);
+ if (status) {
+ if (status == -ENODEV)
+ clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
+ set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ rt2x00lib_dmadone(entry);
+ }
+}
+
+void rt2x00usb_kick_queue(struct data_queue *queue)
+{
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ if (!rt2x00queue_empty(queue))
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_tx_entry);
+ break;
+ case QID_RX:
+ if (!rt2x00queue_full(queue))
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_kick_rx_entry);
+ break;
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
+
+static void rt2x00usb_flush_entry(struct queue_entry *entry)
+{
+ 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;
+
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return;
+
+ usb_kill_urb(entry_priv->urb);
+
+ /*
+ * Kill guardian urb (if required by driver).
+ */
+ if ((entry->queue->qid == QID_BEACON) &&
+ (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+ usb_kill_urb(bcn_priv->guardian_urb);
+}
+
+void rt2x00usb_flush_queue(struct data_queue *queue)
+{
+ struct work_struct *completion;
+ unsigned int i;
+
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00usb_flush_entry);
+
+ /*
+ * Obtain the queue completion handler
+ */
+ switch (queue->qid) {
+ case QID_AC_VO:
+ case QID_AC_VI:
+ case QID_AC_BE:
+ case QID_AC_BK:
+ completion = &queue->rt2x00dev->txdone_work;
+ break;
+ case QID_RX:
+ completion = &queue->rt2x00dev->rxdone_work;
+ break;
+ default:
+ return;
+ }
+
+ for (i = 0; i < 20; i++) {
+ /*
+ * Check if the driver is already done, otherwise we
+ * have to sleep a little while to give the driver/hw
+ * the oppurtunity to complete interrupt process itself.
+ */
+ if (rt2x00queue_empty(queue))
+ break;
+
+ /*
+ * Schedule the completion handler manually, when this
+ * worker function runs, it should cleanup the queue.
+ */
+ ieee80211_queue_work(queue->rt2x00dev->hw, completion);
+
+ /*
+ * Wait for a little while to give the driver
+ * the oppurtunity to recover itself.
+ */
+ msleep(10);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_flush_queue);
+
+static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
+{
+ WARNING(queue->rt2x00dev, "TX queue %d DMA timed out,"
+ " invoke forced forced reset\n", queue->qid);
+
+ rt2x00queue_flush_queue(queue, true);
+}
+
+static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
+{
+ WARNING(queue->rt2x00dev, "TX queue %d status timed out,"
+ " invoke forced tx handler\n", 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_empty(queue)) {
+ if (rt2x00queue_dma_timeout(queue))
+ rt2x00usb_watchdog_tx_dma(queue);
+ if (rt2x00queue_status_timeout(queue))
+ rt2x00usb_watchdog_tx_status(queue);
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_watchdog);
+
/*
* Radio handlers
*/
@@ -417,12 +478,6 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0, 0,
REGISTER_TIMEOUT);
-
- /*
- * The USB version of kill_tx_queue also works
- * on the RX queue.
- */
- rt2x00dev->ops->lib->kill_tx_queue(rt2x00dev->rx);
}
EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
@@ -431,25 +486,10 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
*/
void rt2x00usb_clear_entry(struct queue_entry *entry)
{
- struct usb_device *usb_dev =
- to_usb_device_intf(entry->queue->rt2x00dev->dev);
- struct queue_entry_priv_usb *entry_priv = entry->priv_data;
- int pipe;
-
entry->flags = 0;
- if (entry->queue->qid == QID_RX) {
- pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint);
- usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe,
- entry->skb->data, entry->skb->len,
- rt2x00usb_interrupt_rxdone, entry);
-
- set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- if (usb_submit_urb(entry_priv->urb, GFP_ATOMIC)) {
- set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
- rt2x00lib_dmadone(entry);
- }
- }
+ if (entry->queue->qid == QID_RX)
+ rt2x00usb_kick_rx_entry(entry);
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index c2d997f67b3e..6aaf51fc7ad8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -378,22 +378,22 @@ struct queue_entry_priv_usb_bcn {
};
/**
- * rt2x00usb_kick_tx_queue - Kick data queue
+ * rt2x00usb_kick_queue - Kick data queue
* @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 data_queue *queue);
+void rt2x00usb_kick_queue(struct data_queue *queue);
/**
- * rt2x00usb_kill_tx_queue - Kill data queue
- * @queue: Data queue to kill
+ * rt2x00usb_flush_queue - Flush data queue
+ * @queue: Data queue to stop
*
* This will walk through all entries of the queue and kill all
- * previously kicked frames before they can be send.
+ * URB's which were send to the device.
*/
-void rt2x00usb_kill_tx_queue(struct data_queue *queue);
+void rt2x00usb_flush_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 6b09b01f634f..8de44dd401e0 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1140,6 +1140,106 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt61pci_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt61pci_kick_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt61pci_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_AC_VO:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_VI:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BE:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_AC_BK:
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+ break;
+ case QID_RX:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1616,17 +1716,6 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
enum dev_state state)
{
@@ -1743,10 +1832,6 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt61pci_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt61pci_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1876,6 +1961,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;
/*
@@ -1897,13 +1983,16 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
entry_priv->desc, TXINFO_SIZE);
rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
- entry->skb->data, entry->skb->len);
+ entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -1925,37 +2014,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
entry->skb = NULL;
}
-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, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, 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 data_queue *queue)
-{
- struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- u32 reg;
-
- if (queue->qid == QID_BEACON) {
- rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
- return;
- }
-
- rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, (queue->qid == QID_AC_BE));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, (queue->qid == QID_AC_BK));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, (queue->qid == QID_AC_VI));
- rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, (queue->qid == QID_AC_VO));
- rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
-}
-
/*
* RX control handlers
*/
@@ -2840,10 +2898,11 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.link_stats = rt61pci_link_stats,
.reset_tuner = rt61pci_reset_tuner,
.link_tuner = rt61pci_link_tuner,
+ .start_queue = rt61pci_start_queue,
+ .kick_queue = rt61pci_kick_queue,
+ .stop_queue = rt61pci_stop_queue,
.write_tx_desc = rt61pci_write_tx_desc,
.write_beacon = rt61pci_write_beacon,
- .kick_tx_queue = rt61pci_kick_tx_queue,
- .kill_tx_queue = rt61pci_kill_tx_queue,
.fill_rxdone = rt61pci_fill_rxdone,
.config_shared_key = rt61pci_config_shared_key,
.config_pairwise_key = rt61pci_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index afc803b7959f..e3cd6db76b0e 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -784,25 +784,25 @@ struct hw_pairwise_ta_entry {
*/
/*
- * AC0_BASE_CSR: AC_BK base address.
+ * AC0_BASE_CSR: AC_VO base address.
*/
#define AC0_BASE_CSR 0x3400
#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * AC1_BASE_CSR: AC_BE base address.
+ * AC1_BASE_CSR: AC_VI base address.
*/
#define AC1_BASE_CSR 0x3404
#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * AC2_BASE_CSR: AC_VI base address.
+ * AC2_BASE_CSR: AC_BE base address.
*/
#define AC2_BASE_CSR 0x3408
#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * AC3_BASE_CSR: AC_VO base address.
+ * AC3_BASE_CSR: AC_BK base address.
*/
#define AC3_BASE_CSR 0x340c
#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
@@ -814,7 +814,7 @@ struct hw_pairwise_ta_entry {
#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
/*
- * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
+ * TX_RING_CSR0: TX Ring size for AC_VO, AC_VI, AC_BE, AC_BK.
*/
#define TX_RING_CSR0 0x3418
#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff)
@@ -833,10 +833,10 @@ struct hw_pairwise_ta_entry {
/*
* AIFSN_CSR: AIFSN for each EDCA AC.
- * AIFSN0: For AC_BK.
- * AIFSN1: For AC_BE.
- * AIFSN2: For AC_VI.
- * AIFSN3: For AC_VO.
+ * AIFSN0: For AC_VO.
+ * AIFSN1: For AC_VI.
+ * AIFSN2: For AC_BE.
+ * AIFSN3: For AC_BK.
*/
#define AIFSN_CSR 0x3420
#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
@@ -846,10 +846,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMIN_CSR: CWmin for each EDCA AC.
- * CWMIN0: For AC_BK.
- * CWMIN1: For AC_BE.
- * CWMIN2: For AC_VI.
- * CWMIN3: For AC_VO.
+ * CWMIN0: For AC_VO.
+ * CWMIN1: For AC_VI.
+ * CWMIN2: For AC_BE.
+ * CWMIN3: For AC_BK.
*/
#define CWMIN_CSR 0x3424
#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
@@ -859,10 +859,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMAX_CSR: CWmax for each EDCA AC.
- * CWMAX0: For AC_BK.
- * CWMAX1: For AC_BE.
- * CWMAX2: For AC_VI.
- * CWMAX3: For AC_VO.
+ * CWMAX0: For AC_VO.
+ * CWMAX1: For AC_VI.
+ * CWMAX2: For AC_BE.
+ * CWMAX3: For AC_BK.
*/
#define CWMAX_CSR 0x3428
#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
@@ -883,14 +883,14 @@ struct hw_pairwise_ta_entry {
/*
* TX_CNTL_CSR: KICK/Abort TX.
- * KICK_TX_AC0: For AC_BK.
- * KICK_TX_AC1: For AC_BE.
- * KICK_TX_AC2: For AC_VI.
- * KICK_TX_AC3: For AC_VO.
- * ABORT_TX_AC0: For AC_BK.
- * ABORT_TX_AC1: For AC_BE.
- * ABORT_TX_AC2: For AC_VI.
- * ABORT_TX_AC3: For AC_VO.
+ * KICK_TX_AC0: For AC_VO.
+ * KICK_TX_AC1: For AC_VI.
+ * KICK_TX_AC2: For AC_BE.
+ * KICK_TX_AC3: For AC_BK.
+ * ABORT_TX_AC0: For AC_VO.
+ * ABORT_TX_AC1: For AC_VI.
+ * ABORT_TX_AC2: For AC_BE.
+ * ABORT_TX_AC3: For AC_BK.
*/
#define TX_CNTL_CSR 0x3430
#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001)
@@ -1010,18 +1010,18 @@ struct hw_pairwise_ta_entry {
#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
/*
- * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
- * AC0_TX_OP: For AC_BK, in unit of 32us.
- * AC1_TX_OP: For AC_BE, in unit of 32us.
+ * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
+ * AC0_TX_OP: For AC_VO, in unit of 32us.
+ * AC1_TX_OP: For AC_VI, in unit of 32us.
*/
#define AC_TXOP_CSR0 0x3474
#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
/*
- * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
- * AC2_TX_OP: For AC_VI, in unit of 32us.
- * AC3_TX_OP: For AC_VO, in unit of 32us.
+ * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
+ * AC2_TX_OP: For AC_BE, in unit of 32us.
+ * AC3_TX_OP: For AC_BK, in unit of 32us.
*/
#define AC_TXOP_CSR1 0x3478
#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6f04552f5819..029be3c6c030 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1031,6 +1031,55 @@ dynamic_cca_tune:
}
/*
+ * Queue handlers.
+ */
+static void rt73usb_start_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+static void rt73usb_stop_queue(struct data_queue *queue)
+{
+ struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+ u32 reg;
+
+ switch (queue->qid) {
+ case QID_RX:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 1);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+ break;
+ case QID_BEACON:
+ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
* Firmware functions
*/
static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -1324,17 +1373,6 @@ static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
/*
* Device state switch handlers.
*/
-static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
- enum dev_state state)
-{
- u32 reg;
-
- rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
- rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
- (state == STATE_RADIO_RX_OFF));
- rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg);
-}
-
static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
@@ -1401,10 +1439,6 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
case STATE_RADIO_OFF:
rt73usb_disable_radio(rt2x00dev);
break;
- case STATE_RADIO_RX_ON:
- case STATE_RADIO_RX_OFF:
- rt73usb_toggle_rx(rt2x00dev, state);
- break;
case STATE_RADIO_IRQ_ON:
case STATE_RADIO_IRQ_ON_ISR:
case STATE_RADIO_IRQ_OFF:
@@ -1512,6 +1546,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
unsigned int beacon_base;
+ unsigned int padding_len;
u32 reg;
/*
@@ -1539,11 +1574,13 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
- * Write entire beacon with descriptor to register.
+ * Write entire beacon with descriptor and padding to register.
*/
+ padding_len = roundup(entry->skb->len, 4) - entry->skb->len;
+ skb_pad(entry->skb, padding_len);
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
+ rt2x00usb_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data,
+ entry->skb->len + padding_len);
/*
* Enable beaconing again.
@@ -1579,14 +1616,6 @@ 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
*/
@@ -2278,11 +2307,13 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
.reset_tuner = rt73usb_reset_tuner,
.link_tuner = rt73usb_link_tuner,
.watchdog = rt2x00usb_watchdog,
+ .start_queue = rt73usb_start_queue,
+ .kick_queue = rt2x00usb_kick_queue,
+ .stop_queue = rt73usb_stop_queue,
+ .flush_queue = rt2x00usb_flush_queue,
.write_tx_desc = rt73usb_write_tx_desc,
.write_beacon = rt73usb_write_beacon,
.get_tx_data_len = rt73usb_get_tx_data_len,
- .kick_tx_queue = rt2x00usb_kick_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,
@@ -2415,6 +2446,7 @@ static struct usb_device_id rt73usb_device_table[] = {
{ USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
/* Qcom */
{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 1315ce5c992f..9f6b470414d3 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -689,10 +689,10 @@ struct hw_pairwise_ta_entry {
/*
* AIFSN_CSR: AIFSN for each EDCA AC.
- * AIFSN0: For AC_BK.
- * AIFSN1: For AC_BE.
- * AIFSN2: For AC_VI.
- * AIFSN3: For AC_VO.
+ * AIFSN0: For AC_VO.
+ * AIFSN1: For AC_VI.
+ * AIFSN2: For AC_BE.
+ * AIFSN3: For AC_BK.
*/
#define AIFSN_CSR 0x0400
#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
@@ -702,10 +702,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMIN_CSR: CWmin for each EDCA AC.
- * CWMIN0: For AC_BK.
- * CWMIN1: For AC_BE.
- * CWMIN2: For AC_VI.
- * CWMIN3: For AC_VO.
+ * CWMIN0: For AC_VO.
+ * CWMIN1: For AC_VI.
+ * CWMIN2: For AC_BE.
+ * CWMIN3: For AC_BK.
*/
#define CWMIN_CSR 0x0404
#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
@@ -715,10 +715,10 @@ struct hw_pairwise_ta_entry {
/*
* CWMAX_CSR: CWmax for each EDCA AC.
- * CWMAX0: For AC_BK.
- * CWMAX1: For AC_BE.
- * CWMAX2: For AC_VI.
- * CWMAX3: For AC_VO.
+ * CWMAX0: For AC_VO.
+ * CWMAX1: For AC_VI.
+ * CWMAX2: For AC_BE.
+ * CWMAX3: For AC_BK.
*/
#define CWMAX_CSR 0x0408
#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
@@ -727,18 +727,18 @@ struct hw_pairwise_ta_entry {
#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)
/*
- * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
- * AC0_TX_OP: For AC_BK, in unit of 32us.
- * AC1_TX_OP: For AC_BE, in unit of 32us.
+ * AC_TXOP_CSR0: AC_VO/AC_VI TXOP register.
+ * AC0_TX_OP: For AC_VO, in unit of 32us.
+ * AC1_TX_OP: For AC_VI, in unit of 32us.
*/
#define AC_TXOP_CSR0 0x040c
#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
/*
- * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
- * AC2_TX_OP: For AC_VI, in unit of 32us.
- * AC3_TX_OP: For AC_VO, in unit of 32us.
+ * AC_TXOP_CSR1: AC_BE/AC_BK TXOP register.
+ * AC2_TX_OP: For AC_BE, in unit of 32us.
+ * AC3_TX_OP: For AC_BK, in unit of 32us.
*/
#define AC_TXOP_CSR1 0x0410
#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)