aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2011-01-30 07:19:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-31 15:06:23 -0500
commit16222a0d06f5032d7e8bc7c65e8bf299e21f413a (patch)
treec3d7592fe6ddc199d4885e18bd60e0db5a1a3fc6 /drivers/net/wireless
parent5846a550b5838ea7fe8e280caff159a5ddb5c7e1 (diff)
rt2x00: Convert rt2500pci 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')
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c150
1 files changed, 111 insertions, 39 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 5225ae1899fe..7daa483c3742 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -735,6 +735,11 @@ static void rt2500pci_start_queue(struct data_queue *queue)
735 rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); 735 rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
736 break; 736 break;
737 case QID_BEACON: 737 case QID_BEACON:
738 /*
739 * Allow the tbtt tasklet to be scheduled.
740 */
741 tasklet_enable(&rt2x00dev->tbtt_tasklet);
742
738 rt2x00pci_register_read(rt2x00dev, CSR14, &reg); 743 rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
739 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1); 744 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
740 rt2x00_set_field32(&reg, CSR14_TBCN, 1); 745 rt2x00_set_field32(&reg, CSR14_TBCN, 1);
@@ -796,6 +801,11 @@ static void rt2500pci_stop_queue(struct data_queue *queue)
796 rt2x00_set_field32(&reg, CSR14_TBCN, 0); 801 rt2x00_set_field32(&reg, CSR14_TBCN, 0);
797 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0); 802 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
798 rt2x00pci_register_write(rt2x00dev, CSR14, reg); 803 rt2x00pci_register_write(rt2x00dev, CSR14, reg);
804
805 /*
806 * Wait for possibly running tbtt tasklets.
807 */
808 tasklet_disable(&rt2x00dev->tbtt_tasklet);
799 break; 809 break;
800 default: 810 default:
801 break; 811 break;
@@ -1119,6 +1129,7 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
1119 int mask = (state == STATE_RADIO_IRQ_OFF) || 1129 int mask = (state == STATE_RADIO_IRQ_OFF) ||
1120 (state == STATE_RADIO_IRQ_OFF_ISR); 1130 (state == STATE_RADIO_IRQ_OFF_ISR);
1121 u32 reg; 1131 u32 reg;
1132 unsigned long flags;
1122 1133
1123 /* 1134 /*
1124 * When interrupts are being enabled, the interrupt registers 1135 * When interrupts are being enabled, the interrupt registers
@@ -1127,12 +1138,20 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
1127 if (state == STATE_RADIO_IRQ_ON) { 1138 if (state == STATE_RADIO_IRQ_ON) {
1128 rt2x00pci_register_read(rt2x00dev, CSR7, &reg); 1139 rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
1129 rt2x00pci_register_write(rt2x00dev, CSR7, reg); 1140 rt2x00pci_register_write(rt2x00dev, CSR7, reg);
1141
1142 /*
1143 * Enable tasklets.
1144 */
1145 tasklet_enable(&rt2x00dev->txstatus_tasklet);
1146 tasklet_enable(&rt2x00dev->rxdone_tasklet);
1130 } 1147 }
1131 1148
1132 /* 1149 /*
1133 * Only toggle the interrupts bits we are going to use. 1150 * Only toggle the interrupts bits we are going to use.
1134 * Non-checked interrupt bits are disabled by default. 1151 * Non-checked interrupt bits are disabled by default.
1135 */ 1152 */
1153 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1154
1136 rt2x00pci_register_read(rt2x00dev, CSR8, &reg); 1155 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1137 rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask); 1156 rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
1138 rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask); 1157 rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
@@ -1140,6 +1159,16 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
1140 rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask); 1159 rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
1141 rt2x00_set_field32(&reg, CSR8_RXDONE, mask); 1160 rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
1142 rt2x00pci_register_write(rt2x00dev, CSR8, reg); 1161 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1162
1163 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1164
1165 if (state == STATE_RADIO_IRQ_OFF) {
1166 /*
1167 * Ensure that all tasklets are finished.
1168 */
1169 tasklet_disable(&rt2x00dev->txstatus_tasklet);
1170 tasklet_disable(&rt2x00dev->rxdone_tasklet);
1171 }
1143} 1172}
1144 1173
1145static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) 1174static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
@@ -1418,58 +1447,71 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
1418 } 1447 }
1419} 1448}
1420 1449
1421static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance) 1450static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
1451 struct rt2x00_field32 irq_field)
1422{ 1452{
1423 struct rt2x00_dev *rt2x00dev = dev_instance; 1453 unsigned long flags;
1424 u32 reg = rt2x00dev->irqvalue[0]; 1454 u32 reg;
1425 1455
1426 /* 1456 /*
1427 * Handle interrupts, walk through all bits 1457 * Enable a single interrupt. The interrupt mask register
1428 * and run the tasks, the bits are checked in order of 1458 * access needs locking.
1429 * priority.
1430 */ 1459 */
1460 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1431 1461
1432 /* 1462 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1433 * 1 - Beacon timer expired interrupt. 1463 rt2x00_set_field32(&reg, irq_field, 0);
1434 */ 1464 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1435 if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
1436 rt2x00lib_beacondone(rt2x00dev);
1437 1465
1438 /* 1466 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1439 * 2 - Rx ring done interrupt. 1467}
1440 */
1441 if (rt2x00_get_field32(reg, CSR7_RXDONE))
1442 rt2x00pci_rxdone(rt2x00dev);
1443 1468
1444 /* 1469static void rt2500pci_txstatus_tasklet(unsigned long data)
1445 * 3 - Atim ring transmit done interrupt. 1470{
1446 */ 1471 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
1447 if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) 1472 u32 reg;
1448 rt2500pci_txdone(rt2x00dev, QID_ATIM); 1473 unsigned long flags;
1449 1474
1450 /* 1475 /*
1451 * 4 - Priority ring transmit done interrupt. 1476 * Handle all tx queues.
1452 */ 1477 */
1453 if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) 1478 rt2500pci_txdone(rt2x00dev, QID_ATIM);
1454 rt2500pci_txdone(rt2x00dev, QID_AC_VO); 1479 rt2500pci_txdone(rt2x00dev, QID_AC_VO);
1480 rt2500pci_txdone(rt2x00dev, QID_AC_VI);
1455 1481
1456 /* 1482 /*
1457 * 5 - Tx ring transmit done interrupt. 1483 * Enable all TXDONE interrupts again.
1458 */ 1484 */
1459 if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) 1485 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1460 rt2500pci_txdone(rt2x00dev, QID_AC_VI);
1461 1486
1462 /* Enable interrupts again. */ 1487 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1463 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 1488 rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, 0);
1464 STATE_RADIO_IRQ_ON_ISR); 1489 rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, 0);
1490 rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, 0);
1491 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1465 1492
1466 return IRQ_HANDLED; 1493 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1494}
1495
1496static void rt2500pci_tbtt_tasklet(unsigned long data)
1497{
1498 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
1499 rt2x00lib_beacondone(rt2x00dev);
1500 rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE);
1501}
1502
1503static void rt2500pci_rxdone_tasklet(unsigned long data)
1504{
1505 struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
1506 rt2x00pci_rxdone(rt2x00dev);
1507 rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
1467} 1508}
1468 1509
1469static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) 1510static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
1470{ 1511{
1471 struct rt2x00_dev *rt2x00dev = dev_instance; 1512 struct rt2x00_dev *rt2x00dev = dev_instance;
1472 u32 reg; 1513 u32 reg, mask;
1514 unsigned long flags;
1473 1515
1474 /* 1516 /*
1475 * Get the interrupt sources & saved to local variable. 1517 * Get the interrupt sources & saved to local variable.
@@ -1484,14 +1526,42 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
1484 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 1526 if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
1485 return IRQ_HANDLED; 1527 return IRQ_HANDLED;
1486 1528
1487 /* Store irqvalues for use in the interrupt thread. */ 1529 mask = reg;
1488 rt2x00dev->irqvalue[0] = reg; 1530
1531 /*
1532 * Schedule tasklets for interrupt handling.
1533 */
1534 if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
1535 tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet);
1536
1537 if (rt2x00_get_field32(reg, CSR7_RXDONE))
1538 tasklet_schedule(&rt2x00dev->rxdone_tasklet);
1539
1540 if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) ||
1541 rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) ||
1542 rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) {
1543 tasklet_schedule(&rt2x00dev->txstatus_tasklet);
1544 /*
1545 * Mask out all txdone interrupts.
1546 */
1547 rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1);
1548 rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1);
1549 rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1);
1550 }
1551
1552 /*
1553 * Disable all interrupts for which a tasklet was scheduled right now,
1554 * the tasklet will reenable the appropriate interrupts.
1555 */
1556 spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
1489 1557
1490 /* Disable interrupts, will be enabled again in the interrupt thread. */ 1558 rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
1491 rt2x00dev->ops->lib->set_device_state(rt2x00dev, 1559 reg |= mask;
1492 STATE_RADIO_IRQ_OFF_ISR); 1560 rt2x00pci_register_write(rt2x00dev, CSR8, reg);
1561
1562 spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
1493 1563
1494 return IRQ_WAKE_THREAD; 1564 return IRQ_HANDLED;
1495} 1565}
1496 1566
1497/* 1567/*
@@ -1948,7 +2018,9 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
1948 2018
1949static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { 2019static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
1950 .irq_handler = rt2500pci_interrupt, 2020 .irq_handler = rt2500pci_interrupt,
1951 .irq_handler_thread = rt2500pci_interrupt_thread, 2021 .txstatus_tasklet = rt2500pci_txstatus_tasklet,
2022 .tbtt_tasklet = rt2500pci_tbtt_tasklet,
2023 .rxdone_tasklet = rt2500pci_rxdone_tasklet,
1952 .probe_hw = rt2500pci_probe_hw, 2024 .probe_hw = rt2500pci_probe_hw,
1953 .initialize = rt2x00pci_initialize, 2025 .initialize = rt2x00pci_initialize,
1954 .uninitialize = rt2x00pci_uninitialize, 2026 .uninitialize = rt2x00pci_uninitialize,