]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/ath9k/hw.c
ath9k: AR9280 PCI devices must serialize IO as well
[karo-tx-linux.git] / drivers / net / wireless / ath9k / hw.c
index 668865dce533ea8a894432945e0584a855a3ee19..c38a00bbce64664caa1042be4ee37da97e1f6c46 100644 (file)
@@ -37,7 +37,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type);
 static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
                              enum ath9k_ht_macmode macmode);
 static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
-                             struct ar5416_eeprom *pEepData,
+                             struct ar5416_eeprom_def *pEepData,
                              u32 reg, u32 value);
 static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
 static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan);
@@ -392,6 +392,8 @@ static const char *ath9k_hw_devname(u16 devid)
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
                return "Atheros 9280";
+       case AR9285_DEVID_PCIE:
+               return "Atheros 9285";
        }
 
        return NULL;
@@ -435,6 +437,25 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah)
        }
 
        ah->ah_config.intr_mitigation = 1;
+
+       /*
+        * We need this for PCI devices only (Cardbus, PCI, miniPCI)
+        * _and_ if on non-uniprocessor systems (Multiprocessor/HT).
+        * This means we use it for all AR5416 devices, and the few
+        * minor PCI AR9280 devices out there.
+        *
+        * Serialization is required because these devices do not handle
+        * well the case of two concurrent reads/writes due to the latency
+        * involved. During one read/write another read/write can be issued
+        * on another CPU while the previous read/write may still be working
+        * on our hardware, if we hit this case the hardware poops in a loop.
+        * We prevent this by serializing reads and writes.
+        *
+        * This issue is not present on PCI-Express devices or pre-AR5416
+        * devices (legacy, 802.11abg).
+        */
+       if (num_possible_cpus() > 1)
+               ah->ah_config.serialize_regmode = SER_REG_MODE_AUTO;
 }
 
 static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid,
@@ -640,10 +661,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        struct ath_hal_5416 *ahp;
        struct ath_hal *ah;
        int ecode;
-#ifndef CONFIG_SLOW_ANT_DIV
-       u32 i;
-       u32 j;
-#endif
+       u32 i, j;
 
        ahp = ath9k_hw_newstate(devid, sc, mem, status);
        if (ahp == NULL)
@@ -669,7 +687,8 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        }
 
        if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) {
-               if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) {
+               if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI ||
+                   (AR_SREV_9280(ah) && !ah->ah_isPciExpress)) {
                        ah->ah_config.serialize_regmode =
                                SER_REG_MODE_ON;
                } else {
@@ -685,7 +704,7 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) &&
            (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) &&
            (ah->ah_macVersion != AR_SREV_VERSION_9160) &&
-           (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) {
+           (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
                        "Mac Chip Rev 0x%02x.%x is not supported by "
                        "this driver\n", ah->ah_macVersion, ah->ah_macRev);
@@ -736,7 +755,38 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                "This Mac Chip Rev 0x%02x.%x is \n",
                ah->ah_macVersion, ah->ah_macRev);
 
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
+       if (AR_SREV_9285_12_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2,
+                              ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2,
+                              ARRAY_SIZE(ar9285Common_9285_1_2), 2);
+
+               if (ah->ah_config.pcie_clock_req) {
+                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+                       ar9285PciePhy_clkreq_off_L1_9285_1_2,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
+               } else {
+                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+                       ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
+                                 2);
+               }
+       } else if (AR_SREV_9285_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285,
+                              ARRAY_SIZE(ar9285Modes_9285), 6);
+               INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285,
+                              ARRAY_SIZE(ar9285Common_9285), 2);
+
+               if (ah->ah_config.pcie_clock_req) {
+                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+                       ar9285PciePhy_clkreq_off_L1_9285,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
+               } else {
+                       INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes,
+                       ar9285PciePhy_clkreq_always_on_L1_9285,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
+               }
+       } else if (AR_SREV_9280_20_OR_LATER(ah)) {
                INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2,
                               ARRAY_SIZE(ar9280Modes_9280_2), 6);
                INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2,
@@ -846,14 +896,13 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                goto bad;
 
        /* rxgain table */
-       if (AR_SREV_9280_20_OR_LATER(ah))
+       if (AR_SREV_9280_20(ah))
                ath9k_hw_init_rxgain_ini(ah);
 
        /* txgain table */
-       if (AR_SREV_9280_20_OR_LATER(ah))
+       if (AR_SREV_9280_20(ah))
                ath9k_hw_init_txgain_ini(ah);
 
-#ifndef CONFIG_SLOW_ANT_DIV
        if (ah->ah_devid == AR9280_DEVID_PCI) {
                for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) {
                        u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
@@ -862,12 +911,13 @@ static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                                u32 val = INI_RA(&ahp->ah_iniModes, i, j);
 
                                INI_RA(&ahp->ah_iniModes, i, j) =
-                                       ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom,
+                                       ath9k_hw_ini_fixup(ah,
+                                                          &ahp->ah_eeprom.def,
                                                           reg, val);
                        }
                }
        }
-#endif
+
        if (!ath9k_hw_fill_cap_info(ah)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
                        "failed ath9k_hw_fill_cap_info\n");
@@ -1020,8 +1070,6 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah)
                }
        case 0x1:
        case 0x2:
-               if (!AR_SREV_9280(ah))
-                       break;
        case 0x7:
                REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
                REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
@@ -1166,12 +1214,10 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
        case AR9160_DEVID_PCI:
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
+       case AR9285_DEVID_PCIE:
                ah = ath9k_hw_do_attach(devid, sc, mem, error);
                break;
        default:
-               DPRINTF(ah->ah_sc, ATH_DBG_ANY,
-                       "devid=0x%x not supported.\n", devid);
-               ah = NULL;
                *error = -ENXIO;
                break;
        }
@@ -1186,6 +1232,14 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
 static void ath9k_hw_override_ini(struct ath_hal *ah,
                                  struct ath9k_channel *chan)
 {
+       /*
+        * Set the RX_ABORT and RX_DIS and clear if off only after
+        * RXE is set for MAC. This prevents frames with corrupted
+        * descriptor status.
+        */
+       REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+
        if (!AR_SREV_5416_V20_OR_LATER(ah) ||
            AR_SREV_9280_10_OR_LATER(ah))
                return;
@@ -1193,8 +1247,8 @@ static void ath9k_hw_override_ini(struct ath_hal *ah,
        REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
 }
 
-static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
-                             struct ar5416_eeprom *pEepData,
+static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah,
+                             struct ar5416_eeprom_def *pEepData,
                              u32 reg, u32 value)
 {
        struct base_eep_header *pBase = &(pEepData->baseEepHeader);
@@ -1227,6 +1281,18 @@ static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
        return value;
 }
 
+static u32 ath9k_hw_ini_fixup(struct ath_hal *ah,
+                             struct ar5416_eeprom_def *pEepData,
+                             u32 reg, u32 value)
+{
+       struct ath_hal_5416 *ahp = AH5416(ah);
+
+       if (ahp->ah_eep_map == EEP_MAP_4KBITS)
+               return value;
+       else
+               return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
+}
+
 static int ath9k_hw_process_ini(struct ath_hal *ah,
                                struct ath9k_channel *chan,
                                enum ath9k_ht_macmode macmode)
@@ -1294,11 +1360,6 @@ static int ath9k_hw_process_ini(struct ath_hal *ah,
                u32 reg = INI_RA(&ahp->ah_iniModes, i, 0);
                u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex);
 
-#ifdef CONFIG_SLOW_ANT_DIV
-               if (ah->ah_devid == AR9280_DEVID_PCI)
-                       val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, val);
-#endif
-
                REG_WRITE(ah, reg, val);
 
                if (reg >= 0x7800 && reg < 0x78a0
@@ -1309,10 +1370,10 @@ static int ath9k_hw_process_ini(struct ath_hal *ah,
                DO_DELAY(regWrites);
        }
 
-       if (AR_SREV_9280_20_OR_LATER(ah))
+       if (AR_SREV_9280(ah))
                REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites);
 
-       if (AR_SREV_9280_20_OR_LATER(ah))
+       if (AR_SREV_9280(ah))
                REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites);
 
        for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) {
@@ -1585,10 +1646,15 @@ static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan,
                              enum ath9k_ht_macmode macmode)
 {
        u32 phymode;
+       u32 enableDacFifo = 0;
        struct ath_hal_5416 *ahp = AH5416(ah);
 
+       if (AR_SREV_9285_10_OR_LATER(ah))
+               enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
+                                        AR_PHY_FC_ENABLE_DAC_FIFO);
+
        phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
-               | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH;
+               | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
 
        if (IS_CHAN_HT40(chan)) {
                phymode |= AR_PHY_FC_DYN2040_EN;
@@ -2771,11 +2837,14 @@ void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore)
        if (ah->ah_config.pcie_waen) {
                REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen);
        } else {
-               if (AR_SREV_9280(ah))
-                       REG_WRITE(ah, AR_WA, 0x0040073f);
+               if (AR_SREV_9285(ah))
+                       REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
+               else if (AR_SREV_9280(ah))
+                       REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT);
                else
-                       REG_WRITE(ah, AR_WA, 0x0000073f);
+                       REG_WRITE(ah, AR_WA, AR_WA_DEFAULT);
        }
+
 }
 
 /**********************/
@@ -3326,7 +3395,7 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
        else
                pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
 
-       if (AR_SREV_9280(ah))
+       if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
                pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
        else
                pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
@@ -3346,9 +3415,9 @@ bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
        pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
 
        pCap->num_antcfg_5ghz =
-               ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_5GHZ);
+               ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ);
        pCap->num_antcfg_2ghz =
-               ath9k_hw_get_num_ant_config(ah, IEEE80211_BAND_2GHZ);
+               ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
 
        return true;
 }