ath9k_hw: check GPM HW write pointer before chip reset
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>
Mon, 11 Jun 2012 06:49:32 +0000 (12:19 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 13 Jun 2012 18:35:53 +0000 (14:35 -0400)
Both "MAC Warm Reset" and "MCI Reset Rx" will reset GPM HW write_ptr.
We should check software cached write_ptr against HW write_ptr before
reset. Otherwise the pending DMA data will be lost.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_mci.h
drivers/net/wireless/ath/ath9k/hw.c

index 13907f6..cbeff9c 100644 (file)
@@ -893,6 +893,9 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
                udelay(100);
        }
 
+       /* Check pending GPM msg before MCI Reset Rx */
+       ar9003_mci_state(ah, MCI_STATE_CHECK_GPM_OFFSET, NULL);
+
        regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
        REG_WRITE(ah, AR_MCI_COMMAND2, regval);
        udelay(1);
@@ -1190,6 +1193,21 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
                value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
                mci->gpm_idx = value;
                break;
+       case MCI_STATE_CHECK_GPM_OFFSET:
+               /*
+                * This should only be called before "MAC Warm Reset" or
+                * "MCI Reset Rx".
+                */
+               value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+               if (mci->gpm_idx == value)
+                       break;
+               ath_dbg(common, MCI,
+                       "GPM cached write pointer mismatch %d %d\n",
+                       mci->gpm_idx, value);
+               mci->query_bt = true;
+               mci->need_flush_btinfo = true;
+               mci->gpm_idx = 0;
+               break;
        case MCI_STATE_NEXT_GPM_OFFSET:
        case MCI_STATE_LAST_GPM_OFFSET:
                /*
index 2a8c764..45624e1 100644 (file)
@@ -190,6 +190,7 @@ enum mci_bt_state {
 enum mci_state_type {
        MCI_STATE_ENABLE,
        MCI_STATE_INIT_GPM_OFFSET,
+       MCI_STATE_CHECK_GPM_OFFSET,
        MCI_STATE_NEXT_GPM_OFFSET,
        MCI_STATE_LAST_GPM_OFFSET,
        MCI_STATE_BT,
index 6d89333..8412128 100644 (file)
@@ -1348,6 +1348,9 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                }
        }
 
+       if (ath9k_hw_mci_is_enabled(ah))
+               ar9003_mci_state(ah, MCI_STATE_CHECK_GPM_OFFSET, NULL);
+
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
 
        REGWRITE_BUFFER_FLUSH(ah);