]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/wireless/ath/ath9k/hw.c
ath9k: rename ath9k_hw_set_defaults() to ath9k_hw_init_config()
[linux-2.6.git] / drivers / net / wireless / ath / ath9k / hw.c
index 34935a8ee59de1c443a1a3fc7a2cfe7ece086a92..31ec83dfddd5551a9d510f2aee0fb9f1eef2b906 100644 (file)
@@ -380,12 +380,15 @@ static const char *ath9k_hw_devname(u16 devid)
                return "Atheros 9280";
        case AR9285_DEVID_PCIE:
                return "Atheros 9285";
+       case AR5416_DEVID_AR9287_PCI:
+       case AR5416_DEVID_AR9287_PCIE:
+               return "Atheros 9287";
        }
 
        return NULL;
 }
 
-static void ath9k_hw_set_defaults(struct ath_hw *ah)
+static void ath9k_hw_init_config(struct ath_hw *ah)
 {
        int i;
 
@@ -434,27 +437,14 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
                ah->config.serialize_regmode = SER_REG_MODE_AUTO;
 }
 
-static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
-                                       int *status)
+static void ath9k_hw_init_defaults(struct ath_hw *ah)
 {
-       struct ath_hw *ah;
-
-       ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
-       if (ah == NULL) {
-               DPRINTF(sc, ATH_DBG_FATAL,
-                       "Cannot allocate memory for state block\n");
-               *status = -ENOMEM;
-               return NULL;
-       }
-
-       ah->ah_sc = sc;
        ah->hw_version.magic = AR5416_MAGIC;
        ah->regulatory.country_code = CTRY_DEFAULT;
-       ah->hw_version.devid = devid;
        ah->hw_version.subvendorid = 0;
 
        ah->ah_flags = 0;
-       if ((devid == AR5416_AR9100_DEVID))
+       if (ah->hw_version.devid == AR5416_AR9100_DEVID)
                ah->hw_version.macVersion = AR_SREV_VERSION_9100;
        if (!AR_SREV_9100(ah))
                ah->ah_flags = AH_USE_EEPROM;
@@ -475,7 +465,7 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
 
        ah->gbeacon_rate = 0;
 
-       return ah;
+       ah->power_mode = ATH9K_PM_UNDEFINED;
 }
 
 static int ath9k_hw_rfattach(struct ath_hw *ah)
@@ -618,28 +608,64 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
        return 0;
 }
 
-static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
-                                        int *status)
+static bool ath9k_hw_devid_supported(u16 devid)
 {
-       struct ath_hw *ah;
-       int ecode;
+       switch (devid) {
+       case AR5416_DEVID_PCI:
+       case AR5416_DEVID_PCIE:
+       case AR5416_AR9100_DEVID:
+       case AR9160_DEVID_PCI:
+       case AR9280_DEVID_PCI:
+       case AR9280_DEVID_PCIE:
+       case AR9285_DEVID_PCIE:
+       case AR5416_DEVID_AR9287_PCI:
+       case AR5416_DEVID_AR9287_PCIE:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+static bool ath9k_hw_macversion_supported(u32 macversion)
+{
+       switch (macversion) {
+       case AR_SREV_VERSION_5416_PCI:
+       case AR_SREV_VERSION_5416_PCIE:
+       case AR_SREV_VERSION_9160:
+       case AR_SREV_VERSION_9100:
+       case AR_SREV_VERSION_9280:
+       case AR_SREV_VERSION_9285:
+       case AR_SREV_VERSION_9287:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+int ath9k_hw_attach(struct ath_hw *ah)
+{
+       int r;
        u32 i, j;
 
-       ah = ath9k_hw_newstate(devid, sc, status);
-       if (ah == NULL)
-               return NULL;
+       if (!ath9k_hw_devid_supported(ah->hw_version.devid)) {
+               r = -EOPNOTSUPP;
+               goto bad;
+       }
 
-       ath9k_hw_set_defaults(ah);
+       ath9k_hw_init_defaults(ah);
+       ath9k_hw_init_config(ah);
 
        if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
-               DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
-               ecode = -EIO;
+               DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
+               r = -EIO;
                goto bad;
        }
 
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
-               DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
-               ecode = -EIO;
+               DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+               r = -EIO;
                goto bad;
        }
 
@@ -654,18 +680,15 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                }
        }
 
-       DPRINTF(sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+       DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
                ah->config.serialize_regmode);
 
-       if ((ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCI) &&
-           (ah->hw_version.macVersion != AR_SREV_VERSION_5416_PCIE) &&
-           (ah->hw_version.macVersion != AR_SREV_VERSION_9160) &&
-           (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) {
-               DPRINTF(sc, ATH_DBG_FATAL,
+       if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
                        "Mac Chip Rev 0x%02x.%x is not supported by "
                        "this driver\n", ah->hw_version.macVersion,
                        ah->hw_version.macRev);
-               ecode = -EOPNOTSUPP;
+               r = -EOPNOTSUPP;
                goto bad;
        }
 
@@ -700,8 +723,37 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        ah->ani_function = ATH9K_ANI_ALL;
        if (AR_SREV_9280_10_OR_LATER(ah))
                ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
+       if (AR_SREV_9287_11_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
+                               ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
+                               ARRAY_SIZE(ar9287Common_9287_1_1), 2);
+               if (ah->config.pcie_clock_req)
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_off_L1_9287_1_1,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
+               else
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
+                                       2);
+       } else if (AR_SREV_9287_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
+                               ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
+                               ARRAY_SIZE(ar9287Common_9287_1_0), 2);
+
+               if (ah->config.pcie_clock_req)
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_off_L1_9287_1_0,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
+               else
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
+                                 2);
+       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
 
-       if (AR_SREV_9285_12_OR_LATER(ah)) {
 
                INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
                               ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
@@ -838,11 +890,32 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        else
                ath9k_hw_disablepcie(ah);
 
-       ecode = ath9k_hw_post_attach(ah);
-       if (ecode != 0)
+       r = ath9k_hw_post_attach(ah);
+       if (r)
                goto bad;
 
-       if (AR_SREV_9285_12_OR_LATER(ah)) {
+       if (AR_SREV_9287_11(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+               ar9287Modes_rx_gain_9287_1_1,
+               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+       else if (AR_SREV_9287_10(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+               ar9287Modes_rx_gain_9287_1_0,
+               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
+       else if (AR_SREV_9280_20(ah))
+               ath9k_hw_init_rxgain_ini(ah);
+
+       if (AR_SREV_9287_11(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9287Modes_tx_gain_9287_1_1,
+               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+       } else if (AR_SREV_9287_10(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9287Modes_tx_gain_9287_1_0,
+               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
+       } else if (AR_SREV_9280_20(ah)) {
+               ath9k_hw_init_txgain_ini(ah);
+       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
                u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
 
                /* txgain table */
@@ -858,14 +931,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 
        }
 
-       /* rxgain table */
-       if (AR_SREV_9280_20(ah))
-               ath9k_hw_init_rxgain_ini(ah);
-
-       /* txgain table */
-       if (AR_SREV_9280_20(ah))
-               ath9k_hw_init_txgain_ini(ah);
-
        ath9k_hw_fill_cap_info(ah);
 
        if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
@@ -886,9 +951,9 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                }
        }
 
-       ecode = ath9k_hw_init_macaddr(ah);
-       if (ecode != 0) {
-               DPRINTF(sc, ATH_DBG_FATAL,
+       r = ath9k_hw_init_macaddr(ah);
+       if (r) {
+               DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
                        "Failed to initialize MAC address\n");
                goto bad;
        }
@@ -900,14 +965,10 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 
        ath9k_init_nfcal_hist_buffer(ah);
 
-       return ah;
+       return 0;
 bad:
-       if (ah)
-               ath9k_hw_detach(ah);
-       if (status)
-               *status = ecode;
-
-       return NULL;
+       ath9k_hw_detach(ah);
+       return r;
 }
 
 static void ath9k_hw_init_bb(struct ath_hw *ah,
@@ -1153,28 +1214,6 @@ void ath9k_hw_detach(struct ath_hw *ah)
        kfree(ah);
 }
 
-struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
-{
-       struct ath_hw *ah = NULL;
-
-       switch (devid) {
-       case AR5416_DEVID_PCI:
-       case AR5416_DEVID_PCIE:
-       case AR5416_AR9100_DEVID:
-       case AR9160_DEVID_PCI:
-       case AR9280_DEVID_PCI:
-       case AR9280_DEVID_PCIE:
-       case AR9285_DEVID_PCIE:
-               ah = ath9k_hw_do_attach(devid, sc, error);
-               break;
-       default:
-               *error = -ENXIO;
-               break;
-       }
-
-       return ah;
-}
-
 /*******/
 /* INI */
 /*******/
@@ -1341,10 +1380,11 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
                DO_DELAY(regWrites);
        }
 
-       if (AR_SREV_9280(ah))
+       if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
                REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
 
-       if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah))
+       if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
+           AR_SREV_9287_10_OR_LATER(ah))
                REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
 
        for (i = 0; i < ah->iniCommon.ia_rows; i++) {
@@ -2254,6 +2294,16 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (AR_SREV_9280_10_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
+       if (AR_SREV_9287_10_OR_LATER(ah)) {
+               /* Enable ASYNC FIFO */
+               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+               REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+               REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+       }
        r = ath9k_hw_process_ini(ah, chan, sc->tx_chan_width);
        if (r)
                return r;
@@ -2330,6 +2380,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_init_user_settings(ah);
 
+       if (AR_SREV_9287_10_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+                         AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+                         AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+                         AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+
+               REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+
+               REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+                           AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+               REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+                             AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+       }
+       if (AR_SREV_9287_10_OR_LATER(ah)) {
+               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+                               AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+       }
+
        REG_WRITE(ah, AR_STA_ID1,
                  REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
 
@@ -2345,7 +2416,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_bb(ah, chan);
 
        if (!ath9k_hw_init_cal(ah, chan))
-               return -EIO;;
+               return -EIO;
 
        rx_chainmask = ah->rxchainmask;
        if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2728,7 +2799,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
        return true;
 }
 
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+                                    enum ath9k_power_mode mode)
 {
        int status = true, setChip = true;
        static const char *modes[] = {
@@ -2738,6 +2810,9 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
                "UNDEFINED"
        };
 
+       if (ah->power_mode == mode)
+               return status;
+
        DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s -> %s\n",
                modes[ah->power_mode], modes[mode]);
 
@@ -2762,6 +2837,51 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
        return status;
 }
 
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
+       ret = ath9k_hw_setpower_nolock(ah, mode);
+       spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
+
+       return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (++sc->ps_usecount != 1)
+               goto unlock;
+
+       ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+
+ unlock:
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
+       if (--sc->ps_usecount != 0)
+               goto unlock;
+
+       if (sc->ps_enabled &&
+           !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+                             SC_OP_WAIT_FOR_CAB |
+                             SC_OP_WAIT_FOR_PSPOLL_DATA |
+                             SC_OP_WAIT_FOR_TX_ACK)))
+               ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+
+ unlock:
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
 /*
  * Helper for ASPM support.
  *
@@ -2790,7 +2910,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
                /*
                 * AR9280 2.0 or later chips use SerDes values from the
                 * initvals.h initialized depending on chipset during
-                * ath9k_hw_do_attach()
+                * ath9k_hw_attach()
                 */
                for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
                        REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
@@ -3021,11 +3141,6 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
        return true;
 }
 
-enum ath9k_int ath9k_hw_intrget(struct ath_hw *ah)
-{
-       return ah->mask_reg;
-}
-
 enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
 {
        u32 omask = ah->mask_reg;
@@ -3305,7 +3420,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        if (eeval & AR5416_OPFLAGS_11G) {
-               set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
                set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
                if (ah->config.ht_enable) {
                        if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3595,7 +3709,9 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
        if (gpio >= ah->caps.num_gpio_pins)
                return 0xffffffff;
 
-       if (AR_SREV_9285_10_OR_LATER(ah))
+       if (AR_SREV_9287_10_OR_LATER(ah))
+               return MS_REG_READ(AR9287, gpio) != 0;
+       else if (AR_SREV_9285_10_OR_LATER(ah))
                return MS_REG_READ(AR9285, gpio) != 0;
        else if (AR_SREV_9280_10_OR_LATER(ah))
                return MS_REG_READ(AR928X, gpio) != 0;
@@ -3791,19 +3907,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
 
 void ath9k_hw_reset_tsf(struct ath_hw *ah)
 {
-       int count;
+       ath9k_ps_wakeup(ah->ah_sc);
+       if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
+                          AH_TSF_WRITE_TIMEOUT))
+               DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+                       "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
 
-       count = 0;
-       while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
-               count++;
-               if (count > 10) {
-                       DPRINTF(ah->ah_sc, ATH_DBG_RESET,
-                               "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
-                       break;
-               }
-               udelay(10);
-       }
        REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+       ath9k_ps_restore(ah->ah_sc);
 }
 
 bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)