diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2500pci.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500pci.c | 159 |
1 files changed, 112 insertions, 47 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index a9ff26a27724..3ef1fb4185c0 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -311,9 +311,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, | |||
311 | * Enable synchronisation. | 311 | * Enable synchronisation. |
312 | */ | 312 | */ |
313 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 313 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
314 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | ||
315 | rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); | 314 | rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); |
316 | rt2x00_set_field32(®, CSR14_TBCN, 1); | ||
317 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 315 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
318 | } | 316 | } |
319 | 317 | ||
@@ -737,6 +735,11 @@ static void rt2500pci_start_queue(struct data_queue *queue) | |||
737 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); | 735 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); |
738 | break; | 736 | break; |
739 | case QID_BEACON: | 737 | case QID_BEACON: |
738 | /* | ||
739 | * Allow the tbtt tasklet to be scheduled. | ||
740 | */ | ||
741 | tasklet_enable(&rt2x00dev->tbtt_tasklet); | ||
742 | |||
740 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 743 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
741 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | 744 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); |
742 | rt2x00_set_field32(®, CSR14_TBCN, 1); | 745 | rt2x00_set_field32(®, CSR14_TBCN, 1); |
@@ -798,6 +801,11 @@ static void rt2500pci_stop_queue(struct data_queue *queue) | |||
798 | rt2x00_set_field32(®, CSR14_TBCN, 0); | 801 | rt2x00_set_field32(®, CSR14_TBCN, 0); |
799 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 802 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); |
800 | 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); | ||
801 | break; | 809 | break; |
802 | default: | 810 | default: |
803 | break; | 811 | break; |
@@ -1118,9 +1126,9 @@ static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
1118 | static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | 1126 | static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, |
1119 | enum dev_state state) | 1127 | enum dev_state state) |
1120 | { | 1128 | { |
1121 | int mask = (state == STATE_RADIO_IRQ_OFF) || | 1129 | int mask = (state == STATE_RADIO_IRQ_OFF); |
1122 | (state == STATE_RADIO_IRQ_OFF_ISR); | ||
1123 | u32 reg; | 1130 | u32 reg; |
1131 | unsigned long flags; | ||
1124 | 1132 | ||
1125 | /* | 1133 | /* |
1126 | * When interrupts are being enabled, the interrupt registers | 1134 | * When interrupts are being enabled, the interrupt registers |
@@ -1129,12 +1137,20 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1129 | if (state == STATE_RADIO_IRQ_ON) { | 1137 | if (state == STATE_RADIO_IRQ_ON) { |
1130 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | 1138 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); |
1131 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | 1139 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); |
1140 | |||
1141 | /* | ||
1142 | * Enable tasklets. | ||
1143 | */ | ||
1144 | tasklet_enable(&rt2x00dev->txstatus_tasklet); | ||
1145 | tasklet_enable(&rt2x00dev->rxdone_tasklet); | ||
1132 | } | 1146 | } |
1133 | 1147 | ||
1134 | /* | 1148 | /* |
1135 | * Only toggle the interrupts bits we are going to use. | 1149 | * Only toggle the interrupts bits we are going to use. |
1136 | * Non-checked interrupt bits are disabled by default. | 1150 | * Non-checked interrupt bits are disabled by default. |
1137 | */ | 1151 | */ |
1152 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | ||
1153 | |||
1138 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | 1154 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
1139 | rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); | 1155 | rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); |
1140 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); | 1156 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); |
@@ -1142,6 +1158,16 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
1142 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); | 1158 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); |
1143 | rt2x00_set_field32(®, CSR8_RXDONE, mask); | 1159 | rt2x00_set_field32(®, CSR8_RXDONE, mask); |
1144 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | 1160 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); |
1161 | |||
1162 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); | ||
1163 | |||
1164 | if (state == STATE_RADIO_IRQ_OFF) { | ||
1165 | /* | ||
1166 | * Ensure that all tasklets are finished. | ||
1167 | */ | ||
1168 | tasklet_disable(&rt2x00dev->txstatus_tasklet); | ||
1169 | tasklet_disable(&rt2x00dev->rxdone_tasklet); | ||
1170 | } | ||
1145 | } | 1171 | } |
1146 | 1172 | ||
1147 | static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) | 1173 | static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev) |
@@ -1214,9 +1240,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
1214 | rt2500pci_disable_radio(rt2x00dev); | 1240 | rt2500pci_disable_radio(rt2x00dev); |
1215 | break; | 1241 | break; |
1216 | case STATE_RADIO_IRQ_ON: | 1242 | case STATE_RADIO_IRQ_ON: |
1217 | case STATE_RADIO_IRQ_ON_ISR: | ||
1218 | case STATE_RADIO_IRQ_OFF: | 1243 | case STATE_RADIO_IRQ_OFF: |
1219 | case STATE_RADIO_IRQ_OFF_ISR: | ||
1220 | rt2500pci_toggle_irq(rt2x00dev, state); | 1244 | rt2500pci_toggle_irq(rt2x00dev, state); |
1221 | break; | 1245 | break; |
1222 | case STATE_DEEP_SLEEP: | 1246 | case STATE_DEEP_SLEEP: |
@@ -1337,8 +1361,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry, | |||
1337 | /* | 1361 | /* |
1338 | * Enable beaconing again. | 1362 | * Enable beaconing again. |
1339 | */ | 1363 | */ |
1340 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | ||
1341 | rt2x00_set_field32(®, CSR14_TBCN, 1); | ||
1342 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); | 1364 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); |
1343 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 1365 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
1344 | } | 1366 | } |
@@ -1422,58 +1444,71 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1422 | } | 1444 | } |
1423 | } | 1445 | } |
1424 | 1446 | ||
1425 | static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance) | 1447 | static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, |
1448 | struct rt2x00_field32 irq_field) | ||
1426 | { | 1449 | { |
1427 | struct rt2x00_dev *rt2x00dev = dev_instance; | 1450 | unsigned long flags; |
1428 | u32 reg = rt2x00dev->irqvalue[0]; | 1451 | u32 reg; |
1429 | 1452 | ||
1430 | /* | 1453 | /* |
1431 | * Handle interrupts, walk through all bits | 1454 | * Enable a single interrupt. The interrupt mask register |
1432 | * and run the tasks, the bits are checked in order of | 1455 | * access needs locking. |
1433 | * priority. | ||
1434 | */ | 1456 | */ |
1457 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | ||
1435 | 1458 | ||
1436 | /* | 1459 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
1437 | * 1 - Beacon timer expired interrupt. | 1460 | rt2x00_set_field32(®, irq_field, 0); |
1438 | */ | 1461 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); |
1439 | if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) | ||
1440 | rt2x00lib_beacondone(rt2x00dev); | ||
1441 | 1462 | ||
1442 | /* | 1463 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); |
1443 | * 2 - Rx ring done interrupt. | 1464 | } |
1444 | */ | ||
1445 | if (rt2x00_get_field32(reg, CSR7_RXDONE)) | ||
1446 | rt2x00pci_rxdone(rt2x00dev); | ||
1447 | 1465 | ||
1448 | /* | 1466 | static void rt2500pci_txstatus_tasklet(unsigned long data) |
1449 | * 3 - Atim ring transmit done interrupt. | 1467 | { |
1450 | */ | 1468 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1451 | if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) | 1469 | u32 reg; |
1452 | rt2500pci_txdone(rt2x00dev, QID_ATIM); | 1470 | unsigned long flags; |
1453 | 1471 | ||
1454 | /* | 1472 | /* |
1455 | * 4 - Priority ring transmit done interrupt. | 1473 | * Handle all tx queues. |
1456 | */ | 1474 | */ |
1457 | if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) | 1475 | rt2500pci_txdone(rt2x00dev, QID_ATIM); |
1458 | rt2500pci_txdone(rt2x00dev, QID_AC_VO); | 1476 | rt2500pci_txdone(rt2x00dev, QID_AC_VO); |
1477 | rt2500pci_txdone(rt2x00dev, QID_AC_VI); | ||
1459 | 1478 | ||
1460 | /* | 1479 | /* |
1461 | * 5 - Tx ring transmit done interrupt. | 1480 | * Enable all TXDONE interrupts again. |
1462 | */ | 1481 | */ |
1463 | if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) | 1482 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); |
1464 | rt2500pci_txdone(rt2x00dev, QID_AC_VI); | 1483 | |
1484 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | ||
1485 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); | ||
1486 | rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); | ||
1487 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); | ||
1488 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | ||
1465 | 1489 | ||
1466 | /* Enable interrupts again. */ | 1490 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); |
1467 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | 1491 | } |
1468 | STATE_RADIO_IRQ_ON_ISR); | ||
1469 | 1492 | ||
1470 | return IRQ_HANDLED; | 1493 | static void rt2500pci_tbtt_tasklet(unsigned long data) |
1494 | { | ||
1495 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | ||
1496 | rt2x00lib_beacondone(rt2x00dev); | ||
1497 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); | ||
1498 | } | ||
1499 | |||
1500 | static void rt2500pci_rxdone_tasklet(unsigned long data) | ||
1501 | { | ||
1502 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | ||
1503 | rt2x00pci_rxdone(rt2x00dev); | ||
1504 | rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | ||
1471 | } | 1505 | } |
1472 | 1506 | ||
1473 | static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) | 1507 | static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) |
1474 | { | 1508 | { |
1475 | struct rt2x00_dev *rt2x00dev = dev_instance; | 1509 | struct rt2x00_dev *rt2x00dev = dev_instance; |
1476 | u32 reg; | 1510 | u32 reg, mask; |
1511 | unsigned long flags; | ||
1477 | 1512 | ||
1478 | /* | 1513 | /* |
1479 | * Get the interrupt sources & saved to local variable. | 1514 | * Get the interrupt sources & saved to local variable. |
@@ -1488,14 +1523,42 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) | |||
1488 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 1523 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
1489 | return IRQ_HANDLED; | 1524 | return IRQ_HANDLED; |
1490 | 1525 | ||
1491 | /* Store irqvalues for use in the interrupt thread. */ | 1526 | mask = reg; |
1492 | rt2x00dev->irqvalue[0] = reg; | ||
1493 | 1527 | ||
1494 | /* Disable interrupts, will be enabled again in the interrupt thread. */ | 1528 | /* |
1495 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | 1529 | * Schedule tasklets for interrupt handling. |
1496 | STATE_RADIO_IRQ_OFF_ISR); | 1530 | */ |
1531 | if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) | ||
1532 | tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); | ||
1497 | 1533 | ||
1498 | return IRQ_WAKE_THREAD; | 1534 | if (rt2x00_get_field32(reg, CSR7_RXDONE)) |
1535 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); | ||
1536 | |||
1537 | if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) || | ||
1538 | rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) || | ||
1539 | rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) { | ||
1540 | tasklet_schedule(&rt2x00dev->txstatus_tasklet); | ||
1541 | /* | ||
1542 | * Mask out all txdone interrupts. | ||
1543 | */ | ||
1544 | rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1); | ||
1545 | rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1); | ||
1546 | rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1); | ||
1547 | } | ||
1548 | |||
1549 | /* | ||
1550 | * Disable all interrupts for which a tasklet was scheduled right now, | ||
1551 | * the tasklet will reenable the appropriate interrupts. | ||
1552 | */ | ||
1553 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | ||
1554 | |||
1555 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | ||
1556 | reg |= mask; | ||
1557 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | ||
1558 | |||
1559 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); | ||
1560 | |||
1561 | return IRQ_HANDLED; | ||
1499 | } | 1562 | } |
1500 | 1563 | ||
1501 | /* | 1564 | /* |
@@ -1952,7 +2015,9 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { | |||
1952 | 2015 | ||
1953 | static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { | 2016 | static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { |
1954 | .irq_handler = rt2500pci_interrupt, | 2017 | .irq_handler = rt2500pci_interrupt, |
1955 | .irq_handler_thread = rt2500pci_interrupt_thread, | 2018 | .txstatus_tasklet = rt2500pci_txstatus_tasklet, |
2019 | .tbtt_tasklet = rt2500pci_tbtt_tasklet, | ||
2020 | .rxdone_tasklet = rt2500pci_rxdone_tasklet, | ||
1956 | .probe_hw = rt2500pci_probe_hw, | 2021 | .probe_hw = rt2500pci_probe_hw, |
1957 | .initialize = rt2x00pci_initialize, | 2022 | .initialize = rt2x00pci_initialize, |
1958 | .uninitialize = rt2x00pci_uninitialize, | 2023 | .uninitialize = rt2x00pci_uninitialize, |