aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/rt2x00
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2011-01-30 07:16:03 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-31 15:06:22 -0500
commit69cf36a4523be026bc16743c5c989c5e82edb7d9 (patch)
tree0c6572b724d840d879ff12861d8ac57da1bad635 /drivers/net/wireless/rt2x00
parentd828cd5a95e532636dbc495e4b94b625ab9abdad (diff)
rt2x00: Refactor beacon code to make use of start- and stop_queue
This patch allows to dynamically remove beaconing interfaces without shutting beaconing down on all interfaces. The only place to start and stop beaconing are now the start- and stop_queue callbacks. Hence, we can remove some register writes during interface bring up (config_intf) and only write the correct sync mode to the register there. When multiple beaconing interfaces are present we should enable beaconing as soon as mac80211 enables beaconing on at least one of them. The beacon queue gets stopped when the last beaconing interface was stopped by mac80211. Therefore, introduce another interface counter to keep track ot the number of enabled beaconing interfaces and start or stop the beacon queue accordingly. To allow single interfaces to stop beaconing, add a new driver callback clear_beacon to clear a single interface's beacon without affecting the other interfaces. Don't overload the clear_entry callback for clearing beacons as that would introduce additional overhead (check for each TX queue) into the clear_entry callback which is used on the drivers TX/RX hotpaths. Furthermore, the write beacon callback doesn't need to enable beaconing anymore but since beaconing should be disabled while a new beacon is written or cleared we still disable beacon generation and enable it afterwards again in the driver specific callbacks. However, beacon related interrupts should not be disabled/enabled here, that's solely done from the start- and stop queue callbacks. It would be nice to stop the beacon queue just before the beacon update and enable it afterwards in rt2x00queue itself instead of the current implementation that relies on the driver doing the right thing. However, since start- and stop_queue are mutex protected we cannot use them for atomic beacon updates. 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/rt2x00')
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c67
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c41
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c38
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c41
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c42
14 files changed, 185 insertions, 85 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 54ca49ad3472..cb28e1b2f1e2 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -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, &reg); 307 rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
308 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
309 rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync); 308 rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync);
310 rt2x00_set_field32(&reg, CSR14_TBCN, 1);
311 rt2x00pci_register_write(rt2x00dev, CSR14, reg); 309 rt2x00pci_register_write(rt2x00dev, CSR14, reg);
312 } 310 }
313 311
@@ -1183,8 +1181,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
1183 /* 1181 /*
1184 * Enable beaconing again. 1182 * Enable beaconing again.
1185 */ 1183 */
1186 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
1187 rt2x00_set_field32(&reg, CSR14_TBCN, 1);
1188 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1); 1184 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
1189 rt2x00pci_register_write(rt2x00dev, CSR14, reg); 1185 rt2x00pci_register_write(rt2x00dev, CSR14, reg);
1190} 1186}
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index a9ff26a27724..5225ae1899fe 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, &reg); 313 rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
314 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
315 rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync); 314 rt2x00_set_field32(&reg, CSR14_TSF_SYNC, conf->sync);
316 rt2x00_set_field32(&reg, CSR14_TBCN, 1);
317 rt2x00pci_register_write(rt2x00dev, CSR14, reg); 315 rt2x00pci_register_write(rt2x00dev, CSR14, reg);
318 } 316 }
319 317
@@ -1337,8 +1335,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
1337 /* 1335 /*
1338 * Enable beaconing again. 1336 * Enable beaconing again.
1339 */ 1337 */
1340 rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
1341 rt2x00_set_field32(&reg, CSR14_TBCN, 1);
1342 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1); 1338 rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
1343 rt2x00pci_register_write(rt2x00dev, CSR14, reg); 1339 rt2x00pci_register_write(rt2x00dev, CSR14, reg);
1344} 1340}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 6b3b1de46792..157516e0aab7 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -478,9 +478,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev,
478 rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg); 478 rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
479 479
480 rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg); 480 rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
481 rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
482 rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, conf->sync); 481 rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, conf->sync);
483 rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
484 rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); 482 rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
485 } 483 }
486 484
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index f8ba01cbc6dd..4753fb1b0aaf 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -818,8 +818,6 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
818 /* 818 /*
819 * Enable beaconing again. 819 * Enable beaconing again.
820 */ 820 */
821 rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
822 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
823 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1); 821 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
824 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); 822 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
825 823
@@ -831,8 +829,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
831} 829}
832EXPORT_SYMBOL_GPL(rt2800_write_beacon); 830EXPORT_SYMBOL_GPL(rt2800_write_beacon);
833 831
834static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev, 832static inline void rt2800_clear_beacon_register(struct rt2x00_dev *rt2x00dev,
835 unsigned int beacon_base) 833 unsigned int beacon_base)
836{ 834{
837 int i; 835 int i;
838 836
@@ -845,6 +843,33 @@ static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,
845 rt2800_register_write(rt2x00dev, beacon_base + i, 0); 843 rt2800_register_write(rt2x00dev, beacon_base + i, 0);
846} 844}
847 845
846void rt2800_clear_beacon(struct queue_entry *entry)
847{
848 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
849 u32 reg;
850
851 /*
852 * Disable beaconing while we are reloading the beacon data,
853 * otherwise we might be sending out invalid data.
854 */
855 rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
856 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
857 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
858
859 /*
860 * Clear beacon.
861 */
862 rt2800_clear_beacon_register(rt2x00dev,
863 HW_BEACON_OFFSET(entry->entry_idx));
864
865 /*
866 * Enabled beaconing again.
867 */
868 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
869 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
870}
871EXPORT_SYMBOL_GPL(rt2800_clear_beacon);
872
848#ifdef CONFIG_RT2X00_LIB_DEBUGFS 873#ifdef CONFIG_RT2X00_LIB_DEBUGFS
849const struct rt2x00debug rt2800_rt2x00debug = { 874const struct rt2x00debug rt2800_rt2x00debug = {
850 .owner = THIS_MODULE, 875 .owner = THIS_MODULE,
@@ -1155,29 +1180,11 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
1155 1180
1156 if (flags & CONFIG_UPDATE_TYPE) { 1181 if (flags & CONFIG_UPDATE_TYPE) {
1157 /* 1182 /*
1158 * Clear current synchronisation setup.
1159 */
1160 rt2800_clear_beacon(rt2x00dev,
1161 HW_BEACON_OFFSET(intf->beacon->entry_idx));
1162 /*
1163 * Enable synchronisation. 1183 * Enable synchronisation.
1164 */ 1184 */
1165 rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg); 1185 rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
1166 rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
1167 rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync); 1186 rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
1168 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE,
1169 (conf->sync == TSF_SYNC_ADHOC ||
1170 conf->sync == TSF_SYNC_AP_NONE));
1171 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); 1187 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
1172
1173 /*
1174 * Enable pre tbtt interrupt for beaconing modes
1175 */
1176 rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
1177 rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER,
1178 (conf->sync == TSF_SYNC_AP_NONE));
1179 rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
1180
1181 } 1188 }
1182 1189
1183 if (flags & CONFIG_UPDATE_MAC) { 1190 if (flags & CONFIG_UPDATE_MAC) {
@@ -2187,14 +2194,14 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
2187 /* 2194 /*
2188 * Clear all beacons 2195 * Clear all beacons
2189 */ 2196 */
2190 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0); 2197 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE0);
2191 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1); 2198 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE1);
2192 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2); 2199 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE2);
2193 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3); 2200 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE3);
2194 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4); 2201 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE4);
2195 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5); 2202 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE5);
2196 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6); 2203 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE6);
2197 rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7); 2204 rt2800_clear_beacon_register(rt2x00dev, HW_BEACON_BASE7);
2198 2205
2199 if (rt2x00_is_usb(rt2x00dev)) { 2206 if (rt2x00_is_usb(rt2x00dev)) {
2200 rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg); 2207 rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 3efafb78ff77..0c92d86a36f4 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -156,6 +156,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
156void rt2800_txdone_entry(struct queue_entry *entry, u32 status); 156void rt2800_txdone_entry(struct queue_entry *entry, u32 status);
157 157
158void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); 158void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
159void rt2800_clear_beacon(struct queue_entry *entry);
159 160
160extern const struct rt2x00debug rt2800_rt2x00debug; 161extern const struct rt2x00debug rt2800_rt2x00debug;
161 162
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index bfc2fc5c1c22..54e37e08c114 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -205,6 +205,10 @@ static void rt2800pci_start_queue(struct data_queue *queue)
205 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1); 205 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
206 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1); 206 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
207 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); 207 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
208
209 rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
210 rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 1);
211 rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
208 break; 212 break;
209 default: 213 default:
210 break; 214 break;
@@ -250,6 +254,10 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
250 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0); 254 rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
251 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0); 255 rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
252 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); 256 rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
257
258 rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
259 rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
260 rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
253 break; 261 break;
254 default: 262 default:
255 break; 263 break;
@@ -974,6 +982,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
974 .write_tx_desc = rt2800pci_write_tx_desc, 982 .write_tx_desc = rt2800pci_write_tx_desc,
975 .write_tx_data = rt2800_write_tx_data, 983 .write_tx_data = rt2800_write_tx_data,
976 .write_beacon = rt2800_write_beacon, 984 .write_beacon = rt2800_write_beacon,
985 .clear_beacon = rt2800_clear_beacon,
977 .fill_rxdone = rt2800pci_fill_rxdone, 986 .fill_rxdone = rt2800pci_fill_rxdone,
978 .config_shared_key = rt2800_config_shared_key, 987 .config_shared_key = rt2800_config_shared_key,
979 .config_pairwise_key = rt2800_config_pairwise_key, 988 .config_pairwise_key = rt2800_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index b97a4a54ff4c..3ebe473f8551 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -633,6 +633,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
633 .write_tx_desc = rt2800usb_write_tx_desc, 633 .write_tx_desc = rt2800usb_write_tx_desc,
634 .write_tx_data = rt2800usb_write_tx_data, 634 .write_tx_data = rt2800usb_write_tx_data,
635 .write_beacon = rt2800_write_beacon, 635 .write_beacon = rt2800_write_beacon,
636 .clear_beacon = rt2800_clear_beacon,
636 .get_tx_data_len = rt2800usb_get_tx_data_len, 637 .get_tx_data_len = rt2800usb_get_tx_data_len,
637 .fill_rxdone = rt2800usb_fill_rxdone, 638 .fill_rxdone = rt2800usb_fill_rxdone,
638 .config_shared_key = rt2800_config_shared_key, 639 .config_shared_key = rt2800_config_shared_key,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 84aaf393da43..985982bb65e2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -368,6 +368,7 @@ struct rt2x00_intf {
368 * dedicated beacon entry. 368 * dedicated beacon entry.
369 */ 369 */
370 struct queue_entry *beacon; 370 struct queue_entry *beacon;
371 bool enable_beacon;
371 372
372 /* 373 /*
373 * Actions that needed rescheduling. 374 * Actions that needed rescheduling.
@@ -573,6 +574,7 @@ struct rt2x00lib_ops {
573 struct txentry_desc *txdesc); 574 struct txentry_desc *txdesc);
574 void (*write_beacon) (struct queue_entry *entry, 575 void (*write_beacon) (struct queue_entry *entry,
575 struct txentry_desc *txdesc); 576 struct txentry_desc *txdesc);
577 void (*clear_beacon) (struct queue_entry *entry);
576 int (*get_tx_data_len) (struct queue_entry *entry); 578 int (*get_tx_data_len) (struct queue_entry *entry);
577 579
578 /* 580 /*
@@ -788,10 +790,12 @@ struct rt2x00_dev {
788 * - Open ap interface count. 790 * - Open ap interface count.
789 * - Open sta interface count. 791 * - Open sta interface count.
790 * - Association count. 792 * - Association count.
793 * - Beaconing enabled count.
791 */ 794 */
792 unsigned int intf_ap_count; 795 unsigned int intf_ap_count;
793 unsigned int intf_sta_count; 796 unsigned int intf_sta_count;
794 unsigned int intf_associated; 797 unsigned int intf_associated;
798 unsigned int intf_beaconing;
795 799
796 /* 800 /*
797 * Link quality 801 * Link quality
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 31b7db05abd9..2c6503878059 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -121,7 +121,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac,
121 return; 121 return;
122 122
123 if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags)) 123 if (test_and_clear_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags))
124 rt2x00queue_update_beacon(rt2x00dev, vif, true); 124 rt2x00queue_update_beacon(rt2x00dev, vif);
125} 125}
126 126
127static void rt2x00lib_intf_scheduled(struct work_struct *work) 127static void rt2x00lib_intf_scheduled(struct work_struct *work)
@@ -174,7 +174,7 @@ static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac,
174 vif->type != NL80211_IFTYPE_WDS) 174 vif->type != NL80211_IFTYPE_WDS)
175 return; 175 return;
176 176
177 rt2x00queue_update_beacon(rt2x00dev, vif, true); 177 rt2x00queue_update_beacon(rt2x00dev, vif);
178} 178}
179 179
180void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) 180void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index a105c500627b..6c6a8f15870e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -160,11 +160,17 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
160 * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware 160 * rt2x00queue_update_beacon - Send new beacon from mac80211 to hardware
161 * @rt2x00dev: Pointer to &struct rt2x00_dev. 161 * @rt2x00dev: Pointer to &struct rt2x00_dev.
162 * @vif: Interface for which the beacon should be updated. 162 * @vif: Interface for which the beacon should be updated.
163 * @enable_beacon: Enable beaconing
164 */ 163 */
165int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, 164int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
166 struct ieee80211_vif *vif, 165 struct ieee80211_vif *vif);
167 const bool enable_beacon); 166
167/**
168 * rt2x00queue_clear_beacon - Clear beacon in hardware
169 * @rt2x00dev: Pointer to &struct rt2x00_dev.
170 * @vif: Interface for which the beacon should be updated.
171 */
172int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
173 struct ieee80211_vif *vif);
168 174
169/** 175/**
170 * rt2x00queue_index_inc - Index incrementation function 176 * rt2x00queue_index_inc - Index incrementation function
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index f3da051df39e..7d3316724bb4 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -619,9 +619,44 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
619 /* 619 /*
620 * Update the beacon. 620 * Update the beacon.
621 */ 621 */
622 if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) 622 if (changes & BSS_CHANGED_BEACON)
623 rt2x00queue_update_beacon(rt2x00dev, vif, 623 rt2x00queue_update_beacon(rt2x00dev, vif);
624 bss_conf->enable_beacon); 624
625 /*
626 * Start/stop beaconing.
627 */
628 if (changes & BSS_CHANGED_BEACON_ENABLED) {
629 if (!bss_conf->enable_beacon && intf->enable_beacon) {
630 rt2x00queue_clear_beacon(rt2x00dev, vif);
631 rt2x00dev->intf_beaconing--;
632 intf->enable_beacon = false;
633
634 if (rt2x00dev->intf_beaconing == 0) {
635 /*
636 * Last beaconing interface disabled
637 * -> stop beacon queue.
638 */
639 mutex_lock(&intf->beacon_skb_mutex);
640 rt2x00queue_stop_queue(rt2x00dev->bcn);
641 mutex_unlock(&intf->beacon_skb_mutex);
642 }
643
644
645 } else if (bss_conf->enable_beacon && !intf->enable_beacon) {
646 rt2x00dev->intf_beaconing++;
647 intf->enable_beacon = true;
648
649 if (rt2x00dev->intf_beaconing == 1) {
650 /*
651 * First beaconing interface enabled
652 * -> start beacon queue.
653 */
654 mutex_lock(&intf->beacon_skb_mutex);
655 rt2x00queue_start_queue(rt2x00dev->bcn);
656 mutex_unlock(&intf->beacon_skb_mutex);
657 }
658 }
659 }
625 660
626 /* 661 /*
627 * When the association status has changed we must reset the link 662 * When the association status has changed we must reset the link
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index ca82b3a91697..24bcdb47a465 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -566,9 +566,35 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
566 return 0; 566 return 0;
567} 567}
568 568
569int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
570 struct ieee80211_vif *vif)
571{
572 struct rt2x00_intf *intf = vif_to_intf(vif);
573
574 if (unlikely(!intf->beacon))
575 return -ENOBUFS;
576
577 mutex_lock(&intf->beacon_skb_mutex);
578
579 /*
580 * Clean up the beacon skb.
581 */
582 rt2x00queue_free_skb(intf->beacon);
583
584 /*
585 * Clear beacon (single bssid devices don't need to clear the beacon
586 * since the beacon queue will get stopped anyway).
587 */
588 if (rt2x00dev->ops->lib->clear_beacon)
589 rt2x00dev->ops->lib->clear_beacon(intf->beacon);
590
591 mutex_unlock(&intf->beacon_skb_mutex);
592
593 return 0;
594}
595
569int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, 596int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
570 struct ieee80211_vif *vif, 597 struct ieee80211_vif *vif)
571 const bool enable_beacon)
572{ 598{
573 struct rt2x00_intf *intf = vif_to_intf(vif); 599 struct rt2x00_intf *intf = vif_to_intf(vif);
574 struct skb_frame_desc *skbdesc; 600 struct skb_frame_desc *skbdesc;
@@ -584,12 +610,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
584 */ 610 */
585 rt2x00queue_free_skb(intf->beacon); 611 rt2x00queue_free_skb(intf->beacon);
586 612
587 if (!enable_beacon) {
588 rt2x00queue_stop_queue(intf->beacon->queue);
589 mutex_unlock(&intf->beacon_skb_mutex);
590 return 0;
591 }
592
593 intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif); 613 intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif);
594 if (!intf->beacon->skb) { 614 if (!intf->beacon->skb) {
595 mutex_unlock(&intf->beacon_skb_mutex); 615 mutex_unlock(&intf->beacon_skb_mutex);
@@ -611,7 +631,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
611 skbdesc->entry = intf->beacon; 631 skbdesc->entry = intf->beacon;
612 632
613 /* 633 /*
614 * Send beacon to hardware and enable beacon genaration.. 634 * Send beacon to hardware.
615 */ 635 */
616 rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc); 636 rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
617 637
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 8de44dd401e0..f14cc452eb0c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -551,26 +551,14 @@ static void rt61pci_config_intf(struct rt2x00_dev *rt2x00dev,
551 struct rt2x00intf_conf *conf, 551 struct rt2x00intf_conf *conf,
552 const unsigned int flags) 552 const unsigned int flags)
553{ 553{
554 unsigned int beacon_base;
555 u32 reg; 554 u32 reg;
556 555
557 if (flags & CONFIG_UPDATE_TYPE) { 556 if (flags & CONFIG_UPDATE_TYPE) {
558 /* 557 /*
559 * Clear current synchronisation setup.
560 * For the Beacon base registers, we only need to clear
561 * the first byte since that byte contains the VALID and OWNER
562 * bits which (when set to 0) will invalidate the entire beacon.
563 */
564 beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
565 rt2x00pci_register_write(rt2x00dev, beacon_base, 0);
566
567 /*
568 * Enable synchronisation. 558 * Enable synchronisation.
569 */ 559 */
570 rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg); 560 rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
571 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
572 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync); 561 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
573 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
574 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); 562 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
575 } 563 }
576 564
@@ -2002,8 +1990,6 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
2002 */ 1990 */
2003 rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); 1991 rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
2004 1992
2005 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
2006 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
2007 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1); 1993 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
2008 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); 1994 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
2009 1995
@@ -2014,6 +2000,32 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
2014 entry->skb = NULL; 2000 entry->skb = NULL;
2015} 2001}
2016 2002
2003static void rt61pci_clear_beacon(struct queue_entry *entry)
2004{
2005 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
2006 u32 reg;
2007
2008 /*
2009 * Disable beaconing while we are reloading the beacon data,
2010 * otherwise we might be sending out invalid data.
2011 */
2012 rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
2013 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
2014 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
2015
2016 /*
2017 * Clear beacon.
2018 */
2019 rt2x00pci_register_write(rt2x00dev,
2020 HW_BEACON_OFFSET(entry->entry_idx), 0);
2021
2022 /*
2023 * Enable beaconing again.
2024 */
2025 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
2026 rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
2027}
2028
2017/* 2029/*
2018 * RX control handlers 2030 * RX control handlers
2019 */ 2031 */
@@ -2903,6 +2915,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
2903 .stop_queue = rt61pci_stop_queue, 2915 .stop_queue = rt61pci_stop_queue,
2904 .write_tx_desc = rt61pci_write_tx_desc, 2916 .write_tx_desc = rt61pci_write_tx_desc,
2905 .write_beacon = rt61pci_write_beacon, 2917 .write_beacon = rt61pci_write_beacon,
2918 .clear_beacon = rt61pci_clear_beacon,
2906 .fill_rxdone = rt61pci_fill_rxdone, 2919 .fill_rxdone = rt61pci_fill_rxdone,
2907 .config_shared_key = rt61pci_config_shared_key, 2920 .config_shared_key = rt61pci_config_shared_key,
2908 .config_pairwise_key = rt61pci_config_pairwise_key, 2921 .config_pairwise_key = rt61pci_config_pairwise_key,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 029be3c6c030..330353ec5c96 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -502,26 +502,14 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev,
502 struct rt2x00intf_conf *conf, 502 struct rt2x00intf_conf *conf,
503 const unsigned int flags) 503 const unsigned int flags)
504{ 504{
505 unsigned int beacon_base;
506 u32 reg; 505 u32 reg;
507 506
508 if (flags & CONFIG_UPDATE_TYPE) { 507 if (flags & CONFIG_UPDATE_TYPE) {
509 /* 508 /*
510 * Clear current synchronisation setup.
511 * For the Beacon base registers we only need to clear
512 * the first byte since that byte contains the VALID and OWNER
513 * bits which (when set to 0) will invalidate the entire beacon.
514 */
515 beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);
516 rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
517
518 /*
519 * Enable synchronisation. 509 * Enable synchronisation.
520 */ 510 */
521 rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg); 511 rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
522 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
523 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync); 512 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, conf->sync);
524 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
525 rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); 513 rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
526 } 514 }
527 515
@@ -1590,8 +1578,6 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
1590 */ 1578 */
1591 rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); 1579 rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
1592 1580
1593 rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
1594 rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
1595 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1); 1581 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
1596 rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); 1582 rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
1597 1583
@@ -1602,6 +1588,33 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
1602 entry->skb = NULL; 1588 entry->skb = NULL;
1603} 1589}
1604 1590
1591static void rt73usb_clear_beacon(struct queue_entry *entry)
1592{
1593 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
1594 unsigned int beacon_base;
1595 u32 reg;
1596
1597 /*
1598 * Disable beaconing while we are reloading the beacon data,
1599 * otherwise we might be sending out invalid data.
1600 */
1601 rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
1602 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
1603 rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
1604
1605 /*
1606 * Clear beacon.
1607 */
1608 beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
1609 rt2x00usb_register_write(rt2x00dev, beacon_base, 0);
1610
1611 /*
1612 * Enable beaconing again.
1613 */
1614 rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
1615 rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
1616}
1617
1605static int rt73usb_get_tx_data_len(struct queue_entry *entry) 1618static int rt73usb_get_tx_data_len(struct queue_entry *entry)
1606{ 1619{
1607 int length; 1620 int length;
@@ -2313,6 +2326,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
2313 .flush_queue = rt2x00usb_flush_queue, 2326 .flush_queue = rt2x00usb_flush_queue,
2314 .write_tx_desc = rt73usb_write_tx_desc, 2327 .write_tx_desc = rt73usb_write_tx_desc,
2315 .write_beacon = rt73usb_write_beacon, 2328 .write_beacon = rt73usb_write_beacon,
2329 .clear_beacon = rt73usb_clear_beacon,
2316 .get_tx_data_len = rt73usb_get_tx_data_len, 2330 .get_tx_data_len = rt73usb_get_tx_data_len,
2317 .fill_rxdone = rt73usb_fill_rxdone, 2331 .fill_rxdone = rt73usb_fill_rxdone,
2318 .config_shared_key = rt73usb_config_shared_key, 2332 .config_shared_key = rt73usb_config_shared_key,