307-ath9k-Set-ATH_OP_HW_RESET-before-HW-reset.patch 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. From: Sujith Manoharan <[email protected]>
  2. Date: Fri, 17 Oct 2014 07:40:12 +0530
  3. Subject: [PATCH] ath9k: Set ATH_OP_HW_RESET before HW reset
  4. When a HW reset is done, the interrupt tasklet is
  5. disabled before ISRs are disabled in the HW. This
  6. allows a small window where the HW can still generate
  7. interrupts. Since the tasklet is disabled and not killed,
  8. it is not scheduled but deferred for execution at a later
  9. time.
  10. This happens because ATH_OP_HW_RESET is not set when ath_reset()
  11. is called. When the hw_reset_work workqueue is used, this
  12. problem doesn't arise because ATH_OP_HW_RESET is set
  13. and the ISR bails out.
  14. Set ATH_OP_HW_RESET properly in ath_reset() to avoid
  15. this race - all the ath_reset_internal() callers have
  16. been converted to use ath_reset() in the previous patch.
  17. Signed-off-by: Sujith Manoharan <[email protected]>
  18. ---
  19. --- a/drivers/net/wireless/ath/ath9k/main.c
  20. +++ b/drivers/net/wireless/ath/ath9k/main.c
  21. @@ -598,10 +598,17 @@ chip_reset:
  22. #undef SCHED_INTR
  23. }
  24. +/*
  25. + * This function is called when a HW reset cannot be deferred
  26. + * and has to be immediate.
  27. + */
  28. int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
  29. {
  30. + struct ath_common *common = ath9k_hw_common(sc->sc_ah);
  31. int r;
  32. + set_bit(ATH_OP_HW_RESET, &common->op_flags);
  33. +
  34. ath9k_ps_wakeup(sc);
  35. r = ath_reset_internal(sc, hchan);
  36. ath9k_ps_restore(sc);
  37. @@ -609,6 +616,11 @@ int ath_reset(struct ath_softc *sc, stru
  38. return r;
  39. }
  40. +/*
  41. + * When a HW reset can be deferred, it is added to the
  42. + * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
  43. + * queueing.
  44. + */
  45. void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
  46. {
  47. struct ath_common *common = ath9k_hw_common(sc->sc_ah);