aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00/rt2400pci.c
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2011-01-30 07:20:05 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-31 15:06:23 -0500
commitbcf3cfd047d599cd0e6758c422bd7a4835c00d4a (patch)
tree4d65eb070e5b5e70d6494816c5b147017936b69f /drivers/net/wireless/rt2x00/rt2400pci.c
parent16222a0d06f5032d7e8bc7c65e8bf299e21f413a (diff)
rt2x00: Convert rt2400pci interrupt handling 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/rt2400pci.c')
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c154
1 files changed, 115 insertions, 39 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index cb28e1b2f1e2..b324917106e6 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -645,6 +645,11 @@ static void rt2400pci_start_queue(struct data_queue *queue)
645 rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); 645 rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
646 break; 646 break;
647 case QID_BEACON: 647 case QID_BEACON:
648 /*
649 * Allow the tbtt tasklet to be scheduled.
650 */
651 tasklet_enable(&rt2x00dev->tbtt_tasklet);
652
648 rt2x00pci_register_read(rt2x00dev, CSR14, &reg); 653 rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
649 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1); 654 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
650 rt2x00_set_field32(&reg, CSR14_TBCN, 1); 655 rt2x00_set_field32(&reg, CSR14_TBCN, 1);
@@ -706,6 +711,11 @@ static void rt2400pci_stop_queue(struct data_queue *queue)
706 rt2x00_set_field32(&reg, CSR14_TBCN, 0); 711 rt2x00_set_field32(&reg, CSR14_TBCN, 0);
707 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0); 712 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
708 rt2x00pci_register_write(rt2x00dev, CSR14, reg); 713 rt2x00pci_register_write(rt2x00dev, CSR14, reg);
714
715 /*
716 * Wait for possibly running tbtt tasklets.
717 */
718 tasklet_disable(&rt2x00dev->tbtt_tasklet);
709 break; 719 break;
710 default: 720 default:
711 break; 721 break;
@@ -964,6 +974,7 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
964 int mask = (state == STATE_RADIO_IRQ_OFF) || 974 int mask = (state == STATE_RADIO_IRQ_OFF) ||
965 (state == STATE_RADIO_IRQ_OFF_ISR); 975 (state == STATE_RADIO_IRQ_OFF_ISR);
966 u32 reg; 976 u32 reg;
977 unsigned long flags;
967 978
968 /* 979 /*
969 * When interrupts are being enabled, the interrupt registers 980 * When interrupts are being enabled, the interrupt registers
@@ -972,12 +983,20 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
972 if (state == STATE_RADIO_IRQ_ON) { 983 if (state == STATE_RADIO_IRQ_ON) {
973 rt2x00pci_register_read(rt2x00dev, CSR7, &reg); 984 rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
974 rt2x00pci_register_write(rt2x00dev, CSR7, reg); 985 rt2x00pci_register_write(rt2x00dev, CSR7, reg);
986
987 /*
988 * Enable tasklets.
989 */
990 tasklet_enable(&rt2x00dev->txstatus_tasklet);
991 tasklet_enable(&rt2x00dev->rxdone_tasklet);
975 } 992 }
976 993
977 /* 994 /*
978 * Only toggle the interrupts bits we are going to use. 995 * Only toggle the interrupts bits we are going to use.
979 * Non-checked interrupt bits are disabled by default. 996 * Non-checked interrupt bits are disabled by default.
980 */ 997 */
998 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
999
981 rt2x00pci_register_read(rt2x00dev, CSR8, &reg); 1000 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
982 rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask); 1001 rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
983 rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask); 1002 rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
@@ -985,6 +1004,17 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
985 rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask); 1004 rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
986 rt2x00_set_field32(&reg, CSR8_RXDONE, mask); 1005 rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
987 rt2x00pci_register_write(rt2x00dev, CSR8, reg); 1006 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1007
1008 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1009
1010 if (state == STATE_RADIO_IRQ_OFF) {
1011 /*
1012 * Ensure that all tasklets are finished before
1013 * disabling the interrupts.
1014 */
1015 tasklet_disable(&rt2x00dev->txstatus_tasklet);
1016 tasklet_disable(&rt2x00dev->rxdone_tasklet);
1017 }
988} 1018}
989 1019
990static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) 1020static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -1285,57 +1315,71 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
1285 } 1315 }
1286} 1316}
1287 1317
1288static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance) 1318static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
1319 struct rt2x00_field32 irq_field)
1289{ 1320{
1290 struct rt2x00_dev *rt2x00dev = dev_instance; 1321 unsigned long flags;
1291 u32 reg = rt2x00dev->irqvalue[0]; 1322 u32 reg;
1292 1323
1293 /* 1324 /*
1294 * Handle interrupts, walk through all bits 1325 * Enable a single interrupt. The interrupt mask register
1295 * and run the tasks, the bits are checked in order of 1326 * access needs locking.
1296 * priority.
1297 */ 1327 */
1328 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1298 1329
1299 /* 1330 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1300 * 1 - Beacon timer expired interrupt. 1331 rt2x00_set_field32(&reg, irq_field, 0);
1301 */ 1332 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1302 if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
1303 rt2x00lib_beacondone(rt2x00dev);
1304 1333
1305 /* 1334 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1306 * 2 - Rx ring done interrupt. 1335}
1307 */
1308 if (rt2x00_get_field32(reg, CSR7_RXDONE))
1309 rt2x00pci_rxdone(rt2x00dev);
1310 1336
1311 /* 1337static void rt2400pci_txstatus_tasklet(unsigned long data)
1312 * 3 - Atim ring transmit done interrupt. 1338{
1313 */ 1339 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
1314 if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) 1340 u32 reg;
1315 rt2400pci_txdone(rt2x00dev, QID_ATIM); 1341 unsigned long flags;
1316 1342
1317 /* 1343 /*
1318 * 4 - Priority ring transmit done interrupt. 1344 * Handle all tx queues.
1319 */ 1345 */
1320 if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) 1346 rt2400pci_txdone(rt2x00dev, QID_ATIM);
1321 rt2400pci_txdone(rt2x00dev, QID_AC_VO); 1347 rt2400pci_txdone(rt2x00dev, QID_AC_VO);
1348 rt2400pci_txdone(rt2x00dev, QID_AC_VI);
1322 1349
1323 /* 1350 /*
1324 * 5 - Tx ring transmit done interrupt. 1351 * Enable all TXDONE interrupts again.
1325 */ 1352 */
1326 if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) 1353 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1327 rt2400pci_txdone(rt2x00dev, QID_AC_VI);
1328 1354
1329 /* Enable interrupts again. */ 1355 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1330 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 1356 rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
1331 STATE_RADIO_IRQ_ON_ISR); 1357 rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
1332 return IRQ_HANDLED; 1358 rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
1359 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1360
1361 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1362}
1363
1364static void rt2400pci_tbtt_tasklet(unsigned long data)
1365{
1366 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
1367 rt2x00lib_beacondone(rt2x00dev);
1368 rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
1369}
1370
1371static void rt2400pci_rxdone_tasklet(unsigned long data)
1372{
1373 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
1374 rt2x00pci_rxdone(rt2x00dev);
1375 rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
1333} 1376}
1334 1377
1335static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) 1378static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
1336{ 1379{
1337 struct rt2x00_dev *rt2x00dev = dev_instance; 1380 struct rt2x00_dev *rt2x00dev = dev_instance;
1338 u32 reg; 1381 u32 reg, mask;
1382 unsigned long flags;
1339 1383
1340 /* 1384 /*
1341 * Get the interrupt sources & saved to local variable. 1385 * Get the interrupt sources & saved to local variable.
@@ -1350,14 +1394,44 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
1350 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 1394 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
1351 return IRQ_HANDLED; 1395 return IRQ_HANDLED;
1352 1396
1353 /* Store irqvalues for use in the interrupt thread. */ 1397 mask = reg;
1354 rt2x00dev->irqvalue[0] = reg; 1398
1399 /*
1400 * Schedule tasklets for interrupt handling.
1401 */
1402 if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
1403 tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
1404
1405 if (rt2x00_get_field32(reg, CSR7_RXDONE))
1406 tasklet_schedule(&rt2x00dev->rxdone_tasklet);
1407
1408 if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) ||
1409 rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) ||
1410 rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) {
1411 tasklet_schedule(&rt2x00dev->txstatus_tasklet);
1412 /*
1413 * Mask out all txdone interrupts.
1414 */
1415 rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1);
1416 rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1);
1417 rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1);
1418 }
1355 1419
1356 /* Disable interrupts, will be enabled again in the interrupt thread. */ 1420 /*
1357 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 1421 * Disable all interrupts for which a tasklet was scheduled right now,
1358 STATE_RADIO_IRQ_OFF_ISR); 1422 * the tasklet will reenable the appropriate interrupts.
1423 */
1424 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1359 1425
1360 return IRQ_WAKE_THREAD; 1426 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1427 reg |= mask;
1428 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1429
1430 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1431
1432
1433
1434 return IRQ_HANDLED;
1361} 1435}
1362 1436
1363/* 1437/*
@@ -1651,7 +1725,9 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
1651 1725
1652static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { 1726static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
1653 .irq_handler = rt2400pci_interrupt, 1727 .irq_handler = rt2400pci_interrupt,
1654 .irq_handler_thread = rt2400pci_interrupt_thread, 1728 .txstatus_tasklet = rt2400pci_txstatus_tasklet,
1729 .tbtt_tasklet = rt2400pci_tbtt_tasklet,
1730 .rxdone_tasklet = rt2400pci_rxdone_tasklet,
1655 .probe_hw = rt2400pci_probe_hw, 1731 .probe_hw = rt2400pci_probe_hw,
1656 .initialize = rt2x00pci_initialize, 1732 .initialize = rt2x00pci_initialize,
1657 .uninitialize = rt2x00pci_uninitialize, 1733 .uninitialize = rt2x00pci_uninitialize,