diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 154 |
1 files changed, 109 insertions, 45 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index bc07c56f89b3..014c307c270c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -136,12 +136,10 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
136 | /* | 136 | /* |
137 | * Stop all scheduled work. | 137 | * Stop all scheduled work. |
138 | */ | 138 | */ |
139 | if (work_pending(&rt2x00dev->beacon_work)) | 139 | if (work_pending(&rt2x00dev->intf_work)) |
140 | cancel_work_sync(&rt2x00dev->beacon_work); | 140 | cancel_work_sync(&rt2x00dev->intf_work); |
141 | if (work_pending(&rt2x00dev->filter_work)) | 141 | if (work_pending(&rt2x00dev->filter_work)) |
142 | cancel_work_sync(&rt2x00dev->filter_work); | 142 | cancel_work_sync(&rt2x00dev->filter_work); |
143 | if (work_pending(&rt2x00dev->config_work)) | ||
144 | cancel_work_sync(&rt2x00dev->config_work); | ||
145 | 143 | ||
146 | /* | 144 | /* |
147 | * Stop the TX queues. | 145 | * Stop the TX queues. |
@@ -173,7 +171,7 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) | |||
173 | * When we are enabling the RX, we should also start the link tuner. | 171 | * When we are enabling the RX, we should also start the link tuner. |
174 | */ | 172 | */ |
175 | if (state == STATE_RADIO_RX_ON && | 173 | if (state == STATE_RADIO_RX_ON && |
176 | is_interface_present(&rt2x00dev->interface)) | 174 | (rt2x00dev->intf_ap_count || rt2x00dev->intf_sta_count)) |
177 | rt2x00lib_start_link_tuner(rt2x00dev); | 175 | rt2x00lib_start_link_tuner(rt2x00dev); |
178 | } | 176 | } |
179 | 177 | ||
@@ -401,10 +399,10 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) | |||
401 | unsigned int filter = rt2x00dev->packet_filter; | 399 | unsigned int filter = rt2x00dev->packet_filter; |
402 | 400 | ||
403 | /* | 401 | /* |
404 | * Since we had stored the filter inside interface.filter, | 402 | * Since we had stored the filter inside rt2x00dev->packet_filter, |
405 | * we should now clear that field. Otherwise the driver will | 403 | * we should now clear that field. Otherwise the driver will |
406 | * assume nothing has changed (*total_flags will be compared | 404 | * assume nothing has changed (*total_flags will be compared |
407 | * to interface.filter to determine if any action is required). | 405 | * to rt2x00dev->packet_filter to determine if any action is required). |
408 | */ | 406 | */ |
409 | rt2x00dev->packet_filter = 0; | 407 | rt2x00dev->packet_filter = 0; |
410 | 408 | ||
@@ -412,41 +410,72 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) | |||
412 | filter, &filter, 0, NULL); | 410 | filter, &filter, 0, NULL); |
413 | } | 411 | } |
414 | 412 | ||
415 | static void rt2x00lib_configuration_scheduled(struct work_struct *work) | 413 | static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, |
414 | struct ieee80211_vif *vif) | ||
416 | { | 415 | { |
417 | struct rt2x00_dev *rt2x00dev = | 416 | struct rt2x00_dev *rt2x00dev = data; |
418 | container_of(work, struct rt2x00_dev, config_work); | 417 | struct rt2x00_intf *intf = vif_to_intf(vif); |
419 | struct ieee80211_bss_conf bss_conf; | 418 | struct sk_buff *skb; |
419 | struct ieee80211_tx_control control; | ||
420 | struct ieee80211_bss_conf conf; | ||
421 | int delayed_flags; | ||
422 | |||
423 | /* | ||
424 | * Copy all data we need during this action under the protection | ||
425 | * of a spinlock. Otherwise race conditions might occur which results | ||
426 | * into an invalid configuration. | ||
427 | */ | ||
428 | spin_lock(&intf->lock); | ||
429 | |||
430 | memcpy(&conf, &intf->conf, sizeof(conf)); | ||
431 | delayed_flags = intf->delayed_flags; | ||
432 | intf->delayed_flags = 0; | ||
433 | |||
434 | spin_unlock(&intf->lock); | ||
435 | |||
436 | if (delayed_flags & DELAYED_UPDATE_BEACON) { | ||
437 | skb = ieee80211_beacon_get(rt2x00dev->hw, vif, &control); | ||
438 | if (skb) { | ||
439 | rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, | ||
440 | &control); | ||
441 | dev_kfree_skb(skb); | ||
442 | } | ||
443 | } | ||
444 | |||
445 | if (delayed_flags & DELAYED_CONFIG_PREAMBLE) | ||
446 | rt2x00lib_config_preamble(rt2x00dev, intf, | ||
447 | intf->conf.use_short_preamble); | ||
448 | } | ||
420 | 449 | ||
421 | bss_conf.use_short_preamble = | 450 | static void rt2x00lib_intf_scheduled(struct work_struct *work) |
422 | test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); | 451 | { |
452 | struct rt2x00_dev *rt2x00dev = | ||
453 | container_of(work, struct rt2x00_dev, intf_work); | ||
423 | 454 | ||
424 | /* | 455 | /* |
425 | * FIXME: shouldn't invoke it this way because all other contents | 456 | * Iterate over each interface and perform the |
426 | * of bss_conf is invalid. | 457 | * requested configurations. |
427 | */ | 458 | */ |
428 | rt2x00mac_bss_info_changed(rt2x00dev->hw, rt2x00dev->interface.id, | 459 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, |
429 | &bss_conf, BSS_CHANGED_ERP_PREAMBLE); | 460 | rt2x00lib_intf_scheduled_iter, |
461 | rt2x00dev); | ||
430 | } | 462 | } |
431 | 463 | ||
432 | /* | 464 | /* |
433 | * Interrupt context handlers. | 465 | * Interrupt context handlers. |
434 | */ | 466 | */ |
435 | static void rt2x00lib_beacondone_scheduled(struct work_struct *work) | 467 | static void rt2x00lib_beacondone_iter(void *data, u8 *mac, |
468 | struct ieee80211_vif *vif) | ||
436 | { | 469 | { |
437 | struct rt2x00_dev *rt2x00dev = | 470 | struct rt2x00_intf *intf = vif_to_intf(vif); |
438 | container_of(work, struct rt2x00_dev, beacon_work); | ||
439 | struct ieee80211_tx_control control; | ||
440 | struct sk_buff *skb; | ||
441 | 471 | ||
442 | skb = ieee80211_beacon_get(rt2x00dev->hw, | 472 | if (vif->type != IEEE80211_IF_TYPE_AP && |
443 | rt2x00dev->interface.id, &control); | 473 | vif->type != IEEE80211_IF_TYPE_IBSS) |
444 | if (!skb) | ||
445 | return; | 474 | return; |
446 | 475 | ||
447 | rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb, &control); | 476 | spin_lock(&intf->lock); |
448 | 477 | intf->delayed_flags |= DELAYED_UPDATE_BEACON; | |
449 | dev_kfree_skb(skb); | 478 | spin_unlock(&intf->lock); |
450 | } | 479 | } |
451 | 480 | ||
452 | void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | 481 | void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) |
@@ -454,7 +483,11 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | |||
454 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) | 483 | if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) |
455 | return; | 484 | return; |
456 | 485 | ||
457 | queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work); | 486 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, |
487 | rt2x00lib_beacondone_iter, | ||
488 | rt2x00dev); | ||
489 | |||
490 | queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work); | ||
458 | } | 491 | } |
459 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); | 492 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); |
460 | 493 | ||
@@ -1037,6 +1070,10 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) | |||
1037 | return retval; | 1070 | return retval; |
1038 | } | 1071 | } |
1039 | 1072 | ||
1073 | rt2x00dev->intf_ap_count = 0; | ||
1074 | rt2x00dev->intf_sta_count = 0; | ||
1075 | rt2x00dev->intf_associated = 0; | ||
1076 | |||
1040 | __set_bit(DEVICE_STARTED, &rt2x00dev->flags); | 1077 | __set_bit(DEVICE_STARTED, &rt2x00dev->flags); |
1041 | 1078 | ||
1042 | return 0; | 1079 | return 0; |
@@ -1053,6 +1090,10 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) | |||
1053 | */ | 1090 | */ |
1054 | rt2x00lib_disable_radio(rt2x00dev); | 1091 | rt2x00lib_disable_radio(rt2x00dev); |
1055 | 1092 | ||
1093 | rt2x00dev->intf_ap_count = 0; | ||
1094 | rt2x00dev->intf_sta_count = 0; | ||
1095 | rt2x00dev->intf_associated = 0; | ||
1096 | |||
1056 | __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); | 1097 | __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); |
1057 | } | 1098 | } |
1058 | 1099 | ||
@@ -1064,6 +1105,12 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1064 | int retval = -ENOMEM; | 1105 | int retval = -ENOMEM; |
1065 | 1106 | ||
1066 | /* | 1107 | /* |
1108 | * Make room for rt2x00_intf inside the per-interface | ||
1109 | * structure ieee80211_vif. | ||
1110 | */ | ||
1111 | rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); | ||
1112 | |||
1113 | /* | ||
1067 | * Let the driver probe the device to detect the capabilities. | 1114 | * Let the driver probe the device to detect the capabilities. |
1068 | */ | 1115 | */ |
1069 | retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); | 1116 | retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev); |
@@ -1075,17 +1122,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) | |||
1075 | /* | 1122 | /* |
1076 | * Initialize configuration work. | 1123 | * Initialize configuration work. |
1077 | */ | 1124 | */ |
1078 | INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled); | 1125 | INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); |
1079 | INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); | 1126 | INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled); |
1080 | INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled); | ||
1081 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); | 1127 | INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner); |
1082 | 1128 | ||
1083 | /* | 1129 | /* |
1084 | * Reset current working type. | ||
1085 | */ | ||
1086 | rt2x00dev->interface.type = IEEE80211_IF_TYPE_INVALID; | ||
1087 | |||
1088 | /* | ||
1089 | * Allocate queue array. | 1130 | * Allocate queue array. |
1090 | */ | 1131 | */ |
1091 | retval = rt2x00queue_allocate(rt2x00dev); | 1132 | retval = rt2x00queue_allocate(rt2x00dev); |
@@ -1203,9 +1244,30 @@ exit: | |||
1203 | } | 1244 | } |
1204 | EXPORT_SYMBOL_GPL(rt2x00lib_suspend); | 1245 | EXPORT_SYMBOL_GPL(rt2x00lib_suspend); |
1205 | 1246 | ||
1247 | static void rt2x00lib_resume_intf(void *data, u8 *mac, | ||
1248 | struct ieee80211_vif *vif) | ||
1249 | { | ||
1250 | struct rt2x00_dev *rt2x00dev = data; | ||
1251 | struct rt2x00_intf *intf = vif_to_intf(vif); | ||
1252 | |||
1253 | spin_lock(&intf->lock); | ||
1254 | |||
1255 | rt2x00lib_config_intf(rt2x00dev, intf, | ||
1256 | vif->type, intf->mac, intf->bssid); | ||
1257 | |||
1258 | |||
1259 | /* | ||
1260 | * Master or Ad-hoc mode require a new beacon update. | ||
1261 | */ | ||
1262 | if (vif->type == IEEE80211_IF_TYPE_AP || | ||
1263 | vif->type == IEEE80211_IF_TYPE_IBSS) | ||
1264 | intf->delayed_flags |= DELAYED_UPDATE_BEACON; | ||
1265 | |||
1266 | spin_unlock(&intf->lock); | ||
1267 | } | ||
1268 | |||
1206 | int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) | 1269 | int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) |
1207 | { | 1270 | { |
1208 | struct interface *intf = &rt2x00dev->interface; | ||
1209 | int retval; | 1271 | int retval; |
1210 | 1272 | ||
1211 | NOTICE(rt2x00dev, "Waking up.\n"); | 1273 | NOTICE(rt2x00dev, "Waking up.\n"); |
@@ -1235,9 +1297,12 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) | |||
1235 | if (!rt2x00dev->hw->conf.radio_enabled) | 1297 | if (!rt2x00dev->hw->conf.radio_enabled) |
1236 | rt2x00lib_disable_radio(rt2x00dev); | 1298 | rt2x00lib_disable_radio(rt2x00dev); |
1237 | 1299 | ||
1238 | rt2x00lib_config_mac_addr(rt2x00dev, intf->mac); | 1300 | /* |
1239 | rt2x00lib_config_bssid(rt2x00dev, intf->bssid); | 1301 | * Iterator over each active interface to |
1240 | rt2x00lib_config_type(rt2x00dev, intf->type); | 1302 | * reconfigure the hardware. |
1303 | */ | ||
1304 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, | ||
1305 | rt2x00lib_resume_intf, rt2x00dev); | ||
1241 | 1306 | ||
1242 | /* | 1307 | /* |
1243 | * We are ready again to receive requests from mac80211. | 1308 | * We are ready again to receive requests from mac80211. |
@@ -1253,12 +1318,11 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) | |||
1253 | ieee80211_start_queues(rt2x00dev->hw); | 1318 | ieee80211_start_queues(rt2x00dev->hw); |
1254 | 1319 | ||
1255 | /* | 1320 | /* |
1256 | * When in Master or Ad-hoc mode, | 1321 | * During interface iteration we might have changed the |
1257 | * restart Beacon transmitting by faking a beacondone event. | 1322 | * delayed_flags, time to handles the event by calling |
1323 | * the work handler directly. | ||
1258 | */ | 1324 | */ |
1259 | if (intf->type == IEEE80211_IF_TYPE_AP || | 1325 | rt2x00lib_intf_scheduled(&rt2x00dev->intf_work); |
1260 | intf->type == IEEE80211_IF_TYPE_IBSS) | ||
1261 | rt2x00lib_beacondone(rt2x00dev); | ||
1262 | 1326 | ||
1263 | return 0; | 1327 | return 0; |
1264 | 1328 | ||