diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2400pci.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2400pci.c | 165 |
1 files changed, 117 insertions, 48 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 54ca49ad3472..2725f3c4442e 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -46,7 +46,7 @@ | |||
46 | * These indirect registers work with busy bits, | 46 | * These indirect registers work with busy bits, |
47 | * and we will try maximal REGISTER_BUSY_COUNT times to access | 47 | * and we will try maximal REGISTER_BUSY_COUNT times to access |
48 | * the register while taking a REGISTER_BUSY_DELAY us delay | 48 | * the register while taking a REGISTER_BUSY_DELAY us delay |
49 | * between each attampt. When the busy bit is still set at that time, | 49 | * between each attempt. When the busy bit is still set at that time, |
50 | * the access attempt is considered to have failed, | 50 | * the access attempt is considered to have failed, |
51 | * and we will print an error. | 51 | * and we will print an error. |
52 | */ | 52 | */ |
@@ -305,9 +305,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, | |||
305 | * Enable synchronisation. | 305 | * Enable synchronisation. |
306 | */ | 306 | */ |
307 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 307 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
308 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | ||
309 | rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); | 308 | rt2x00_set_field32(®, CSR14_TSF_SYNC, conf->sync); |
310 | rt2x00_set_field32(®, CSR14_TBCN, 1); | ||
311 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 309 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
312 | } | 310 | } |
313 | 311 | ||
@@ -647,6 +645,11 @@ static void rt2400pci_start_queue(struct data_queue *queue) | |||
647 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); | 645 | rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); |
648 | break; | 646 | break; |
649 | case QID_BEACON: | 647 | case QID_BEACON: |
648 | /* | ||
649 | * Allow the tbtt tasklet to be scheduled. | ||
650 | */ | ||
651 | tasklet_enable(&rt2x00dev->tbtt_tasklet); | ||
652 | |||
650 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); | 653 | rt2x00pci_register_read(rt2x00dev, CSR14, ®); |
651 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | 654 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); |
652 | rt2x00_set_field32(®, CSR14_TBCN, 1); | 655 | rt2x00_set_field32(®, CSR14_TBCN, 1); |
@@ -708,6 +711,11 @@ static void rt2400pci_stop_queue(struct data_queue *queue) | |||
708 | rt2x00_set_field32(®, CSR14_TBCN, 0); | 711 | rt2x00_set_field32(®, CSR14_TBCN, 0); |
709 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); | 712 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); |
710 | 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); | ||
711 | break; | 719 | break; |
712 | default: | 720 | default: |
713 | break; | 721 | break; |
@@ -963,9 +971,9 @@ static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev) | |||
963 | static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | 971 | static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, |
964 | enum dev_state state) | 972 | enum dev_state state) |
965 | { | 973 | { |
966 | int mask = (state == STATE_RADIO_IRQ_OFF) || | 974 | int mask = (state == STATE_RADIO_IRQ_OFF); |
967 | (state == STATE_RADIO_IRQ_OFF_ISR); | ||
968 | u32 reg; | 975 | u32 reg; |
976 | unsigned long flags; | ||
969 | 977 | ||
970 | /* | 978 | /* |
971 | * When interrupts are being enabled, the interrupt registers | 979 | * When interrupts are being enabled, the interrupt registers |
@@ -974,12 +982,20 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
974 | if (state == STATE_RADIO_IRQ_ON) { | 982 | if (state == STATE_RADIO_IRQ_ON) { |
975 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | 983 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); |
976 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | 984 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); |
985 | |||
986 | /* | ||
987 | * Enable tasklets. | ||
988 | */ | ||
989 | tasklet_enable(&rt2x00dev->txstatus_tasklet); | ||
990 | tasklet_enable(&rt2x00dev->rxdone_tasklet); | ||
977 | } | 991 | } |
978 | 992 | ||
979 | /* | 993 | /* |
980 | * Only toggle the interrupts bits we are going to use. | 994 | * Only toggle the interrupts bits we are going to use. |
981 | * Non-checked interrupt bits are disabled by default. | 995 | * Non-checked interrupt bits are disabled by default. |
982 | */ | 996 | */ |
997 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | ||
998 | |||
983 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | 999 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
984 | rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); | 1000 | rt2x00_set_field32(®, CSR8_TBCN_EXPIRE, mask); |
985 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); | 1001 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, mask); |
@@ -987,6 +1003,17 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | |||
987 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); | 1003 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, mask); |
988 | rt2x00_set_field32(®, CSR8_RXDONE, mask); | 1004 | rt2x00_set_field32(®, CSR8_RXDONE, mask); |
989 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | 1005 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); |
1006 | |||
1007 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); | ||
1008 | |||
1009 | if (state == STATE_RADIO_IRQ_OFF) { | ||
1010 | /* | ||
1011 | * Ensure that all tasklets are finished before | ||
1012 | * disabling the interrupts. | ||
1013 | */ | ||
1014 | tasklet_disable(&rt2x00dev->txstatus_tasklet); | ||
1015 | tasklet_disable(&rt2x00dev->rxdone_tasklet); | ||
1016 | } | ||
990 | } | 1017 | } |
991 | 1018 | ||
992 | static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) | 1019 | static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev) |
@@ -1059,9 +1086,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
1059 | rt2400pci_disable_radio(rt2x00dev); | 1086 | rt2400pci_disable_radio(rt2x00dev); |
1060 | break; | 1087 | break; |
1061 | case STATE_RADIO_IRQ_ON: | 1088 | case STATE_RADIO_IRQ_ON: |
1062 | case STATE_RADIO_IRQ_ON_ISR: | ||
1063 | case STATE_RADIO_IRQ_OFF: | 1089 | case STATE_RADIO_IRQ_OFF: |
1064 | case STATE_RADIO_IRQ_OFF_ISR: | ||
1065 | rt2400pci_toggle_irq(rt2x00dev, state); | 1090 | rt2400pci_toggle_irq(rt2x00dev, state); |
1066 | break; | 1091 | break; |
1067 | case STATE_DEEP_SLEEP: | 1092 | case STATE_DEEP_SLEEP: |
@@ -1183,8 +1208,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry, | |||
1183 | /* | 1208 | /* |
1184 | * Enable beaconing again. | 1209 | * Enable beaconing again. |
1185 | */ | 1210 | */ |
1186 | rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); | ||
1187 | rt2x00_set_field32(®, CSR14_TBCN, 1); | ||
1188 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); | 1211 | rt2x00_set_field32(®, CSR14_BEACON_GEN, 1); |
1189 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); | 1212 | rt2x00pci_register_write(rt2x00dev, CSR14, reg); |
1190 | } | 1213 | } |
@@ -1289,57 +1312,71 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1289 | } | 1312 | } |
1290 | } | 1313 | } |
1291 | 1314 | ||
1292 | static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance) | 1315 | static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev, |
1316 | struct rt2x00_field32 irq_field) | ||
1293 | { | 1317 | { |
1294 | struct rt2x00_dev *rt2x00dev = dev_instance; | 1318 | unsigned long flags; |
1295 | u32 reg = rt2x00dev->irqvalue[0]; | 1319 | u32 reg; |
1296 | 1320 | ||
1297 | /* | 1321 | /* |
1298 | * Handle interrupts, walk through all bits | 1322 | * Enable a single interrupt. The interrupt mask register |
1299 | * and run the tasks, the bits are checked in order of | 1323 | * access needs locking. |
1300 | * priority. | ||
1301 | */ | 1324 | */ |
1325 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | ||
1302 | 1326 | ||
1303 | /* | 1327 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
1304 | * 1 - Beacon timer expired interrupt. | 1328 | rt2x00_set_field32(®, irq_field, 0); |
1305 | */ | 1329 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); |
1306 | if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) | ||
1307 | rt2x00lib_beacondone(rt2x00dev); | ||
1308 | 1330 | ||
1309 | /* | 1331 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); |
1310 | * 2 - Rx ring done interrupt. | 1332 | } |
1311 | */ | ||
1312 | if (rt2x00_get_field32(reg, CSR7_RXDONE)) | ||
1313 | rt2x00pci_rxdone(rt2x00dev); | ||
1314 | 1333 | ||
1315 | /* | 1334 | static void rt2400pci_txstatus_tasklet(unsigned long data) |
1316 | * 3 - Atim ring transmit done interrupt. | 1335 | { |
1317 | */ | 1336 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; |
1318 | if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) | 1337 | u32 reg; |
1319 | rt2400pci_txdone(rt2x00dev, QID_ATIM); | 1338 | unsigned long flags; |
1320 | 1339 | ||
1321 | /* | 1340 | /* |
1322 | * 4 - Priority ring transmit done interrupt. | 1341 | * Handle all tx queues. |
1323 | */ | 1342 | */ |
1324 | if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) | 1343 | rt2400pci_txdone(rt2x00dev, QID_ATIM); |
1325 | rt2400pci_txdone(rt2x00dev, QID_AC_VO); | 1344 | rt2400pci_txdone(rt2x00dev, QID_AC_VO); |
1345 | rt2400pci_txdone(rt2x00dev, QID_AC_VI); | ||
1326 | 1346 | ||
1327 | /* | 1347 | /* |
1328 | * 5 - Tx ring transmit done interrupt. | 1348 | * Enable all TXDONE interrupts again. |
1329 | */ | 1349 | */ |
1330 | if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) | 1350 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); |
1331 | rt2400pci_txdone(rt2x00dev, QID_AC_VI); | ||
1332 | 1351 | ||
1333 | /* Enable interrupts again. */ | 1352 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); |
1334 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | 1353 | rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); |
1335 | STATE_RADIO_IRQ_ON_ISR); | 1354 | rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); |
1336 | return IRQ_HANDLED; | 1355 | rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); |
1356 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | ||
1357 | |||
1358 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); | ||
1359 | } | ||
1360 | |||
1361 | static void rt2400pci_tbtt_tasklet(unsigned long data) | ||
1362 | { | ||
1363 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | ||
1364 | rt2x00lib_beacondone(rt2x00dev); | ||
1365 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); | ||
1366 | } | ||
1367 | |||
1368 | static void rt2400pci_rxdone_tasklet(unsigned long data) | ||
1369 | { | ||
1370 | struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; | ||
1371 | rt2x00pci_rxdone(rt2x00dev); | ||
1372 | rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); | ||
1337 | } | 1373 | } |
1338 | 1374 | ||
1339 | static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) | 1375 | static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) |
1340 | { | 1376 | { |
1341 | struct rt2x00_dev *rt2x00dev = dev_instance; | 1377 | struct rt2x00_dev *rt2x00dev = dev_instance; |
1342 | u32 reg; | 1378 | u32 reg, mask; |
1379 | unsigned long flags; | ||
1343 | 1380 | ||
1344 | /* | 1381 | /* |
1345 | * Get the interrupt sources & saved to local variable. | 1382 | * Get the interrupt sources & saved to local variable. |
@@ -1354,14 +1391,44 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) | |||
1354 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 1391 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
1355 | return IRQ_HANDLED; | 1392 | return IRQ_HANDLED; |
1356 | 1393 | ||
1357 | /* Store irqvalues for use in the interrupt thread. */ | 1394 | mask = reg; |
1358 | rt2x00dev->irqvalue[0] = reg; | ||
1359 | 1395 | ||
1360 | /* Disable interrupts, will be enabled again in the interrupt thread. */ | 1396 | /* |
1361 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | 1397 | * Schedule tasklets for interrupt handling. |
1362 | STATE_RADIO_IRQ_OFF_ISR); | 1398 | */ |
1399 | if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) | ||
1400 | tasklet_hi_schedule(&rt2x00dev->tbtt_tasklet); | ||
1363 | 1401 | ||
1364 | return IRQ_WAKE_THREAD; | 1402 | if (rt2x00_get_field32(reg, CSR7_RXDONE)) |
1403 | tasklet_schedule(&rt2x00dev->rxdone_tasklet); | ||
1404 | |||
1405 | if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING) || | ||
1406 | rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING) || | ||
1407 | rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) { | ||
1408 | tasklet_schedule(&rt2x00dev->txstatus_tasklet); | ||
1409 | /* | ||
1410 | * Mask out all txdone interrupts. | ||
1411 | */ | ||
1412 | rt2x00_set_field32(&mask, CSR8_TXDONE_TXRING, 1); | ||
1413 | rt2x00_set_field32(&mask, CSR8_TXDONE_ATIMRING, 1); | ||
1414 | rt2x00_set_field32(&mask, CSR8_TXDONE_PRIORING, 1); | ||
1415 | } | ||
1416 | |||
1417 | /* | ||
1418 | * Disable all interrupts for which a tasklet was scheduled right now, | ||
1419 | * the tasklet will reenable the appropriate interrupts. | ||
1420 | */ | ||
1421 | spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); | ||
1422 | |||
1423 | rt2x00pci_register_read(rt2x00dev, CSR8, ®); | ||
1424 | reg |= mask; | ||
1425 | rt2x00pci_register_write(rt2x00dev, CSR8, reg); | ||
1426 | |||
1427 | spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); | ||
1428 | |||
1429 | |||
1430 | |||
1431 | return IRQ_HANDLED; | ||
1365 | } | 1432 | } |
1366 | 1433 | ||
1367 | /* | 1434 | /* |
@@ -1655,7 +1722,9 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { | |||
1655 | 1722 | ||
1656 | static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { | 1723 | static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { |
1657 | .irq_handler = rt2400pci_interrupt, | 1724 | .irq_handler = rt2400pci_interrupt, |
1658 | .irq_handler_thread = rt2400pci_interrupt_thread, | 1725 | .txstatus_tasklet = rt2400pci_txstatus_tasklet, |
1726 | .tbtt_tasklet = rt2400pci_tbtt_tasklet, | ||
1727 | .rxdone_tasklet = rt2400pci_rxdone_tasklet, | ||
1659 | .probe_hw = rt2400pci_probe_hw, | 1728 | .probe_hw = rt2400pci_probe_hw, |
1660 | .initialize = rt2x00pci_initialize, | 1729 | .initialize = rt2x00pci_initialize, |
1661 | .uninitialize = rt2x00pci_uninitialize, | 1730 | .uninitialize = rt2x00pci_uninitialize, |