diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2400pci.c | 54 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500pci.c | 55 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2500usb.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800pci.c | 50 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2800usb.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00pci.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00reg.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt61pci.c | 64 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt73usb.c | 2 |
11 files changed, 201 insertions, 70 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 25e9dcf65c4e..116244b72371 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -879,7 +879,8 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev, | |||
879 | static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | 879 | static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, |
880 | enum dev_state state) | 880 | enum dev_state state) |
881 | { | 881 | { |
882 | int mask = (state == STATE_RADIO_IRQ_OFF); | 882 | int mask = (state == STATE_RADIO_IRQ_OFF) || |
883 | (state == STATE_RADIO_IRQ_OFF_ISR); | ||
883 | u32 reg; | 884 | u32 reg; |
884 | 885 | ||
885 | /* | 886 | /* |
@@ -980,7 +981,9 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
980 | rt2400pci_toggle_rx(rt2x00dev, state); | 981 | rt2400pci_toggle_rx(rt2x00dev, state); |
981 | break; | 982 | break; |
982 | case STATE_RADIO_IRQ_ON: | 983 | case STATE_RADIO_IRQ_ON: |
984 | case STATE_RADIO_IRQ_ON_ISR: | ||
983 | case STATE_RADIO_IRQ_OFF: | 985 | case STATE_RADIO_IRQ_OFF: |
986 | case STATE_RADIO_IRQ_OFF_ISR: | ||
984 | rt2400pci_toggle_irq(rt2x00dev, state); | 987 | rt2400pci_toggle_irq(rt2x00dev, state); |
985 | break; | 988 | break; |
986 | case STATE_DEEP_SLEEP: | 989 | case STATE_DEEP_SLEEP: |
@@ -1235,23 +1238,10 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1235 | } | 1238 | } |
1236 | } | 1239 | } |
1237 | 1240 | ||
1238 | static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) | 1241 | static irqreturn_t rt2400pci_interrupt_thread(int irq, void *dev_instance) |
1239 | { | 1242 | { |
1240 | struct rt2x00_dev *rt2x00dev = dev_instance; | 1243 | struct rt2x00_dev *rt2x00dev = dev_instance; |
1241 | u32 reg; | 1244 | u32 reg = rt2x00dev->irqvalue[0]; |
1242 | |||
1243 | /* | ||
1244 | * Get the interrupt sources & saved to local variable. | ||
1245 | * Write register value back to clear pending interrupts. | ||
1246 | */ | ||
1247 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | ||
1248 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | ||
1249 | |||
1250 | if (!reg) | ||
1251 | return IRQ_NONE; | ||
1252 | |||
1253 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
1254 | return IRQ_HANDLED; | ||
1255 | 1245 | ||
1256 | /* | 1246 | /* |
1257 | * Handle interrupts, walk through all bits | 1247 | * Handle interrupts, walk through all bits |
@@ -1289,9 +1279,40 @@ static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) | |||
1289 | if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) | 1279 | if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) |
1290 | rt2400pci_txdone(rt2x00dev, QID_AC_BK); | 1280 | rt2400pci_txdone(rt2x00dev, QID_AC_BK); |
1291 | 1281 | ||
1282 | /* Enable interrupts again. */ | ||
1283 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
1284 | STATE_RADIO_IRQ_ON_ISR); | ||
1292 | return IRQ_HANDLED; | 1285 | return IRQ_HANDLED; |
1293 | } | 1286 | } |
1294 | 1287 | ||
1288 | static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) | ||
1289 | { | ||
1290 | struct rt2x00_dev *rt2x00dev = dev_instance; | ||
1291 | u32 reg; | ||
1292 | |||
1293 | /* | ||
1294 | * Get the interrupt sources & saved to local variable. | ||
1295 | * Write register value back to clear pending interrupts. | ||
1296 | */ | ||
1297 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | ||
1298 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | ||
1299 | |||
1300 | if (!reg) | ||
1301 | return IRQ_NONE; | ||
1302 | |||
1303 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
1304 | return IRQ_HANDLED; | ||
1305 | |||
1306 | /* Store irqvalues for use in the interrupt thread. */ | ||
1307 | rt2x00dev->irqvalue[0] = reg; | ||
1308 | |||
1309 | /* Disable interrupts, will be enabled again in the interrupt thread. */ | ||
1310 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
1311 | STATE_RADIO_IRQ_OFF_ISR); | ||
1312 | |||
1313 | return IRQ_WAKE_THREAD; | ||
1314 | } | ||
1315 | |||
1295 | /* | 1316 | /* |
1296 | * Device probe functions. | 1317 | * Device probe functions. |
1297 | */ | 1318 | */ |
@@ -1581,6 +1602,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { | |||
1581 | 1602 | ||
1582 | static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { | 1603 | static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { |
1583 | .irq_handler = rt2400pci_interrupt, | 1604 | .irq_handler = rt2400pci_interrupt, |
1605 | .irq_handler_thread = rt2400pci_interrupt_thread, | ||
1584 | .probe_hw = rt2400pci_probe_hw, | 1606 | .probe_hw = rt2400pci_probe_hw, |
1585 | .initialize = rt2x00pci_initialize, | 1607 | .initialize = rt2x00pci_initialize, |
1586 | .uninitialize = rt2x00pci_uninitialize, | 1608 | .uninitialize = rt2x00pci_uninitialize, |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index faa804cf181a..5e80948d1a3e 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -1033,7 +1033,8 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev, | |||
1033 | static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | 1033 | static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, |
1034 | enum dev_state state) | 1034 | enum dev_state state) |
1035 | { | 1035 | { |
1036 | int mask = (state == STATE_RADIO_IRQ_OFF); | 1036 | int mask = (state == STATE_RADIO_IRQ_OFF) || |
1037 | (state == STATE_RADIO_IRQ_OFF_ISR); | ||
1037 | u32 reg; | 1038 | u32 reg; |
1038 | 1039 | ||
1039 | /* | 1040 | /* |
@@ -1134,7 +1135,9 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
1134 | rt2500pci_toggle_rx(rt2x00dev, state); | 1135 | rt2500pci_toggle_rx(rt2x00dev, state); |
1135 | break; | 1136 | break; |
1136 | case STATE_RADIO_IRQ_ON: | 1137 | case STATE_RADIO_IRQ_ON: |
1138 | case STATE_RADIO_IRQ_ON_ISR: | ||
1137 | case STATE_RADIO_IRQ_OFF: | 1139 | case STATE_RADIO_IRQ_OFF: |
1140 | case STATE_RADIO_IRQ_OFF_ISR: | ||
1138 | rt2500pci_toggle_irq(rt2x00dev, state); | 1141 | rt2500pci_toggle_irq(rt2x00dev, state); |
1139 | break; | 1142 | break; |
1140 | case STATE_DEEP_SLEEP: | 1143 | case STATE_DEEP_SLEEP: |
@@ -1367,23 +1370,10 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, | |||
1367 | } | 1370 | } |
1368 | } | 1371 | } |
1369 | 1372 | ||
1370 | static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) | 1373 | static irqreturn_t rt2500pci_interrupt_thread(int irq, void *dev_instance) |
1371 | { | 1374 | { |
1372 | struct rt2x00_dev *rt2x00dev = dev_instance; | 1375 | struct rt2x00_dev *rt2x00dev = dev_instance; |
1373 | u32 reg; | 1376 | u32 reg = rt2x00dev->irqvalue[0]; |
1374 | |||
1375 | /* | ||
1376 | * Get the interrupt sources & saved to local variable. | ||
1377 | * Write register value back to clear pending interrupts. | ||
1378 | */ | ||
1379 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | ||
1380 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | ||
1381 | |||
1382 | if (!reg) | ||
1383 | return IRQ_NONE; | ||
1384 | |||
1385 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
1386 | return IRQ_HANDLED; | ||
1387 | 1377 | ||
1388 | /* | 1378 | /* |
1389 | * Handle interrupts, walk through all bits | 1379 | * Handle interrupts, walk through all bits |
@@ -1421,9 +1411,41 @@ static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) | |||
1421 | if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) | 1411 | if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) |
1422 | rt2500pci_txdone(rt2x00dev, QID_AC_BK); | 1412 | rt2500pci_txdone(rt2x00dev, QID_AC_BK); |
1423 | 1413 | ||
1414 | /* Enable interrupts again. */ | ||
1415 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
1416 | STATE_RADIO_IRQ_ON_ISR); | ||
1417 | |||
1424 | return IRQ_HANDLED; | 1418 | return IRQ_HANDLED; |
1425 | } | 1419 | } |
1426 | 1420 | ||
1421 | static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) | ||
1422 | { | ||
1423 | struct rt2x00_dev *rt2x00dev = dev_instance; | ||
1424 | u32 reg; | ||
1425 | |||
1426 | /* | ||
1427 | * Get the interrupt sources & saved to local variable. | ||
1428 | * Write register value back to clear pending interrupts. | ||
1429 | */ | ||
1430 | rt2x00pci_register_read(rt2x00dev, CSR7, ®); | ||
1431 | rt2x00pci_register_write(rt2x00dev, CSR7, reg); | ||
1432 | |||
1433 | if (!reg) | ||
1434 | return IRQ_NONE; | ||
1435 | |||
1436 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
1437 | return IRQ_HANDLED; | ||
1438 | |||
1439 | /* Store irqvalues for use in the interrupt thread. */ | ||
1440 | rt2x00dev->irqvalue[0] = reg; | ||
1441 | |||
1442 | /* Disable interrupts, will be enabled again in the interrupt thread. */ | ||
1443 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
1444 | STATE_RADIO_IRQ_OFF_ISR); | ||
1445 | |||
1446 | return IRQ_WAKE_THREAD; | ||
1447 | } | ||
1448 | |||
1427 | /* | 1449 | /* |
1428 | * Device probe functions. | 1450 | * Device probe functions. |
1429 | */ | 1451 | */ |
@@ -1874,6 +1896,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { | |||
1874 | 1896 | ||
1875 | static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { | 1897 | static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { |
1876 | .irq_handler = rt2500pci_interrupt, | 1898 | .irq_handler = rt2500pci_interrupt, |
1899 | .irq_handler_thread = rt2500pci_interrupt_thread, | ||
1877 | .probe_hw = rt2500pci_probe_hw, | 1900 | .probe_hw = rt2500pci_probe_hw, |
1878 | .initialize = rt2x00pci_initialize, | 1901 | .initialize = rt2x00pci_initialize, |
1879 | .uninitialize = rt2x00pci_uninitialize, | 1902 | .uninitialize = rt2x00pci_uninitialize, |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 009323e6c20f..242d59558b79 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -1004,7 +1004,9 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
1004 | rt2500usb_toggle_rx(rt2x00dev, state); | 1004 | rt2500usb_toggle_rx(rt2x00dev, state); |
1005 | break; | 1005 | break; |
1006 | case STATE_RADIO_IRQ_ON: | 1006 | case STATE_RADIO_IRQ_ON: |
1007 | case STATE_RADIO_IRQ_ON_ISR: | ||
1007 | case STATE_RADIO_IRQ_OFF: | 1008 | case STATE_RADIO_IRQ_OFF: |
1009 | case STATE_RADIO_IRQ_OFF_ISR: | ||
1008 | /* No support, but no error either */ | 1010 | /* No support, but no error either */ |
1009 | break; | 1011 | break; |
1010 | case STATE_DEEP_SLEEP: | 1012 | case STATE_DEEP_SLEEP: |
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index a9eca99d416c..f21b77c61ad4 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c | |||
@@ -422,7 +422,8 @@ static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev, | |||
422 | static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | 422 | static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, |
423 | enum dev_state state) | 423 | enum dev_state state) |
424 | { | 424 | { |
425 | int mask = (state == STATE_RADIO_IRQ_ON); | 425 | int mask = (state == STATE_RADIO_IRQ_ON) || |
426 | (state == STATE_RADIO_IRQ_ON_ISR); | ||
426 | u32 reg; | 427 | u32 reg; |
427 | 428 | ||
428 | /* | 429 | /* |
@@ -631,7 +632,9 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
631 | rt2800pci_toggle_rx(rt2x00dev, state); | 632 | rt2800pci_toggle_rx(rt2x00dev, state); |
632 | break; | 633 | break; |
633 | case STATE_RADIO_IRQ_ON: | 634 | case STATE_RADIO_IRQ_ON: |
635 | case STATE_RADIO_IRQ_ON_ISR: | ||
634 | case STATE_RADIO_IRQ_OFF: | 636 | case STATE_RADIO_IRQ_OFF: |
637 | case STATE_RADIO_IRQ_OFF_ISR: | ||
635 | rt2800pci_toggle_irq(rt2x00dev, state); | 638 | rt2800pci_toggle_irq(rt2x00dev, state); |
636 | break; | 639 | break; |
637 | case STATE_DEEP_SLEEP: | 640 | case STATE_DEEP_SLEEP: |
@@ -929,20 +932,10 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev) | |||
929 | rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); | 932 | rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); |
930 | } | 933 | } |
931 | 934 | ||
932 | static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) | 935 | static irqreturn_t rt2800pci_interrupt_thread(int irq, void *dev_instance) |
933 | { | 936 | { |
934 | struct rt2x00_dev *rt2x00dev = dev_instance; | 937 | struct rt2x00_dev *rt2x00dev = dev_instance; |
935 | u32 reg; | 938 | u32 reg = rt2x00dev->irqvalue[0]; |
936 | |||
937 | /* Read status and ACK all interrupts */ | ||
938 | rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); | ||
939 | rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); | ||
940 | |||
941 | if (!reg) | ||
942 | return IRQ_NONE; | ||
943 | |||
944 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
945 | return IRQ_HANDLED; | ||
946 | 939 | ||
947 | /* | 940 | /* |
948 | * 1 - Rx ring done interrupt. | 941 | * 1 - Rx ring done interrupt. |
@@ -962,9 +955,39 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) | |||
962 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) | 955 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP)) |
963 | rt2800pci_wakeup(rt2x00dev); | 956 | rt2800pci_wakeup(rt2x00dev); |
964 | 957 | ||
958 | /* Enable interrupts again. */ | ||
959 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
960 | STATE_RADIO_IRQ_ON_ISR); | ||
961 | |||
965 | return IRQ_HANDLED; | 962 | return IRQ_HANDLED; |
966 | } | 963 | } |
967 | 964 | ||
965 | static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance) | ||
966 | { | ||
967 | struct rt2x00_dev *rt2x00dev = dev_instance; | ||
968 | u32 reg; | ||
969 | |||
970 | /* Read status and ACK all interrupts */ | ||
971 | rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, ®); | ||
972 | rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg); | ||
973 | |||
974 | if (!reg) | ||
975 | return IRQ_NONE; | ||
976 | |||
977 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
978 | return IRQ_HANDLED; | ||
979 | |||
980 | /* Store irqvalue for use in the interrupt thread. */ | ||
981 | rt2x00dev->irqvalue[0] = reg; | ||
982 | |||
983 | /* Disable interrupts, will be enabled again in the interrupt thread. */ | ||
984 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
985 | STATE_RADIO_IRQ_OFF_ISR); | ||
986 | |||
987 | |||
988 | return IRQ_WAKE_THREAD; | ||
989 | } | ||
990 | |||
968 | /* | 991 | /* |
969 | * Device probe functions. | 992 | * Device probe functions. |
970 | */ | 993 | */ |
@@ -1049,6 +1072,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) | |||
1049 | 1072 | ||
1050 | static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { | 1073 | static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { |
1051 | .irq_handler = rt2800pci_interrupt, | 1074 | .irq_handler = rt2800pci_interrupt, |
1075 | .irq_handler_thread = rt2800pci_interrupt_thread, | ||
1052 | .probe_hw = rt2800pci_probe_hw, | 1076 | .probe_hw = rt2800pci_probe_hw, |
1053 | .get_firmware_name = rt2800pci_get_firmware_name, | 1077 | .get_firmware_name = rt2800pci_get_firmware_name, |
1054 | .check_firmware = rt2800pci_check_firmware, | 1078 | .check_firmware = rt2800pci_check_firmware, |
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5aa7563155cd..df78e28526bf 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c | |||
@@ -406,7 +406,9 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
406 | rt2800usb_toggle_rx(rt2x00dev, state); | 406 | rt2800usb_toggle_rx(rt2x00dev, state); |
407 | break; | 407 | break; |
408 | case STATE_RADIO_IRQ_ON: | 408 | case STATE_RADIO_IRQ_ON: |
409 | case STATE_RADIO_IRQ_ON_ISR: | ||
409 | case STATE_RADIO_IRQ_OFF: | 410 | case STATE_RADIO_IRQ_OFF: |
411 | case STATE_RADIO_IRQ_OFF_ISR: | ||
410 | /* No support, but no error either */ | 412 | /* No support, but no error either */ |
411 | break; | 413 | break; |
412 | case STATE_DEEP_SLEEP: | 414 | case STATE_DEEP_SLEEP: |
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 97b6261fee4f..0fa21410676f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h | |||
@@ -515,6 +515,11 @@ struct rt2x00lib_ops { | |||
515 | irq_handler_t irq_handler; | 515 | irq_handler_t irq_handler; |
516 | 516 | ||
517 | /* | 517 | /* |
518 | * Threaded Interrupt handlers. | ||
519 | */ | ||
520 | irq_handler_t irq_handler_thread; | ||
521 | |||
522 | /* | ||
518 | * Device init handlers. | 523 | * Device init handlers. |
519 | */ | 524 | */ |
520 | int (*probe_hw) (struct rt2x00_dev *rt2x00dev); | 525 | int (*probe_hw) (struct rt2x00_dev *rt2x00dev); |
@@ -871,6 +876,12 @@ struct rt2x00_dev { | |||
871 | const struct firmware *fw; | 876 | const struct firmware *fw; |
872 | 877 | ||
873 | /* | 878 | /* |
879 | * Interrupt values, stored between interrupt service routine | ||
880 | * and interrupt thread routine. | ||
881 | */ | ||
882 | u32 irqvalue[2]; | ||
883 | |||
884 | /* | ||
874 | * Driver specific data. | 885 | * Driver specific data. |
875 | */ | 886 | */ |
876 | void *priv; | 887 | void *priv; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0906e14b347f..d3ebb4144562 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -340,9 +340,17 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
340 | * send the status report back. | 340 | * send the status report back. |
341 | */ | 341 | */ |
342 | if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) | 342 | if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) |
343 | ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); | 343 | /* |
344 | * Only PCI and SOC devices process the tx status in process | ||
345 | * context. Hence use ieee80211_tx_status for PCI and SOC | ||
346 | * devices and stick to ieee80211_tx_status_irqsafe for USB. | ||
347 | */ | ||
348 | if (rt2x00_is_usb(rt2x00dev)) | ||
349 | ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); | ||
350 | else | ||
351 | ieee80211_tx_status(rt2x00dev->hw, entry->skb); | ||
344 | else | 352 | else |
345 | dev_kfree_skb_irq(entry->skb); | 353 | dev_kfree_skb_any(entry->skb); |
346 | 354 | ||
347 | /* | 355 | /* |
348 | * Make this entry available for reuse. | 356 | * Make this entry available for reuse. |
@@ -489,7 +497,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, | |||
489 | */ | 497 | */ |
490 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); | 498 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); |
491 | memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); | 499 | memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); |
492 | ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); | 500 | |
501 | /* | ||
502 | * Currently only PCI and SOC devices handle rx interrupts in process | ||
503 | * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni | ||
504 | * for PCI and SOC devices. | ||
505 | */ | ||
506 | if (rt2x00_is_usb(rt2x00dev)) | ||
507 | ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); | ||
508 | else | ||
509 | ieee80211_rx_ni(rt2x00dev->hw, entry->skb); | ||
493 | 510 | ||
494 | /* | 511 | /* |
495 | * Replace the skb with the freshly allocated one. | 512 | * Replace the skb with the freshly allocated one. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index fc9da8358784..19b262e1ddbe 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c | |||
@@ -153,8 +153,10 @@ int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev) | |||
153 | /* | 153 | /* |
154 | * Register interrupt handler. | 154 | * Register interrupt handler. |
155 | */ | 155 | */ |
156 | status = request_irq(rt2x00dev->irq, rt2x00dev->ops->lib->irq_handler, | 156 | status = request_threaded_irq(rt2x00dev->irq, |
157 | IRQF_SHARED, rt2x00dev->name, rt2x00dev); | 157 | rt2x00dev->ops->lib->irq_handler, |
158 | rt2x00dev->ops->lib->irq_handler_thread, | ||
159 | IRQF_SHARED, rt2x00dev->name, rt2x00dev); | ||
158 | if (status) { | 160 | if (status) { |
159 | ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", | 161 | ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n", |
160 | rt2x00dev->irq, status); | 162 | rt2x00dev->irq, status); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index b9fe94873ee0..055501c355a5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h | |||
@@ -88,6 +88,8 @@ enum dev_state { | |||
88 | STATE_RADIO_RX_OFF_LINK, | 88 | STATE_RADIO_RX_OFF_LINK, |
89 | STATE_RADIO_IRQ_ON, | 89 | STATE_RADIO_IRQ_ON, |
90 | STATE_RADIO_IRQ_OFF, | 90 | STATE_RADIO_IRQ_OFF, |
91 | STATE_RADIO_IRQ_ON_ISR, | ||
92 | STATE_RADIO_IRQ_OFF_ISR, | ||
91 | }; | 93 | }; |
92 | 94 | ||
93 | /* | 95 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index fe7bce7c05de..049433fa760d 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -1622,7 +1622,8 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev, | |||
1622 | static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, | 1622 | static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, |
1623 | enum dev_state state) | 1623 | enum dev_state state) |
1624 | { | 1624 | { |
1625 | int mask = (state == STATE_RADIO_IRQ_OFF); | 1625 | int mask = (state == STATE_RADIO_IRQ_OFF) || |
1626 | (state == STATE_RADIO_IRQ_OFF_ISR); | ||
1626 | u32 reg; | 1627 | u32 reg; |
1627 | 1628 | ||
1628 | /* | 1629 | /* |
@@ -1739,7 +1740,9 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
1739 | rt61pci_toggle_rx(rt2x00dev, state); | 1740 | rt61pci_toggle_rx(rt2x00dev, state); |
1740 | break; | 1741 | break; |
1741 | case STATE_RADIO_IRQ_ON: | 1742 | case STATE_RADIO_IRQ_ON: |
1743 | case STATE_RADIO_IRQ_ON_ISR: | ||
1742 | case STATE_RADIO_IRQ_OFF: | 1744 | case STATE_RADIO_IRQ_OFF: |
1745 | case STATE_RADIO_IRQ_OFF_ISR: | ||
1743 | rt61pci_toggle_irq(rt2x00dev, state); | 1746 | rt61pci_toggle_irq(rt2x00dev, state); |
1744 | break; | 1747 | break; |
1745 | case STATE_DEEP_SLEEP: | 1748 | case STATE_DEEP_SLEEP: |
@@ -2147,27 +2150,11 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev) | |||
2147 | rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); | 2150 | rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS); |
2148 | } | 2151 | } |
2149 | 2152 | ||
2150 | static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) | 2153 | static irqreturn_t rt61pci_interrupt_thread(int irq, void *dev_instance) |
2151 | { | 2154 | { |
2152 | struct rt2x00_dev *rt2x00dev = dev_instance; | 2155 | struct rt2x00_dev *rt2x00dev = dev_instance; |
2153 | u32 reg_mcu; | 2156 | u32 reg = rt2x00dev->irqvalue[0]; |
2154 | u32 reg; | 2157 | u32 reg_mcu = rt2x00dev->irqvalue[1]; |
2155 | |||
2156 | /* | ||
2157 | * Get the interrupt sources & saved to local variable. | ||
2158 | * Write register value back to clear pending interrupts. | ||
2159 | */ | ||
2160 | rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu); | ||
2161 | rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); | ||
2162 | |||
2163 | rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); | ||
2164 | rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); | ||
2165 | |||
2166 | if (!reg && !reg_mcu) | ||
2167 | return IRQ_NONE; | ||
2168 | |||
2169 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
2170 | return IRQ_HANDLED; | ||
2171 | 2158 | ||
2172 | /* | 2159 | /* |
2173 | * Handle interrupts, walk through all bits | 2160 | * Handle interrupts, walk through all bits |
@@ -2206,9 +2193,45 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) | |||
2206 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) | 2193 | if (rt2x00_get_field32(reg, INT_SOURCE_CSR_BEACON_DONE)) |
2207 | rt2x00lib_beacondone(rt2x00dev); | 2194 | rt2x00lib_beacondone(rt2x00dev); |
2208 | 2195 | ||
2196 | /* Enable interrupts again. */ | ||
2197 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
2198 | STATE_RADIO_IRQ_ON_ISR); | ||
2209 | return IRQ_HANDLED; | 2199 | return IRQ_HANDLED; |
2210 | } | 2200 | } |
2211 | 2201 | ||
2202 | |||
2203 | static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) | ||
2204 | { | ||
2205 | struct rt2x00_dev *rt2x00dev = dev_instance; | ||
2206 | u32 reg_mcu; | ||
2207 | u32 reg; | ||
2208 | |||
2209 | /* | ||
2210 | * Get the interrupt sources & saved to local variable. | ||
2211 | * Write register value back to clear pending interrupts. | ||
2212 | */ | ||
2213 | rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®_mcu); | ||
2214 | rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu); | ||
2215 | |||
2216 | rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); | ||
2217 | rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); | ||
2218 | |||
2219 | if (!reg && !reg_mcu) | ||
2220 | return IRQ_NONE; | ||
2221 | |||
2222 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
2223 | return IRQ_HANDLED; | ||
2224 | |||
2225 | /* Store irqvalues for use in the interrupt thread. */ | ||
2226 | rt2x00dev->irqvalue[0] = reg; | ||
2227 | rt2x00dev->irqvalue[1] = reg_mcu; | ||
2228 | |||
2229 | /* Disable interrupts, will be enabled again in the interrupt thread. */ | ||
2230 | rt2x00dev->ops->lib->set_device_state(rt2x00dev, | ||
2231 | STATE_RADIO_IRQ_OFF_ISR); | ||
2232 | return IRQ_WAKE_THREAD; | ||
2233 | } | ||
2234 | |||
2212 | /* | 2235 | /* |
2213 | * Device probe functions. | 2236 | * Device probe functions. |
2214 | */ | 2237 | */ |
@@ -2795,6 +2818,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { | |||
2795 | 2818 | ||
2796 | static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { | 2819 | static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { |
2797 | .irq_handler = rt61pci_interrupt, | 2820 | .irq_handler = rt61pci_interrupt, |
2821 | .irq_handler_thread = rt61pci_interrupt_thread, | ||
2798 | .probe_hw = rt61pci_probe_hw, | 2822 | .probe_hw = rt61pci_probe_hw, |
2799 | .get_firmware_name = rt61pci_get_firmware_name, | 2823 | .get_firmware_name = rt61pci_get_firmware_name, |
2800 | .check_firmware = rt61pci_check_firmware, | 2824 | .check_firmware = rt61pci_check_firmware, |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index cad07b69c53e..aa9de18fd410 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -1400,7 +1400,9 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, | |||
1400 | rt73usb_toggle_rx(rt2x00dev, state); | 1400 | rt73usb_toggle_rx(rt2x00dev, state); |
1401 | break; | 1401 | break; |
1402 | case STATE_RADIO_IRQ_ON: | 1402 | case STATE_RADIO_IRQ_ON: |
1403 | case STATE_RADIO_IRQ_ON_ISR: | ||
1403 | case STATE_RADIO_IRQ_OFF: | 1404 | case STATE_RADIO_IRQ_OFF: |
1405 | case STATE_RADIO_IRQ_OFF_ISR: | ||
1404 | /* No support, but no error either */ | 1406 | /* No support, but no error either */ |
1405 | break; | 1407 | break; |
1406 | case STATE_DEEP_SLEEP: | 1408 | case STATE_DEEP_SLEEP: |