]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/ath/ath9k/hw.c
Merge branch 'master' into for-davem
[karo-tx-linux.git] / drivers / net / wireless / ath / ath9k / hw.c
index 1dc1b485c3c38b958f6e5bf561a48416b9d3fe4f..5a29048db3b192c496d3a5507961fe2ed7e5be94 100644 (file)
  */
 
 #include <linux/io.h>
+#include <linux/slab.h>
 #include <asm/unaligned.h>
 
 #include "hw.h"
 #include "hw-ops.h"
 #include "rc.h"
+#include "ar9003_mac.h"
 
 #define ATH9K_CLOCK_RATE_CCK           22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
@@ -273,6 +275,8 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
        if (AR_SREV_9100(ah))
                return;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
        REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
        REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
@@ -284,6 +288,9 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
        REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
 
        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* This should work for all families including legacy */
@@ -637,6 +644,8 @@ EXPORT_SYMBOL(ath9k_hw_init);
 
 static void ath9k_hw_init_qos(struct ath_hw *ah)
 {
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
        REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
 
@@ -650,6 +659,9 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
        REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
        REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
        REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_init_pll(struct ath_hw *ah,
@@ -701,6 +713,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
        if (opmode == NL80211_IFTYPE_AP)
                imr_reg |= AR_IMR_MIB;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_IMR, imr_reg);
        ah->imrs2_reg |= AR_IMR_S2_GTT;
        REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
@@ -711,6 +725,9 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
        }
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        if (AR_SREV_9300_20_OR_LATER(ah)) {
                REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
                REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0);
@@ -839,6 +856,8 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        u32 regval;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        /*
         * set AHB_MODE not to do cacheline prefetches
        */
@@ -853,6 +872,9 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
        regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
        REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        /*
         * Restore TX Trigger Level to its pre-reset value.
         * The initial value depends on whether aggregation is enabled, and is
@@ -861,6 +883,8 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
        if (!AR_SREV_9300_20_OR_LATER(ah))
                REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        /*
         * let mac dma writes be in 128 byte chunks
         */
@@ -895,6 +919,12 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
                REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
                          AR_PCU_TXBUF_CTRL_USABLE_SIZE);
        }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               ath9k_hw_reset_txstatus_ring(ah);
 }
 
 static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
@@ -952,6 +982,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                (void)REG_READ(ah, AR_RTC_DERIVED_CLK);
        }
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -980,6 +1012,10 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        }
 
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        udelay(50);
 
        REG_WRITE(ah, AR_RTC_RC, 0);
@@ -1000,6 +1036,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 
 static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 {
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1008,6 +1046,9 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 
        REG_WRITE(ah, AR_RTC_RESET, 0);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        if (!AR_SREV_9300_20_OR_LATER(ah))
                udelay(2);
 
@@ -1119,6 +1160,34 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        return true;
 }
 
+bool ath9k_hw_check_alive(struct ath_hw *ah)
+{
+       int count = 50;
+       u32 reg;
+
+       if (AR_SREV_9285_10_OR_LATER(ah))
+               return true;
+
+       do {
+               reg = REG_READ(ah, AR_OBS_BUS_1);
+
+               if ((reg & 0x7E7FFFEF) == 0x00702400)
+                       continue;
+
+               switch (reg & 0x7E000B00) {
+               case 0x1E000000:
+               case 0x52000B00:
+               case 0x18000B00:
+                       continue;
+               default:
+                       return true;
+               }
+       } while (count-- > 0);
+
+       return false;
+}
+EXPORT_SYMBOL(ath9k_hw_check_alive);
+
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                    bool bChannelChange)
 {
@@ -1133,6 +1202,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ah->txchainmask = common->tx_chainmask;
        ah->rxchainmask = common->rx_chainmask;
 
+       if (!ah->chip_fullsleep) {
+               ath9k_hw_abortpcurecv(ah);
+               if (!ath9k_hw_stopdmarecv(ah))
+                       ath_print(common, ATH_DBG_XMIT,
+                               "Failed to stop receive dma\n");
+       }
+
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
@@ -1227,6 +1303,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_spur_mitigate_freq(ah, chan);
        ah->eep_ops->set_board_values(ah, chan);
 
+       ath9k_hw_set_operating_mode(ah, ah->opmode);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
        REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
                  | macStaId1
@@ -1234,25 +1314,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                  | (ah->config.
                     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
                  | ah->sta_id1_defaults);
-       ath9k_hw_set_operating_mode(ah, ah->opmode);
-
        ath_hw_setbssidmask(common);
-
        REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
-
        ath9k_hw_write_associd(ah);
-
        REG_WRITE(ah, AR_ISR, ~0);
-
        REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        r = ath9k_hw_rf_set_freq(ah, chan);
        if (r)
                return r;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        for (i = 0; i < AR_NUM_DCU; i++)
                REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        ah->intr_txqs = 0;
        for (i = 0; i < ah->caps.total_queues; i++)
                ath9k_hw_resettxqueue(ah, i);
@@ -1265,12 +1347,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_init_global_settings(ah);
 
-       if (!AR_SREV_9300_20_OR_LATER(ah))
+       if (!AR_SREV_9300_20_OR_LATER(ah)) {
                ar9002_hw_enable_async_fifo(ah);
-
-       if (AR_SREV_9287_12_OR_LATER(ah)) {
-               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
-                               AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+               ar9002_hw_enable_wep_aggregation(ah);
        }
 
        REG_WRITE(ah, AR_STA_ID1,
@@ -1295,9 +1374,14 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (!ath9k_hw_init_cal(ah, chan))
                return -EIO;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        ath9k_hw_restore_chainmask(ah);
        REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        /*
         * For big endian systems turn on swapping for descriptors
         */
@@ -1327,6 +1411,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
 
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               ath9k_hw_loadnf(ah, curchan);
+               ath9k_hw_start_nfcal(ah);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_reset);
@@ -1756,6 +1845,8 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
 
        ah->beacon_interval = beacon_period;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        switch (ah->opmode) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_MONITOR:
@@ -1799,6 +1890,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
        REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
        REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        beacon_period &= ~ATH9K_BEACON_ENA;
        if (beacon_period & ATH9K_BEACON_RESET_TSF) {
                ath9k_hw_reset_tsf(ah);
@@ -1815,6 +1909,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
 
        REG_WRITE(ah, AR_BEACON_PERIOD,
@@ -1822,6 +1918,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
                  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        REG_RMW_FIELD(ah, AR_RSSI_THR,
                      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
 
@@ -1844,6 +1943,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
        ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_NEXT_DTIM,
                  TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
        REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
@@ -1863,6 +1964,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
        REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        REG_SET_BIT(ah, AR_TIMER_MODE,
                    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
                    AR_DTIM_TIMER_EN);
@@ -2082,11 +2186,12 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        if (AR_SREV_9300_20_OR_LATER(ah)) {
-               pCap->hw_caps |= ATH9K_HW_CAP_EDMA;
+               pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_LDPC;
                pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
                pCap->rx_lp_qdepth = ATH9K_HW_RX_LP_QDEPTH;
                pCap->rx_status_len = sizeof(struct ar9003_rxs);
                pCap->tx_desc_len = sizeof(struct ar9003_txc);
+               pCap->txs_len = sizeof(struct ar9003_txs);
        } else {
                pCap->tx_desc_len = sizeof(struct ath_desc);
        }
@@ -2319,6 +2424,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 {
        u32 phybits;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_RX_FILTER, bits);
 
        phybits = 0;
@@ -2334,6 +2441,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
        else
                REG_WRITE(ah, AR_RXCFG,
                          REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_setrxfilter);
 
@@ -2406,14 +2516,25 @@ void ath9k_hw_write_associd(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_write_associd);
 
+#define ATH9K_MAX_TSF_READ 10
+
 u64 ath9k_hw_gettsf64(struct ath_hw *ah)
 {
-       u64 tsf;
+       u32 tsf_lower, tsf_upper1, tsf_upper2;
+       int i;
+
+       tsf_upper1 = REG_READ(ah, AR_TSF_U32);
+       for (i = 0; i < ATH9K_MAX_TSF_READ; i++) {
+               tsf_lower = REG_READ(ah, AR_TSF_L32);
+               tsf_upper2 = REG_READ(ah, AR_TSF_U32);
+               if (tsf_upper2 == tsf_upper1)
+                       break;
+               tsf_upper1 = tsf_upper2;
+       }
 
-       tsf = REG_READ(ah, AR_TSF_U32);
-       tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
+       WARN_ON( i == ATH9K_MAX_TSF_READ );
 
-       return tsf;
+       return (((u64)tsf_upper1 << 32) | tsf_lower);
 }
 EXPORT_SYMBOL(ath9k_hw_gettsf64);