ath9k: propagate hw initialization errors
[safe/jmp/linux-2.6] / drivers / net / wireless / ath / ath9k / hw.c
index 4acfab5..2e09204 100644 (file)
@@ -380,6 +380,9 @@ 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;
@@ -475,6 +478,8 @@ static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
 
        ah->gbeacon_rate = 0;
 
+       ah->power_mode = ATH9K_PM_UNDEFINED;
+
        return ah;
 }
 
@@ -657,10 +662,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        DPRINTF(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))) {
+       switch (ah->hw_version.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:
+               break;
+       default:
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Mac Chip Rev 0x%02x.%x is not supported by "
                        "this driver\n", ah->hw_version.macVersion,
@@ -700,8 +711,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);
@@ -842,7 +882,28 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        if (ecode != 0)
                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 +919,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) &&
@@ -1165,10 +1218,12 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
        case AR9280_DEVID_PCI:
        case AR9280_DEVID_PCIE:
        case AR9285_DEVID_PCIE:
+       case AR5416_DEVID_AR9287_PCI:
+       case AR5416_DEVID_AR9287_PCIE:
                ah = ath9k_hw_do_attach(devid, sc, error);
                break;
        default:
-               *error = -ENXIO;
+               *error = -EOPNOTSUPP;
                break;
        }
 
@@ -1341,10 +1396,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++) {
@@ -2186,6 +2242,18 @@ static void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan
        REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
 }
 
+static void ath9k_enable_rfkill(struct ath_hw *ah)
+{
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+                   AR_GPIO_INPUT_MUX2_RFSILENT);
+
+       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
+       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                    bool bChannelChange)
 {
@@ -2242,6 +2310,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;
@@ -2313,12 +2391,32 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_interrupt_masks(ah, ah->opmode);
        ath9k_hw_init_qos(ah);
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
                ath9k_enable_rfkill(ah);
-#endif
+
        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);
 
@@ -2334,7 +2432,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)) {
@@ -2472,14 +2570,14 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                }
                break;
        case ATH9K_CIPHER_WEP:
-               if (k->kv_len < LEN_WEP40) {
+               if (k->kv_len < WLAN_KEY_LEN_WEP40) {
                        DPRINTF(ah->ah_sc, ATH_DBG_ANY,
                                "WEP key length %u too small\n", k->kv_len);
                        return false;
                }
-               if (k->kv_len <= LEN_WEP40)
+               if (k->kv_len <= WLAN_KEY_LEN_WEP40)
                        keyType = AR_KEYTABLE_TYPE_40;
-               else if (k->kv_len <= LEN_WEP104)
+               else if (k->kv_len <= WLAN_KEY_LEN_WEP104)
                        keyType = AR_KEYTABLE_TYPE_104;
                else
                        keyType = AR_KEYTABLE_TYPE_128;
@@ -2498,7 +2596,7 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
        key2 = get_unaligned_le32(k->kv_val + 6);
        key3 = get_unaligned_le16(k->kv_val + 10);
        key4 = get_unaligned_le32(k->kv_val + 12);
-       if (k->kv_len <= LEN_WEP104)
+       if (k->kv_len <= WLAN_KEY_LEN_WEP104)
                key4 &= 0xff;
 
        /*
@@ -2717,7 +2815,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[] = {
@@ -2727,6 +2826,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]);
 
@@ -2751,6 +2853,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.
  *
@@ -3010,11 +3157,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;
@@ -3294,7 +3436,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))
@@ -3584,7 +3725,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;
@@ -3613,20 +3756,6 @@ void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
                AR_GPIO_BIT(gpio));
 }
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-void ath9k_enable_rfkill(struct ath_hw *ah)
-{
-       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-                   AR_GPIO_INPUT_MUX2_RFSILENT);
-
-       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
-       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-}
-#endif
-
 u32 ath9k_hw_getdefantenna(struct ath_hw *ah)
 {
        return REG_READ(ah, AR_DEF_ANTENNA) & 0x7;
@@ -3794,19 +3923,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)