| 1 | --- a/drivers/net/wireless/ath/ath9k/ath9k.h |
| 2 | +++ b/drivers/net/wireless/ath/ath9k/ath9k.h |
| 3 | @@ -309,7 +309,6 @@ struct ath_rx { |
| 4 | u8 rxotherant; |
| 5 | u32 *rxlink; |
| 6 | unsigned int rxfilter; |
| 7 | - spinlock_t rxflushlock; |
| 8 | spinlock_t rxbuflock; |
| 9 | struct list_head rxbuf; |
| 10 | struct ath_descdma rxdma; |
| 11 | @@ -600,9 +599,9 @@ struct ath_softc { |
| 12 | struct ath_hw *sc_ah; |
| 13 | void __iomem *mem; |
| 14 | int irq; |
| 15 | - spinlock_t sc_resetlock; |
| 16 | spinlock_t sc_serial_rw; |
| 17 | spinlock_t sc_pm_lock; |
| 18 | + spinlock_t sc_pcu_lock; |
| 19 | struct mutex mutex; |
| 20 | struct work_struct paprd_work; |
| 21 | struct work_struct hw_check_work; |
| 22 | --- a/drivers/net/wireless/ath/ath9k/main.c |
| 23 | +++ b/drivers/net/wireless/ath/ath9k/main.c |
| 24 | @@ -228,6 +228,8 @@ int ath_set_channel(struct ath_softc *sc |
| 25 | |
| 26 | ath9k_ps_wakeup(sc); |
| 27 | |
| 28 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 29 | + |
| 30 | /* |
| 31 | * This is only performed if the channel settings have |
| 32 | * actually changed. |
| 33 | @@ -239,6 +241,7 @@ int ath_set_channel(struct ath_softc *sc |
| 34 | */ |
| 35 | ath9k_hw_disable_interrupts(ah); |
| 36 | ath_drain_all_txq(sc, false); |
| 37 | + |
| 38 | stopped = ath_stoprecv(sc); |
| 39 | |
| 40 | /* XXX: do not flush receive queue here. We don't want |
| 41 | @@ -257,18 +260,14 @@ int ath_set_channel(struct ath_softc *sc |
| 42 | channel->center_freq, conf_is_ht40(conf), |
| 43 | fastcc); |
| 44 | |
| 45 | - spin_lock_bh(&sc->sc_resetlock); |
| 46 | - |
| 47 | r = ath9k_hw_reset(ah, hchan, caldata, fastcc); |
| 48 | if (r) { |
| 49 | ath_print(common, ATH_DBG_FATAL, |
| 50 | "Unable to reset channel (%u MHz), " |
| 51 | "reset status %d\n", |
| 52 | channel->center_freq, r); |
| 53 | - spin_unlock_bh(&sc->sc_resetlock); |
| 54 | goto ps_restore; |
| 55 | } |
| 56 | - spin_unlock_bh(&sc->sc_resetlock); |
| 57 | |
| 58 | if (ath_startrecv(sc) != 0) { |
| 59 | ath_print(common, ATH_DBG_FATAL, |
| 60 | @@ -287,6 +286,8 @@ int ath_set_channel(struct ath_softc *sc |
| 61 | } |
| 62 | |
| 63 | ps_restore: |
| 64 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 65 | + |
| 66 | ath9k_ps_restore(sc); |
| 67 | return r; |
| 68 | } |
| 69 | @@ -600,6 +601,8 @@ void ath9k_tasklet(unsigned long data) |
| 70 | return; |
| 71 | } |
| 72 | |
| 73 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 74 | + |
| 75 | if (!ath9k_hw_check_alive(ah)) |
| 76 | ieee80211_queue_work(sc->hw, &sc->hw_check_work); |
| 77 | |
| 78 | @@ -610,15 +613,12 @@ void ath9k_tasklet(unsigned long data) |
| 79 | rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); |
| 80 | |
| 81 | if (status & rxmask) { |
| 82 | - spin_lock_bh(&sc->rx.rxflushlock); |
| 83 | - |
| 84 | /* Check for high priority Rx first */ |
| 85 | if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && |
| 86 | (status & ATH9K_INT_RXHP)) |
| 87 | ath_rx_tasklet(sc, 0, true); |
| 88 | |
| 89 | ath_rx_tasklet(sc, 0, false); |
| 90 | - spin_unlock_bh(&sc->rx.rxflushlock); |
| 91 | } |
| 92 | |
| 93 | if (status & ATH9K_INT_TX) { |
| 94 | @@ -644,6 +644,8 @@ void ath9k_tasklet(unsigned long data) |
| 95 | |
| 96 | /* re-enable hardware interrupt */ |
| 97 | ath9k_hw_enable_interrupts(ah); |
| 98 | + |
| 99 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 100 | ath9k_ps_restore(sc); |
| 101 | } |
| 102 | |
| 103 | @@ -871,12 +873,13 @@ void ath_radio_enable(struct ath_softc * |
| 104 | int r; |
| 105 | |
| 106 | ath9k_ps_wakeup(sc); |
| 107 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 108 | + |
| 109 | ath9k_hw_configpcipowersave(ah, 0, 0); |
| 110 | |
| 111 | if (!ah->curchan) |
| 112 | ah->curchan = ath_get_curchannel(sc, sc->hw); |
| 113 | |
| 114 | - spin_lock_bh(&sc->sc_resetlock); |
| 115 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
| 116 | if (r) { |
| 117 | ath_print(common, ATH_DBG_FATAL, |
| 118 | @@ -884,15 +887,14 @@ void ath_radio_enable(struct ath_softc * |
| 119 | "reset status %d\n", |
| 120 | channel->center_freq, r); |
| 121 | } |
| 122 | - spin_unlock_bh(&sc->sc_resetlock); |
| 123 | |
| 124 | ath_update_txpow(sc); |
| 125 | if (ath_startrecv(sc) != 0) { |
| 126 | ath_print(common, ATH_DBG_FATAL, |
| 127 | "Unable to restart recv logic\n"); |
| 128 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 129 | return; |
| 130 | } |
| 131 | - |
| 132 | if (sc->sc_flags & SC_OP_BEACONS) |
| 133 | ath_beacon_config(sc, NULL); /* restart beacons */ |
| 134 | |
| 135 | @@ -905,6 +907,8 @@ void ath_radio_enable(struct ath_softc * |
| 136 | ath9k_hw_set_gpio(ah, ah->led_pin, 0); |
| 137 | |
| 138 | ieee80211_wake_queues(hw); |
| 139 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 140 | + |
| 141 | ath9k_ps_restore(sc); |
| 142 | } |
| 143 | |
| 144 | @@ -915,6 +919,8 @@ void ath_radio_disable(struct ath_softc |
| 145 | int r; |
| 146 | |
| 147 | ath9k_ps_wakeup(sc); |
| 148 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 149 | + |
| 150 | ieee80211_stop_queues(hw); |
| 151 | |
| 152 | /* |
| 153 | @@ -930,13 +936,13 @@ void ath_radio_disable(struct ath_softc |
| 154 | ath9k_hw_disable_interrupts(ah); |
| 155 | |
| 156 | ath_drain_all_txq(sc, false); /* clear pending tx frames */ |
| 157 | + |
| 158 | ath_stoprecv(sc); /* turn off frame recv */ |
| 159 | ath_flushrecv(sc); /* flush recv queue */ |
| 160 | |
| 161 | if (!ah->curchan) |
| 162 | ah->curchan = ath_get_curchannel(sc, hw); |
| 163 | |
| 164 | - spin_lock_bh(&sc->sc_resetlock); |
| 165 | r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
| 166 | if (r) { |
| 167 | ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, |
| 168 | @@ -944,11 +950,14 @@ void ath_radio_disable(struct ath_softc |
| 169 | "reset status %d\n", |
| 170 | channel->center_freq, r); |
| 171 | } |
| 172 | - spin_unlock_bh(&sc->sc_resetlock); |
| 173 | |
| 174 | ath9k_hw_phy_disable(ah); |
| 175 | + |
| 176 | ath9k_hw_configpcipowersave(ah, 1, 1); |
| 177 | + |
| 178 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 179 | ath9k_ps_restore(sc); |
| 180 | + |
| 181 | ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); |
| 182 | } |
| 183 | |
| 184 | @@ -962,19 +971,20 @@ int ath_reset(struct ath_softc *sc, bool |
| 185 | /* Stop ANI */ |
| 186 | del_timer_sync(&common->ani.timer); |
| 187 | |
| 188 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 189 | + |
| 190 | ieee80211_stop_queues(hw); |
| 191 | |
| 192 | ath9k_hw_disable_interrupts(ah); |
| 193 | ath_drain_all_txq(sc, retry_tx); |
| 194 | + |
| 195 | ath_stoprecv(sc); |
| 196 | ath_flushrecv(sc); |
| 197 | |
| 198 | - spin_lock_bh(&sc->sc_resetlock); |
| 199 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); |
| 200 | if (r) |
| 201 | ath_print(common, ATH_DBG_FATAL, |
| 202 | "Unable to reset hardware; reset status %d\n", r); |
| 203 | - spin_unlock_bh(&sc->sc_resetlock); |
| 204 | |
| 205 | if (ath_startrecv(sc) != 0) |
| 206 | ath_print(common, ATH_DBG_FATAL, |
| 207 | @@ -1004,6 +1014,7 @@ int ath_reset(struct ath_softc *sc, bool |
| 208 | } |
| 209 | |
| 210 | ieee80211_wake_queues(hw); |
| 211 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 212 | |
| 213 | /* Start ANI */ |
| 214 | ath_start_ani(common); |
| 215 | @@ -1142,17 +1153,16 @@ static int ath9k_start(struct ieee80211_ |
| 216 | * be followed by initialization of the appropriate bits |
| 217 | * and then setup of the interrupt mask. |
| 218 | */ |
| 219 | - spin_lock_bh(&sc->sc_resetlock); |
| 220 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 221 | r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); |
| 222 | if (r) { |
| 223 | ath_print(common, ATH_DBG_FATAL, |
| 224 | "Unable to reset hardware; reset status %d " |
| 225 | "(freq %u MHz)\n", r, |
| 226 | curchan->center_freq); |
| 227 | - spin_unlock_bh(&sc->sc_resetlock); |
| 228 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 229 | goto mutex_unlock; |
| 230 | } |
| 231 | - spin_unlock_bh(&sc->sc_resetlock); |
| 232 | |
| 233 | /* |
| 234 | * This is needed only to setup initial state |
| 235 | @@ -1171,8 +1181,10 @@ static int ath9k_start(struct ieee80211_ |
| 236 | ath_print(common, ATH_DBG_FATAL, |
| 237 | "Unable to start recv logic\n"); |
| 238 | r = -EIO; |
| 239 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 240 | goto mutex_unlock; |
| 241 | } |
| 242 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 243 | |
| 244 | /* Setup our intr mask. */ |
| 245 | ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | |
| 246 | @@ -1367,6 +1379,8 @@ static void ath9k_stop(struct ieee80211_ |
| 247 | ath9k_btcoex_timer_pause(sc); |
| 248 | } |
| 249 | |
| 250 | + spin_lock_bh(&sc->sc_pcu_lock); |
| 251 | + |
| 252 | /* make sure h/w will not generate any interrupt |
| 253 | * before setting the invalid flag. */ |
| 254 | ath9k_hw_disable_interrupts(ah); |
| 255 | @@ -1381,6 +1395,9 @@ static void ath9k_stop(struct ieee80211_ |
| 256 | /* disable HAL and put h/w to sleep */ |
| 257 | ath9k_hw_disable(ah); |
| 258 | ath9k_hw_configpcipowersave(ah, 1, 1); |
| 259 | + |
| 260 | + spin_unlock_bh(&sc->sc_pcu_lock); |
| 261 | + |
| 262 | ath9k_ps_restore(sc); |
| 263 | |
| 264 | /* Finally, put the chip in FULL SLEEP mode */ |
| 265 | --- a/drivers/net/wireless/ath/ath9k/recv.c |
| 266 | +++ b/drivers/net/wireless/ath/ath9k/recv.c |
| 267 | @@ -297,19 +297,17 @@ static void ath_edma_start_recv(struct a |
| 268 | ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, |
| 269 | sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); |
| 270 | |
| 271 | - spin_unlock_bh(&sc->rx.rxbuflock); |
| 272 | - |
| 273 | ath_opmode_init(sc); |
| 274 | |
| 275 | ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); |
| 276 | + |
| 277 | + spin_unlock_bh(&sc->rx.rxbuflock); |
| 278 | } |
| 279 | |
| 280 | static void ath_edma_stop_recv(struct ath_softc *sc) |
| 281 | { |
| 282 | - spin_lock_bh(&sc->rx.rxbuflock); |
| 283 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); |
| 284 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); |
| 285 | - spin_unlock_bh(&sc->rx.rxbuflock); |
| 286 | } |
| 287 | |
| 288 | int ath_rx_init(struct ath_softc *sc, int nbufs) |
| 289 | @@ -319,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, in |
| 290 | struct ath_buf *bf; |
| 291 | int error = 0; |
| 292 | |
| 293 | - spin_lock_init(&sc->rx.rxflushlock); |
| 294 | + spin_lock_init(&sc->sc_pcu_lock); |
| 295 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
| 296 | spin_lock_init(&sc->rx.rxbuflock); |
| 297 | |
| 298 | @@ -506,9 +504,9 @@ int ath_startrecv(struct ath_softc *sc) |
| 299 | ath9k_hw_rxena(ah); |
| 300 | |
| 301 | start_recv: |
| 302 | - spin_unlock_bh(&sc->rx.rxbuflock); |
| 303 | ath_opmode_init(sc); |
| 304 | ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); |
| 305 | + spin_unlock_bh(&sc->rx.rxbuflock); |
| 306 | |
| 307 | return 0; |
| 308 | } |
| 309 | @@ -518,6 +516,7 @@ bool ath_stoprecv(struct ath_softc *sc) |
| 310 | struct ath_hw *ah = sc->sc_ah; |
| 311 | bool stopped; |
| 312 | |
| 313 | + spin_lock_bh(&sc->rx.rxbuflock); |
| 314 | ath9k_hw_stoppcurecv(ah); |
| 315 | ath9k_hw_setrxfilter(ah, 0); |
| 316 | stopped = ath9k_hw_stopdmarecv(ah); |
| 317 | @@ -526,19 +525,18 @@ bool ath_stoprecv(struct ath_softc *sc) |
| 318 | ath_edma_stop_recv(sc); |
| 319 | else |
| 320 | sc->rx.rxlink = NULL; |
| 321 | + spin_unlock_bh(&sc->rx.rxbuflock); |
| 322 | |
| 323 | return stopped; |
| 324 | } |
| 325 | |
| 326 | void ath_flushrecv(struct ath_softc *sc) |
| 327 | { |
| 328 | - spin_lock_bh(&sc->rx.rxflushlock); |
| 329 | sc->sc_flags |= SC_OP_RXFLUSH; |
| 330 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| 331 | ath_rx_tasklet(sc, 1, true); |
| 332 | ath_rx_tasklet(sc, 1, false); |
| 333 | sc->sc_flags &= ~SC_OP_RXFLUSH; |
| 334 | - spin_unlock_bh(&sc->rx.rxflushlock); |
| 335 | } |
| 336 | |
| 337 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |
| 338 | --- a/drivers/net/wireless/ath/ath9k/init.c |
| 339 | +++ b/drivers/net/wireless/ath/ath9k/init.c |
| 340 | @@ -588,7 +588,6 @@ static int ath9k_init_softc(u16 devid, s |
| 341 | spin_lock_init(&common->cc_lock); |
| 342 | |
| 343 | spin_lock_init(&sc->wiphy_lock); |
| 344 | - spin_lock_init(&sc->sc_resetlock); |
| 345 | spin_lock_init(&sc->sc_serial_rw); |
| 346 | spin_lock_init(&sc->sc_pm_lock); |
| 347 | mutex_init(&sc->mutex); |
| 348 | --- a/drivers/net/wireless/ath/ath9k/xmit.c |
| 349 | +++ b/drivers/net/wireless/ath/ath9k/xmit.c |
| 350 | @@ -1142,13 +1142,11 @@ void ath_drain_all_txq(struct ath_softc |
| 351 | ath_print(common, ATH_DBG_FATAL, |
| 352 | "Failed to stop TX DMA. Resetting hardware!\n"); |
| 353 | |
| 354 | - spin_lock_bh(&sc->sc_resetlock); |
| 355 | r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); |
| 356 | if (r) |
| 357 | ath_print(common, ATH_DBG_FATAL, |
| 358 | "Unable to reset hardware; reset status %d\n", |
| 359 | r); |
| 360 | - spin_unlock_bh(&sc->sc_resetlock); |
| 361 | } |
| 362 | |
| 363 | for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { |
| 364 | |