From 69cf36a4523be026bc16743c5c989c5e82edb7d9 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sun, 30 Jan 2011 13:16:03 +0100 Subject: rt2x00: Refactor beacon code to make use of start- and stop_queue This patch allows to dynamically remove beaconing interfaces without shutting beaconing down on all interfaces. The only place to start and stop beaconing are now the start- and stop_queue callbacks. Hence, we can remove some register writes during interface bring up (config_intf) and only write the correct sync mode to the register there. When multiple beaconing interfaces are present we should enable beaconing as soon as mac80211 enables beaconing on at least one of them. The beacon queue gets stopped when the last beaconing interface was stopped by mac80211. Therefore, introduce another interface counter to keep track ot the number of enabled beaconing interfaces and start or stop the beacon queue accordingly. To allow single interfaces to stop beaconing, add a new driver callback clear_beacon to clear a single interface's beacon without affecting the other interfaces. Don't overload the clear_entry callback for clearing beacons as that would introduce additional overhead (check for each TX queue) into the clear_entry callback which is used on the drivers TX/RX hotpaths. Furthermore, the write beacon callback doesn't need to enable beaconing anymore but since beaconing should be disabled while a new beacon is written or cleared we still disable beacon generation and enable it afterwards again in the driver specific callbacks. However, beacon related interrupts should not be disabled/enabled here, that's solely done from the start- and stop queue callbacks. It would be nice to stop the beacon queue just before the beacon update and enable it afterwards in rt2x00queue itself instead of the current implementation that relies on the driver doing the right thing. However, since start- and stop_queue are mutex protected we cannot use them for atomic beacon updates. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 41 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 8de44dd401e0..f14cc452eb0c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -551,26 +551,14 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00intf_conf *conf, const unsigned int flags) { - unsigned int beacon_base; u32 reg; if (flags & CONFIG_UPDATE_TYPE) { - /* - * Clear current synchronisation setup. - * For the Beacon base registers, we only need to clear - * the first byte since that byte contains the VALID and OWNER - * bits which (when set to 0) will invalidate the entire beacon. - */ - beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx); - rt2x00pci_register_write(rt2x00dev, beacon_base, 0); - /* * Enable synchronisation. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, conf->sync); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); } @@ -2002,8 +1990,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry, */ rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); - rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2014,6 +2000,32 @@ static void rt61pci_write_beacon(struct queue_entry *entry, entry->skb = NULL; } +static void rt61pci_clear_beacon(struct queue_entry *entry) +{ + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; + u32 reg; + + /* + * Disable beaconing while we are reloading the beacon data, + * otherwise we might be sending out invalid data. + */ + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Clear beacon. + */ + rt2x00pci_register_write(rt2x00dev, + HW_BEACON_OFFSET(entry->entry_idx), 0); + + /* + * Enable beaconing again. + */ + rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 1); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); +} + /* * RX control handlers */ @@ -2903,6 +2915,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .stop_queue = rt61pci_stop_queue, .write_tx_desc = rt61pci_write_tx_desc, .write_beacon = rt61pci_write_beacon, + .clear_beacon = rt61pci_clear_beacon, .fill_rxdone = rt61pci_fill_rxdone, .config_shared_key = rt61pci_config_shared_key, .config_pairwise_key = rt61pci_config_pairwise_key, -- cgit v1.2.3 From 5846a550b5838ea7fe8e280caff159a5ddb5c7e1 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sun, 30 Jan 2011 13:19:08 +0100 Subject: rt2x00: Convert rt61pci to use tasklets Fix interrupt processing on slow machines by using individual tasklets for each different device interrupt. This ensures that while a RX or TX status tasklet is scheduled only the according device interrupt is masked and other interrupts such as TBTT can still be processed. Also, this allows us to use tasklet_hi_schedule for TBTT processing which is required to not send out beacons with a wrong DTIM count (due to delayed periodic beacon updates). Furthermore, this improves the latency between the TBTT and sending out buffered multi- and broadcast traffic. As a nice bonus, the interrupt handling overhead should be much lower. Compile-tested only. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 175 +++++++++++++++++++++++++--------- 1 file changed, 130 insertions(+), 45 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f14cc452eb0c..351055d4b89b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1142,6 +1142,11 @@ static void rt61pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: + /* + * Allow the tbtt tasklet to be scheduled. + */ + tasklet_enable(&rt2x00dev->tbtt_tasklet); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); @@ -1221,6 +1226,11 @@ static void rt61pci_stop_queue(struct data_queue *queue) rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); + + /* + * Wait for possibly running tbtt tasklets. + */ + tasklet_disable(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -1710,6 +1720,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, int mask = (state == STATE_RADIO_IRQ_OFF) || (state == STATE_RADIO_IRQ_OFF_ISR); u32 reg; + unsigned long flags; /* * When interrupts are being enabled, the interrupt registers @@ -1721,12 +1732,21 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); + + /* + * Enable tasklets. + */ + tasklet_enable(&rt2x00dev->txstatus_tasklet); + tasklet_enable(&rt2x00dev->rxdone_tasklet); + tasklet_enable(&rt2x00dev->autowake_tasklet); } /* * Only toggle the interrupts bits we are going to use. * Non-checked interrupt bits are disabled by default. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, INT_MASK_CSR_TXDONE, mask); rt2x00_set_field32(®, INT_MASK_CSR_RXDONE, mask); @@ -1746,6 +1766,17 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MCU_INT_MASK_CSR_7, mask); rt2x00_set_field32(®, MCU_INT_MASK_CSR_TWAKEUP, mask); rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + if (state == STATE_RADIO_IRQ_OFF) { + /* + * Ensure that all tasklets are finished. + */ + tasklet_disable(&rt2x00dev->txstatus_tasklet); + tasklet_disable(&rt2x00dev->rxdone_tasklet); + tasklet_disable(&rt2x00dev->autowake_tasklet); + } } static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -2223,61 +2254,80 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); } -static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance) +static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) { - struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg = rt2x00dev->irqvalue[0]; - u32 reg_mcu = rt2x00dev->irqvalue[1]; + unsigned long flags; + u32 reg; /* - * Handle interrupts, walk through all bits - * and run the tasks, the bits are checked in order of - * priority. + * Enable a single interrupt. The interrupt mask register + * access needs locking. */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* - * 1 - Rx ring done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) - rt2x00pci_rxdone(rt2x00dev); + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + rt2x00_set_field32(®, irq_field, 0); + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); - /* - * 2 - Tx ring done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) - rt61pci_txdone(rt2x00dev); + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); +} - /* - * 3 - Handle MCU command done. - */ - if (reg_mcu) - rt2x00pci_register_write(rt2x00dev, - M2H_CMD_DONE_CSR, 0xffffffff); +static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, + struct rt2x00_field32 irq_field) +{ + unsigned long flags; + u32 reg; /* - * 4 - MCU Autowakeup interrupt. + * Enable a single MCU interrupt. The interrupt mask register + * access needs locking. */ - if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) - rt61pci_wakeup(rt2x00dev); + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - /* - * 5 - Beacon done interrupt. - */ - if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) - rt2x00lib_beacondone(rt2x00dev); + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + rt2x00_set_field32(®, irq_field, 0); + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); - /* Enable interrupts again. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_ON_ISR); - return IRQ_HANDLED; + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); } +static void rt61pci_txstatus_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt61pci_txdone(rt2x00dev); + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); +} + +static void rt61pci_tbtt_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00lib_beacondone(rt2x00dev); + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); +} + +static void rt61pci_rxdone_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt2x00pci_rxdone(rt2x00dev); + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); +} + +static void rt61pci_autowake_tasklet(unsigned long data) +{ + struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; + rt61pci_wakeup(rt2x00dev); + rt2x00pci_register_write(rt2x00dev, + M2H_CMD_DONE_CSR, 0xffffffff); + rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); +} static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; - u32 reg_mcu; - u32 reg; + u32 reg_mcu, mask_mcu; + u32 reg, mask; + unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -2295,14 +2345,46 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) return IRQ_HANDLED; - /* Store irqvalues for use in the interrupt thread. */ - rt2x00dev->irqvalue[0] = reg; - rt2x00dev->irqvalue[1] = reg_mcu; + /* + * Schedule tasklets for interrupt handling. + */ + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE)) + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE)) + tasklet_schedule(&rt2x00dev->txstatus_tasklet); + + if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) + tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); + + if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) + tasklet_schedule(&rt2x00dev->autowake_tasklet); + + /* + * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits + * for interrupts and interrupt masks we can just use the value of + * INT_SOURCE_CSR to create the interrupt mask. + */ + mask = reg; + mask_mcu = reg_mcu; + + /* + * Disable all interrupts for which a tasklet was scheduled right now, + * the tasklet will reenable the appropriate interrupts. + */ + spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + + rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); + reg |= mask; + rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); - /* Disable interrupts, will be enabled again in the interrupt thread. */ - rt2x00dev->ops->lib->set_device_state(rt2x00dev, - STATE_RADIO_IRQ_OFF_ISR); - return IRQ_WAKE_THREAD; + rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); + reg |= mask_mcu; + rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); + + spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + + return IRQ_HANDLED; } /* @@ -2896,7 +2978,10 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .irq_handler = rt61pci_interrupt, - .irq_handler_thread = rt61pci_interrupt_thread, + .txstatus_tasklet = rt61pci_txstatus_tasklet, + .tbtt_tasklet = rt61pci_tbtt_tasklet, + .rxdone_tasklet = rt61pci_rxdone_tasklet, + .autowake_tasklet = rt61pci_autowake_tasklet, .probe_hw = rt61pci_probe_hw, .get_firmware_name = rt61pci_get_firmware_name, .check_firmware = rt61pci_check_firmware, -- cgit v1.2.3 From b550911abc0db069bb157f9769ffb7cf22c6c868 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Sun, 30 Jan 2011 13:20:52 +0100 Subject: rt2x00: Remove STATE_RADIO_IRQ_OFF_ISR and STATE_RADIO_IRQ_ON_ISR Remove STATE_RADIO_IRQ_OFF_ISR and STATE_RADIO_IRQ_ON_ISR as they are not used anymore. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2500pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2500usb.c | 2 -- drivers/net/wireless/rt2x00/rt2800pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2800usb.c | 2 -- drivers/net/wireless/rt2x00/rt2x00reg.h | 2 -- drivers/net/wireless/rt2x00/rt61pci.c | 5 +---- drivers/net/wireless/rt2x00/rt73usb.c | 2 -- 8 files changed, 4 insertions(+), 24 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b324917106e6..5c88fdc136a4 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -971,8 +971,7 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_OFF) || - (state == STATE_RADIO_IRQ_OFF_ISR); + int mask = (state == STATE_RADIO_IRQ_OFF); u32 reg; unsigned long flags; @@ -1087,9 +1086,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2400pci_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt2400pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 7daa483c3742..3ef1fb4185c0 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1126,8 +1126,7 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_OFF) || - (state == STATE_RADIO_IRQ_OFF_ISR); + int mask = (state == STATE_RADIO_IRQ_OFF); u32 reg; unsigned long flags; @@ -1241,9 +1240,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2500pci_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt2500pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 157516e0aab7..01f385d5846c 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1054,9 +1054,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt2500usb_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: /* No support, but no error either */ break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 31483c79a457..208ea5e966ed 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -418,8 +418,7 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_ON) || - (state == STATE_RADIO_IRQ_ON_ISR); + int mask = (state == STATE_RADIO_IRQ_ON); u32 reg; unsigned long flags; @@ -564,9 +563,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2800pci_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt2800pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3ebe473f8551..3d2a944814bc 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -253,9 +253,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt2800usb_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: /* No support, but no error either */ break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index e8259ae48ced..6f867eec49cc 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -85,8 +85,6 @@ enum dev_state { STATE_RADIO_OFF, STATE_RADIO_IRQ_ON, STATE_RADIO_IRQ_OFF, - STATE_RADIO_IRQ_ON_ISR, - STATE_RADIO_IRQ_OFF_ISR, }; /* diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 351055d4b89b..3afafabda080 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1717,8 +1717,7 @@ static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev) static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_OFF) || - (state == STATE_RADIO_IRQ_OFF_ISR); + int mask = (state == STATE_RADIO_IRQ_OFF); u32 reg; unsigned long flags; @@ -1852,9 +1851,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt61pci_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: rt61pci_toggle_irq(rt2x00dev, state); break; case STATE_DEEP_SLEEP: diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 330353ec5c96..aa9c61c7f376 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1428,9 +1428,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt73usb_disable_radio(rt2x00dev); break; case STATE_RADIO_IRQ_ON: - case STATE_RADIO_IRQ_ON_ISR: case STATE_RADIO_IRQ_OFF: - case STATE_RADIO_IRQ_OFF_ISR: /* No support, but no error either */ break; case STATE_DEEP_SLEEP: -- cgit v1.2.3 From a0aff623ca8bc8779e6c3a394772d70d8a65dee9 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sun, 30 Jan 2011 13:23:22 +0100 Subject: rt2x00: Fix FIXME comments in rt61pci and rt73usb on Michael MIC. Both rt61pci and rt73usb check the Michael MIC in hardware and strip the Michael MIC from received frames. This is perfectly allowed by mac80211 as long as this is properly reported to mac80211. Both these drivers reported the Michael MIC handling properly to mac80211, but still contained a FIXME comment on this, which is not needed to be handled, since mac80211 doesn't really need the Michael MIC in this case. Signed-off-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.c | 5 ++--- drivers/net/wireless/rt2x00/rt73usb.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3afafabda080..dd2164d4d57b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2118,9 +2118,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_IV_STRIPPED; /* - * FIXME: Legacy driver indicates that the frame does - * contain the Michael Mic. Unfortunately, in rt2x00 - * the MIC seems to be missing completely... + * The hardware has already checked the Michael Mic and has + * stripped it from the frame. Signal this to mac80211. */ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index aa9c61c7f376..5ff72deea8d4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1709,9 +1709,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, rxdesc->flags |= RX_FLAG_IV_STRIPPED; /* - * FIXME: Legacy driver indicates that the frame does - * contain the Michael Mic. Unfortunately, in rt2x00 - * the MIC seems to be missing completely... + * The hardware has already checked the Michael Mic and has + * stripped it from the frame. Signal this to mac80211. */ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; -- cgit v1.2.3 From d76dfc612b40b6a9de0a3fe57fe1fa3db7a1ae3b Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Mon, 14 Feb 2011 08:52:25 -0600 Subject: rt2x00: Check for errors from skb_pad() calls Commit 739fd94 ("rt2x00: Pad beacon to multiple of 32 bits") added calls to skb_pad() without checking the return value, which could cause problems if any of those calls does happen to fail. Add checks to prevent this from happening. Signed-off-by: Seth Forshee Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 12 ++++++++++-- drivers/net/wireless/rt2x00/rt61pci.c | 12 ++++++++++-- drivers/net/wireless/rt2x00/rt73usb.c | 12 ++++++++++-- 3 files changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index c9bf074342ba..7a68a67c506a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -773,13 +773,14 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); unsigned int beacon_base; unsigned int padding_len; - u32 reg; + u32 orig_reg, reg; /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, ®); + orig_reg = reg; rt2x00_set_field32(®, BCN_TIME_CFG_BEACON_GEN, 0); rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); @@ -810,7 +811,14 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) * 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); + if (padding_len && skb_pad(entry->skb, padding_len)) { + ERROR(rt2x00dev, "Failure padding beacon, aborting\n"); + /* skb freed by skb_pad() on failure */ + entry->skb = NULL; + rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg); + return; + } + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); rt2800_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, entry->skb->len + padding_len); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index dd2164d4d57b..927a4a3e0eeb 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1978,13 +1978,14 @@ static void rt61pci_write_beacon(struct queue_entry *entry, struct queue_entry_priv_pci *entry_priv = entry->priv_data; unsigned int beacon_base; unsigned int padding_len; - u32 reg; + u32 orig_reg, reg; /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); + orig_reg = reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -2002,7 +2003,14 @@ static void rt61pci_write_beacon(struct queue_entry *entry, * 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); + if (padding_len && skb_pad(entry->skb, padding_len)) { + ERROR(rt2x00dev, "Failure padding beacon, aborting\n"); + /* skb freed by skb_pad() on failure */ + entry->skb = NULL; + rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, orig_reg); + return; + } + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); rt2x00pci_register_multiwrite(rt2x00dev, beacon_base, entry_priv->desc, TXINFO_SIZE); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 5ff72deea8d4..6e9981a1dd7f 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1533,13 +1533,14 @@ 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; + u32 orig_reg, reg; /* * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); + orig_reg = reg; rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -1563,7 +1564,14 @@ static void rt73usb_write_beacon(struct queue_entry *entry, * 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); + if (padding_len && skb_pad(entry->skb, padding_len)) { + ERROR(rt2x00dev, "Failure padding beacon, aborting\n"); + /* skb freed by skb_pad() on failure */ + entry->skb = NULL; + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg); + return; + } + beacon_base = HW_BEACON_OFFSET(entry->entry_idx); rt2x00usb_register_multiwrite(rt2x00dev, beacon_base, entry->skb->data, entry->skb->len + padding_len); -- cgit v1.2.3 From 11f818e0eb50864c7e6f8af38d8f8822f992906a Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 3 Mar 2011 19:38:55 +0100 Subject: rt2x00: Optimize calls to rt2x00queue_get_queue In some cases (tx path for example) we don't need to check for non-tx queues in rt2x00queue_get_queue. Hence, introduce a new method rt2x00queue_get_tx_queue that is only valid for tx queues and use it in places where only tx queues are valid. Furthermore, this new method is quite short and as such can be inlined to avoid the function call overhead. This only converts the txdone functions of drivers that don't use an ATIM queue and the generic tx path. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 4 ++-- drivers/net/wireless/rt2x00/rt2800pci.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 17 +++++++++++++++++ drivers/net/wireless/rt2x00/rt2x00mac.c | 4 ++-- drivers/net/wireless/rt2x00/rt61pci.c | 4 ++-- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 6 files changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dbee3f12d636..76ced6dcee05 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -751,7 +751,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) if (pid >= QID_RX) continue; - queue = rt2x00queue_get_queue(rt2x00dev, pid); + queue = rt2x00queue_get_tx_queue(rt2x00dev, pid); if (unlikely(!queue)) continue; @@ -3974,7 +3974,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, if (queue_idx >= 4) return 0; - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); /* Update WMM TXOP register */ offset = WMM_TXOP0_CFG + (sizeof(u32) * (!!(queue_idx & 2))); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6c634c3a2e01..5b53d005559b 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -736,7 +736,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) break; } - queue = rt2x00queue_get_queue(rt2x00dev, qid); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); if (unlikely(queue == NULL)) { /* * The queue is NULL, this shouldn't happen. Stop diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 19453d23e90d..2f5d8de5ef14 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1062,6 +1062,23 @@ void rt2x00queue_map_txskb(struct queue_entry *entry); */ void rt2x00queue_unmap_skb(struct queue_entry *entry); +/** + * rt2x00queue_get_tx_queue - Convert tx queue index to queue pointer + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * @queue: rt2x00 queue index (see &enum data_queue_qid). + * + * Returns NULL for non tx queues. + */ +static inline struct data_queue * +rt2x00queue_get_tx_queue(struct rt2x00_dev *rt2x00dev, + const enum data_queue_qid queue) +{ + if (queue < rt2x00dev->ops->tx_queues && rt2x00dev->tx) + return &rt2x00dev->tx[queue]; + + return NULL; +} + /** * rt2x00queue_get_queue - Convert queue index to queue pointer * @rt2x00dev: Pointer to &struct rt2x00_dev. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c2c35838c2f3..7714198b9d3e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -122,7 +122,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) queue = rt2x00queue_get_queue(rt2x00dev, QID_ATIM); else - queue = rt2x00queue_get_queue(rt2x00dev, qid); + queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); if (unlikely(!queue)) { ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" @@ -692,7 +692,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, struct rt2x00_dev *rt2x00dev = hw->priv; struct data_queue *queue; - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); if (unlikely(!queue)) return -EINVAL; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 927a4a3e0eeb..2ed845b1ea3c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2190,7 +2190,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) * queue identication number. */ type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE); - queue = rt2x00queue_get_queue(rt2x00dev, type); + queue = rt2x00queue_get_tx_queue(rt2x00dev, type); if (unlikely(!queue)) continue; @@ -2917,7 +2917,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, if (queue_idx >= 4) return 0; - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); /* Update WMM TXOP register */ offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2))); diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6e9981a1dd7f..a799c262c1db 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2247,7 +2247,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, if (queue_idx >= 4) return 0; - queue = rt2x00queue_get_queue(rt2x00dev, queue_idx); + queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); /* Update WMM TXOP register */ offset = AC_TXOP_CSR0 + (sizeof(u32) * (!!(queue_idx & 2))); -- cgit v1.2.3 From 26a1d07f4176099a7b6f45009dad054e6ad5b7e4 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 3 Mar 2011 19:42:35 +0100 Subject: rt2x00: Optimize TX descriptor handling HT and no-HT rt2x00 devices use a partly different TX descriptor. Optimize the tx desciptor memory layout by putting the PLCP and HT substructs into a union and introduce a new driver flag to decide which TX desciptor format is used by the device. This saves us the expensive PLCP calculation fOr HT devices and the HT descriptor setup on no-HT devices. Acked-by: Gertjan van Wingerde Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 10 ++++++---- drivers/net/wireless/rt2x00/rt2500pci.c | 10 ++++++---- drivers/net/wireless/rt2x00/rt2500usb.c | 10 ++++++---- drivers/net/wireless/rt2x00/rt2800lib.c | 11 ++++++----- drivers/net/wireless/rt2x00/rt2800pci.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00ht.c | 20 ++++++++++---------- drivers/net/wireless/rt2x00/rt2x00queue.c | 23 +++++++++++++---------- drivers/net/wireless/rt2x00/rt2x00queue.h | 27 +++++++++++++++++---------- drivers/net/wireless/rt2x00/rt61pci.c | 10 ++++++---- drivers/net/wireless/rt2x00/rt73usb.c | 10 ++++++---- 12 files changed, 79 insertions(+), 55 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index d38acf4b65e1..60d75962b805 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1131,19 +1131,21 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); - rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5); rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1); - rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->service); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->u.plcp.service); rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6); rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1); rt2x00_desc_write(txd, 3, word); rt2x00_desc_read(txd, 4, &word); - rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, txdesc->length_low); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, + txdesc->u.plcp.length_low); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1); - rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, txdesc->length_high); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, + txdesc->u.plcp.length_high); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7); rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1); rt2x00_desc_write(txd, 4, word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index b00e4d483c58..53ff64e19648 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1287,10 +1287,12 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); - rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->signal); - rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->service); - rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, txdesc->length_low); - rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, txdesc->length_high); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, txdesc->u.plcp.signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, txdesc->u.plcp.service); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, + txdesc->u.plcp.length_low); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, + txdesc->u.plcp.length_high); rt2x00_desc_write(txd, 3, word); rt2x00_desc_read(txd, 10, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b71df29436e7..ed5bc9c6224f 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1114,10 +1114,12 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal); - rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, + txdesc->u.plcp.length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, + txdesc->u.plcp.length_high); rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ad90c86810d7..553d4d01a439 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -472,14 +472,15 @@ void rt2800_write_tx_data(struct queue_entry *entry, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W0_AMPDU, test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density); - rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->txop); - rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs); + rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, + txdesc->u.ht.mpdu_density); + rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->u.ht.txop); + rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->u.ht.mcs); rt2x00_set_field32(&word, TXWI_W0_BW, test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W0_SHORT_GI, test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc); + rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->u.ht.stbc); rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode); rt2x00_desc_write(txwi, 0, word); @@ -488,7 +489,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, test_bit(ENTRY_TXD_ACK, &txdesc->flags)); rt2x00_set_field32(&word, TXWI_W1_NSEQ, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); - rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size); + rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size); rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? txdesc->key_idx : 0xff); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 046a7b7d1241..49ea189c9821 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -979,6 +979,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5d91561e0de7..f1a92144996f 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -565,6 +565,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9067c917c659..81a0f8bed6ae 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -663,6 +663,7 @@ enum rt2x00_flags { DRIVER_REQUIRE_TXSTATUS_FIFO, DRIVER_REQUIRE_TASKLET_CONTEXT, DRIVER_REQUIRE_SW_SEQNO, + DRIVER_REQUIRE_HT_TX_DESC, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c index 03d9579da681..78a0e7386a78 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ht.c +++ b/drivers/net/wireless/rt2x00/rt2x00ht.c @@ -38,12 +38,12 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data; if (tx_info->control.sta) - txdesc->mpdu_density = + txdesc->u.ht.mpdu_density = tx_info->control.sta->ht_cap.ampdu_density; - txdesc->ba_size = 7; /* FIXME: What value is needed? */ + txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ - txdesc->stbc = + txdesc->u.ht.stbc = (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT; /* @@ -51,22 +51,22 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, * mcs rate to be used */ if (txrate->flags & IEEE80211_TX_RC_MCS) { - txdesc->mcs = txrate->idx; + txdesc->u.ht.mcs = txrate->idx; /* * MIMO PS should be set to 1 for STA's using dynamic SM PS * when using more then one tx stream (>MCS7). */ - if (tx_info->control.sta && txdesc->mcs > 7 && + if (tx_info->control.sta && txdesc->u.ht.mcs > 7 && ((tx_info->control.sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> IEEE80211_HT_CAP_SM_PS_SHIFT) == WLAN_HT_CAP_SM_PS_DYNAMIC) __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags); } else { - txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs); + txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs); if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txdesc->mcs |= 0x08; + txdesc->u.ht.mcs |= 0x08; } /* @@ -105,11 +105,11 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry, * for frames not transmitted with TXOP_HTTXOP */ if (ieee80211_is_mgmt(hdr->frame_control)) - txdesc->txop = TXOP_BACKOFF; + txdesc->u.ht.txop = TXOP_BACKOFF; else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)) - txdesc->txop = TXOP_SIFS; + txdesc->u.ht.txop = TXOP_SIFS; else - txdesc->txop = TXOP_HTTXOP; + txdesc->u.ht.txop = TXOP_HTTXOP; } u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index eebb564ee4da..7816c1c39d6e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -270,12 +270,12 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, * PLCP setup * Length calculation depends on OFDM/CCK rate. */ - txdesc->signal = hwrate->plcp; - txdesc->service = 0x04; + txdesc->u.plcp.signal = hwrate->plcp; + txdesc->u.plcp.service = 0x04; if (hwrate->flags & DEV_RATE_OFDM) { - txdesc->length_high = (data_length >> 6) & 0x3f; - txdesc->length_low = data_length & 0x3f; + txdesc->u.plcp.length_high = (data_length >> 6) & 0x3f; + txdesc->u.plcp.length_low = data_length & 0x3f; } else { /* * Convert length to microseconds. @@ -290,18 +290,18 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, * Check if we need to set the Length Extension */ if (hwrate->bitrate == 110 && residual <= 30) - txdesc->service |= 0x80; + txdesc->u.plcp.service |= 0x80; } - txdesc->length_high = (duration >> 8) & 0xff; - txdesc->length_low = duration & 0xff; + txdesc->u.plcp.length_high = (duration >> 8) & 0xff; + txdesc->u.plcp.length_low = duration & 0xff; /* * When preamble is enabled we should set the * preamble bit for the signal. */ if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - txdesc->signal |= 0x08; + txdesc->u.plcp.signal |= 0x08; } } @@ -397,9 +397,12 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, * Apply TX descriptor handling by components */ rt2x00crypto_create_tx_descriptor(entry, txdesc); - rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); rt2x00queue_create_tx_descriptor_seq(entry, txdesc); - rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); + + if (test_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags)) + rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate); + else + rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate); } static int rt2x00queue_write_tx_data(struct queue_entry *entry, diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index fab8e2687f29..330552046440 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -305,20 +305,27 @@ struct txentry_desc { u16 length; u16 header_length; - u16 length_high; - u16 length_low; - u16 signal; - u16 service; - - u16 mcs; - u16 stbc; - u16 ba_size; + union { + struct { + u16 length_high; + u16 length_low; + u16 signal; + u16 service; + } plcp; + + struct { + u16 mcs; + u16 stbc; + u16 ba_size; + u16 mpdu_density; + short txop; + } ht; + } u; + u16 rate_mode; - u16 mpdu_density; short retry_limit; short ifs; - short txop; enum cipher cipher; u16 key_idx; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 2ed845b1ea3c..c01b811a50d5 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1898,10 +1898,12 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal); - rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, + txdesc->u.plcp.length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, + txdesc->u.plcp.length_high); rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a799c262c1db..a4c9a3e20ec4 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1499,10 +1499,12 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->signal); - rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->service); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, txdesc->length_low); - rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); + rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, txdesc->u.plcp.signal); + rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, txdesc->u.plcp.service); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, + txdesc->u.plcp.length_low); + rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, + txdesc->u.plcp.length_high); rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { -- cgit v1.2.3 From 2517794b702cf62bb049e57c0825fc4573f8a6a3 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 3 Mar 2011 19:43:25 +0100 Subject: rt2x00: Move TX descriptor field "ifs" into plcp substruct "ifs" is only used by no-HT devices. Move it into the plcp substruct and fill in the value only for no-HT devices. Signed-off-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500pci.c | 2 +- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 20 +++++++++++--------- drivers/net/wireless/rt2x00/rt2x00queue.h | 2 +- drivers/net/wireless/rt2x00/rt61pci.c | 2 +- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 7 files changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 60d75962b805..9016c00f2946 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1166,7 +1166,7 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_RTS, test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_desc_write(txd, 0, word); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 53ff64e19648..0fbc18cb7304 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1317,7 +1317,7 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W0_OFDM, (txdesc->rate_mode == RATE_MODE_OFDM)); rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1); - rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index ed5bc9c6224f..979fe6596a2d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1100,7 +1100,7 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, (txdesc->rate_mode == RATE_MODE_OFDM)); rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); - rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length); rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher); rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 7816c1c39d6e..6300cf309872 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -262,6 +262,16 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry, unsigned int duration; unsigned int residual; + /* + * Determine with what IFS priority this frame should be send. + * Set ifs to IFS_SIFS when the this is not the first fragment, + * or this fragment came after RTS/CTS. + */ + if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)) + txdesc->u.plcp.ifs = IFS_BACKOFF; + else + txdesc->u.plcp.ifs = IFS_SIFS; + /* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */ data_length = entry->skb->len + 4; data_length += rt2x00crypto_tx_overhead(rt2x00dev, entry->skb); @@ -373,17 +383,9 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, ieee80211_is_probe_resp(hdr->frame_control)) __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags); - /* - * Determine with what IFS priority this frame should be send. - * Set ifs to IFS_SIFS when the this is not the first fragment, - * or this fragment came after RTS/CTS. - */ if ((tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) && - !test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) { + !test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags)) __set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags); - txdesc->ifs = IFS_BACKOFF; - } else - txdesc->ifs = IFS_SIFS; /* * Determine rate modulation. diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 3fa2406af700..7f8528da03e4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -311,6 +311,7 @@ struct txentry_desc { u16 length_low; u16 signal; u16 service; + enum ifs ifs; } plcp; struct { @@ -325,7 +326,6 @@ struct txentry_desc { u16 rate_mode; short retry_limit; - enum ifs ifs; enum cipher cipher; u16 key_idx; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index c01b811a50d5..a014c64f4275 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1948,7 +1948,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, (txdesc->rate_mode == RATE_MODE_OFDM)); - rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a4c9a3e20ec4..02f1148c577e 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1474,7 +1474,7 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, (txdesc->rate_mode == RATE_MODE_OFDM)); - rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); + rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->u.plcp.ifs); rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, -- cgit v1.2.3 From 0aa13b2e06fbb8327c7acb4ccf684b2b65c302ce Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 3 Mar 2011 19:45:16 +0100 Subject: rt2x00: Revise irqmask locking for PCI devices The PCI device irqmask is locked by a spin_lock. Currently spin_lock_irqsave is used everywhere. To reduce the locking overhead replace spin_lock_irqsave in hard irq context with spin_lock and in soft irq context with spin_lock_irq. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 15 ++++++--------- drivers/net/wireless/rt2x00/rt2500pci.c | 15 ++++++--------- drivers/net/wireless/rt2x00/rt2800pci.c | 10 ++++------ drivers/net/wireless/rt2x00/rt61pci.c | 15 ++++++--------- 4 files changed, 22 insertions(+), 33 deletions(-) (limited to 'drivers/net/wireless/rt2x00/rt61pci.c') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 9016c00f2946..80f4988adf80 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1317,27 +1317,25 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { - unsigned long flags; u32 reg; /* * Enable a single interrupt. The interrupt mask register * access needs locking. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, CSR8, ®); rt2x00_set_field32(®, irq_field, 0); rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt2400pci_txstatus_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; u32 reg; - unsigned long flags; /* * Handle all tx queues. @@ -1349,7 +1347,7 @@ static void rt2400pci_txstatus_tasklet(unsigned long data) /* * Enable all TXDONE interrupts again. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, CSR8, ®); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); @@ -1357,7 +1355,7 @@ static void rt2400pci_txstatus_tasklet(unsigned long data) rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt2400pci_tbtt_tasklet(unsigned long data) @@ -1378,7 +1376,6 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; u32 reg, mask; - unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -1420,13 +1417,13 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) * Disable all interrupts for which a tasklet was scheduled right now, * the tasklet will reenable the appropriate interrupts. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, CSR8, ®); reg |= mask; rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock(&rt2x00dev->irqmask_lock); diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 0fbc18cb7304..635f80466540 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1449,27 +1449,25 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { - unsigned long flags; u32 reg; /* * Enable a single interrupt. The interrupt mask register * access needs locking. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, CSR8, ®); rt2x00_set_field32(®, irq_field, 0); rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt2500pci_txstatus_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; u32 reg; - unsigned long flags; /* * Handle all tx queues. @@ -1481,7 +1479,7 @@ static void rt2500pci_txstatus_tasklet(unsigned long data) /* * Enable all TXDONE interrupts again. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, CSR8, ®); rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); @@ -1489,7 +1487,7 @@ static void rt2500pci_txstatus_tasklet(unsigned long data) rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt2500pci_tbtt_tasklet(unsigned long data) @@ -1510,7 +1508,6 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; u32 reg, mask; - unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -1552,13 +1549,13 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) * Disable all interrupts for which a tasklet was scheduled right now, * the tasklet will reenable the appropriate interrupts. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, CSR8, ®); reg |= mask; rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock(&rt2x00dev->irqmask_lock); return IRQ_HANDLED; } diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 49ea189c9821..b58484a80b7c 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -765,18 +765,17 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { - unsigned long flags; u32 reg; /* * Enable a single interrupt. The interrupt mask register * access needs locking. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, irq_field, 1); rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt2800pci_txstatus_tasklet(unsigned long data) @@ -862,7 +861,6 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) { struct rt2x00_dev *rt2x00dev = dev_instance; u32 reg, mask; - unsigned long flags; /* Read status and ACK all interrupts */ rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); @@ -905,11 +903,11 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) * Disable all interrupts for which a tasklet was scheduled right now, * the tasklet will reenable the appropriate interrupts. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock(&rt2x00dev->irqmask_lock); rt2800_register_read(rt2x00dev, INT_MASK_CSR, ®); reg &= mask; rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock(&rt2x00dev->irqmask_lock); return IRQ_HANDLED; } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a014c64f4275..77e8113b91e1 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2263,39 +2263,37 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { - unsigned long flags; u32 reg; /* * Enable a single interrupt. The interrupt mask register * access needs locking. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); rt2x00_set_field32(®, irq_field, 0); rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev, struct rt2x00_field32 irq_field) { - unsigned long flags; u32 reg; /* * Enable a single MCU interrupt. The interrupt mask register * access needs locking. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock_irq(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, ®); rt2x00_set_field32(®, irq_field, 0); rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock_irq(&rt2x00dev->irqmask_lock); } static void rt61pci_txstatus_tasklet(unsigned long data) @@ -2333,7 +2331,6 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) struct rt2x00_dev *rt2x00dev = dev_instance; u32 reg_mcu, mask_mcu; u32 reg, mask; - unsigned long flags; /* * Get the interrupt sources & saved to local variable. @@ -2378,7 +2375,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) * Disable all interrupts for which a tasklet was scheduled right now, * the tasklet will reenable the appropriate interrupts. */ - spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); + spin_lock(&rt2x00dev->irqmask_lock); rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); reg |= mask; @@ -2388,7 +2385,7 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) reg |= mask_mcu; rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); - spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); + spin_unlock(&rt2x00dev->irqmask_lock); return IRQ_HANDLED; } -- cgit v1.2.3