aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt61pci.c
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2011-01-30 07:19:08 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-31 15:06:23 -0500
commit5846a550b5838ea7fe8e280caff159a5ddb5c7e1 (patch)
tree5c4e2210b56c4252c0e4d1b4882efe17aec8ef18 /drivers/net/wireless/rt2x00/rt61pci.c
parenta9d61e9e779579c66c0d4c8af203d51dbca1473c (diff)
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 <helmut.schaa@googlemail.com> Acked-by: Gertjan van Wingerde <gwingerde@gmail.com> Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt61pci.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c175
1 files changed, 130 insertions, 45 deletions
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)
1142 rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); 1142 rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
1143 break; 1143 break;
1144 case QID_BEACON: 1144 case QID_BEACON:
1145 /*
1146 * Allow the tbtt tasklet to be scheduled.
1147 */
1148 tasklet_enable(&rt2x00dev->tbtt_tasklet);
1149
1145 rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg); 1150 rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
1146 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1); 1151 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
1147 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1); 1152 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
@@ -1221,6 +1226,11 @@ static void rt61pci_stop_queue(struct data_queue *queue)
1221 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0); 1226 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 0);
1222 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0); 1227 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
1223 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); 1228 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
1229
1230 /*
1231 * Wait for possibly running tbtt tasklets.
1232 */
1233 tasklet_disable(&rt2x00dev->tbtt_tasklet);
1224 break; 1234 break;
1225 default: 1235 default:
1226 break; 1236 break;
@@ -1710,6 +1720,7 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
1710 int mask = (state == STATE_RADIO_IRQ_OFF) || 1720 int mask = (state == STATE_RADIO_IRQ_OFF) ||
1711 (state == STATE_RADIO_IRQ_OFF_ISR); 1721 (state == STATE_RADIO_IRQ_OFF_ISR);
1712 u32 reg; 1722 u32 reg;
1723 unsigned long flags;
1713 1724
1714 /* 1725 /*
1715 * When interrupts are being enabled, the interrupt registers 1726 * When interrupts are being enabled, the interrupt registers
@@ -1721,12 +1732,21 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
1721 1732
1722 rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg); 1733 rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
1723 rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); 1734 rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
1735
1736 /*
1737 * Enable tasklets.
1738 */
1739 tasklet_enable(&rt2x00dev->txstatus_tasklet);
1740 tasklet_enable(&rt2x00dev->rxdone_tasklet);
1741 tasklet_enable(&rt2x00dev->autowake_tasklet);
1724 } 1742 }
1725 1743
1726 /* 1744 /*
1727 * Only toggle the interrupts bits we are going to use. 1745 * Only toggle the interrupts bits we are going to use.
1728 * Non-checked interrupt bits are disabled by default. 1746 * Non-checked interrupt bits are disabled by default.
1729 */ 1747 */
1748 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1749
1730 rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg); 1750 rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
1731 rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask); 1751 rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
1732 rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask); 1752 rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
@@ -1746,6 +1766,17 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
1746 rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask); 1766 rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
1747 rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_TWAKEUP, mask); 1767 rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_TWAKEUP, mask);
1748 rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg); 1768 rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
1769
1770 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1771
1772 if (state == STATE_RADIO_IRQ_OFF) {
1773 /*
1774 * Ensure that all tasklets are finished.
1775 */
1776 tasklet_disable(&rt2x00dev->txstatus_tasklet);
1777 tasklet_disable(&rt2x00dev->rxdone_tasklet);
1778 tasklet_disable(&rt2x00dev->autowake_tasklet);
1779 }
1749} 1780}
1750 1781
1751static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev) 1782static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -2223,61 +2254,80 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
2223 rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); 2254 rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
2224} 2255}
2225 2256
2226static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance) 2257static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
2258 struct rt2x00_field32 irq_field)
2227{ 2259{
2228 struct rt2x00_dev *rt2x00dev = dev_instance; 2260 unsigned long flags;
2229 u32 reg = rt2x00dev->irqvalue[0]; 2261 u32 reg;
2230 u32 reg_mcu = rt2x00dev->irqvalue[1];
2231 2262
2232 /* 2263 /*
2233 * Handle interrupts, walk through all bits 2264 * Enable a single interrupt. The interrupt mask register
2234 * and run the tasks, the bits are checked in order of 2265 * access needs locking.
2235 * priority.
2236 */ 2266 */
2267 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
2237 2268
2238 /* 2269 rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
2239 * 1 - Rx ring done interrupt. 2270 rt2x00_set_field32(&reg, irq_field, 0);
2240 */ 2271 rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
2241 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
2242 rt2x00pci_rxdone(rt2x00dev);
2243 2272
2244 /* 2273 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
2245 * 2 - Tx ring done interrupt. 2274}
2246 */
2247 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
2248 rt61pci_txdone(rt2x00dev);
2249 2275
2250 /* 2276static void rt61pci_enable_mcu_interrupt(struct rt2x00_dev *rt2x00dev,
2251 * 3 - Handle MCU command done. 2277 struct rt2x00_field32 irq_field)
2252 */ 2278{
2253 if (reg_mcu) 2279 unsigned long flags;
2254 rt2x00pci_register_write(rt2x00dev, 2280 u32 reg;
2255 M2H_CMD_DONE_CSR, 0xffffffff);
2256 2281
2257 /* 2282 /*
2258 * 4 - MCU Autowakeup interrupt. 2283 * Enable a single MCU interrupt. The interrupt mask register
2284 * access needs locking.
2259 */ 2285 */
2260 if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP)) 2286 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
2261 rt61pci_wakeup(rt2x00dev);
2262 2287
2263 /* 2288 rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
2264 * 5 - Beacon done interrupt. 2289 rt2x00_set_field32(&reg, irq_field, 0);
2265 */ 2290 rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
2266 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
2267 rt2x00lib_beacondone(rt2x00dev);
2268 2291
2269 /* Enable interrupts again. */ 2292 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
2270 rt2x00dev->ops->lib->set_device_state(rt2x00dev,
2271 STATE_RADIO_IRQ_ON_ISR);
2272 return IRQ_HANDLED;
2273} 2293}
2274 2294
2295static void rt61pci_txstatus_tasklet(unsigned long data)
2296{
2297 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
2298 rt61pci_txdone(rt2x00dev);
2299 rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE);
2300}
2301
2302static void rt61pci_tbtt_tasklet(unsigned long data)
2303{
2304 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
2305 rt2x00lib_beacondone(rt2x00dev);
2306 rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE);
2307}
2308
2309static void rt61pci_rxdone_tasklet(unsigned long data)
2310{
2311 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
2312 rt2x00pci_rxdone(rt2x00dev);
2313 rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
2314}
2315
2316static void rt61pci_autowake_tasklet(unsigned long data)
2317{
2318 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
2319 rt61pci_wakeup(rt2x00dev);
2320 rt2x00pci_register_write(rt2x00dev,
2321 M2H_CMD_DONE_CSR, 0xffffffff);
2322 rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP);
2323}
2275 2324
2276static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) 2325static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
2277{ 2326{
2278 struct rt2x00_dev *rt2x00dev = dev_instance; 2327 struct rt2x00_dev *rt2x00dev = dev_instance;
2279 u32 reg_mcu; 2328 u32 reg_mcu, mask_mcu;
2280 u32 reg; 2329 u32 reg, mask;
2330 unsigned long flags;
2281 2331
2282 /* 2332 /*
2283 * Get the interrupt sources & saved to local variable. 2333 * Get the interrupt sources & saved to local variable.
@@ -2295,14 +2345,46 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
2295 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 2345 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
2296 return IRQ_HANDLED; 2346 return IRQ_HANDLED;
2297 2347
2298 /* Store irqvalues for use in the interrupt thread. */ 2348 /*
2299 rt2x00dev->irqvalue[0] = reg; 2349 * Schedule tasklets for interrupt handling.
2300 rt2x00dev->irqvalue[1] = reg_mcu; 2350 */
2351 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
2352 tasklet_schedule(&rt2x00dev->rxdone_tasklet);
2353
2354 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
2355 tasklet_schedule(&rt2x00dev->txstatus_tasklet);
2356
2357 if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE))
2358 tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
2359
2360 if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
2361 tasklet_schedule(&rt2x00dev->autowake_tasklet);
2362
2363 /*
2364 * Since INT_MASK_CSR and INT_SOURCE_CSR use the same bits
2365 * for interrupts and interrupt masks we can just use the value of
2366 * INT_SOURCE_CSR to create the interrupt mask.
2367 */
2368 mask = reg;
2369 mask_mcu = reg_mcu;
2370
2371 /*
2372 * Disable all interrupts for which a tasklet was scheduled right now,
2373 * the tasklet will reenable the appropriate interrupts.
2374 */
2375 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
2376
2377 rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
2378 reg |= mask;
2379 rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
2301 2380
2302 /* Disable interrupts, will be enabled again in the interrupt thread. */ 2381 rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
2303 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 2382 reg |= mask_mcu;
2304 STATE_RADIO_IRQ_OFF_ISR); 2383 rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
2305 return IRQ_WAKE_THREAD; 2384
2385 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
2386
2387 return IRQ_HANDLED;
2306} 2388}
2307 2389
2308/* 2390/*
@@ -2896,7 +2978,10 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
2896 2978
2897static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { 2979static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
2898 .irq_handler = rt61pci_interrupt, 2980 .irq_handler = rt61pci_interrupt,
2899 .irq_handler_thread = rt61pci_interrupt_thread, 2981 .txstatus_tasklet = rt61pci_txstatus_tasklet,
2982 .tbtt_tasklet = rt61pci_tbtt_tasklet,
2983 .rxdone_tasklet = rt61pci_rxdone_tasklet,
2984 .autowake_tasklet = rt61pci_autowake_tasklet,
2900 .probe_hw = rt61pci_probe_hw, 2985 .probe_hw = rt61pci_probe_hw,
2901 .get_firmware_name = rt61pci_get_firmware_name, 2986 .get_firmware_name = rt61pci_get_firmware_name,
2902 .check_firmware = rt61pci_check_firmware, 2987 .check_firmware = rt61pci_check_firmware,