summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/hw.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-08-06 21:57:18 +0200
committerDavid S. Miller <davem@davemloft.net>2009-08-06 21:57:18 +0200
commitbfe34ebbaa125f00da309f59cc9d30febe1e3115 (patch)
tree505b43fc81be09ec5b42f82a3e64f300a5e838d5 /drivers/net/wireless/ath/ath9k/hw.c
parentnet/rds: Use AF_INET for sin_family field (diff)
parentath9k: fix compile warning on ath9k_hw_AR9287_check_eeprom() (diff)
downloadlinux-bfe34ebbaa125f00da309f59cc9d30febe1e3115.tar.xz
linux-bfe34ebbaa125f00da309f59cc9d30febe1e3115.zip
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/hw.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c368
1 files changed, 227 insertions, 141 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 431854ccb65b..71a3bcc450a2 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -388,7 +388,7 @@ static const char *ath9k_hw_devname(u16 devid)
return NULL;
}
-static void ath9k_hw_set_defaults(struct ath_hw *ah)
+static void ath9k_hw_init_config(struct ath_hw *ah)
{
int i;
@@ -437,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;
@@ -479,8 +466,6 @@ 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;
}
static int ath9k_hw_rfattach(struct ath_hw *ah)
@@ -593,7 +578,7 @@ static void ath9k_hw_init_txgain_ini(struct ath_hw *ah)
}
}
-static int ath9k_hw_post_attach(struct ath_hw *ah)
+static int ath9k_hw_post_init(struct ath_hw *ah)
{
int ecode;
@@ -604,7 +589,7 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
if (ecode != 0)
return ecode;
- ecode = ath9k_hw_eeprom_attach(ah);
+ ecode = ath9k_hw_eeprom_init(ah);
if (ecode != 0)
return ecode;
@@ -617,71 +602,52 @@ static int ath9k_hw_post_attach(struct ath_hw *ah)
if (!AR_SREV_9100(ah)) {
ath9k_hw_ani_setup(ah);
- ath9k_hw_ani_attach(ah);
+ ath9k_hw_ani_init(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;
- u32 i, j;
-
- ah = ath9k_hw_newstate(devid, sc, status);
- if (ah == NULL)
- return NULL;
-
- ath9k_hw_set_defaults(ah);
-
- if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
- DPRINTF(sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
- ecode = -EIO;
- goto bad;
- }
-
- if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
- DPRINTF(sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
- ecode = -EIO;
- goto bad;
- }
-
- if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
- if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
- (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
- ah->config.serialize_regmode =
- SER_REG_MODE_ON;
- } else {
- ah->config.serialize_regmode =
- SER_REG_MODE_OFF;
- }
- }
-
- 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)) && (!AR_SREV_9287(ah))) {
- DPRINTF(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;
- goto bad;
+ 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;
+}
- if (AR_SREV_9100(ah)) {
- ah->iq_caldata.calData = &iq_cal_multi_sample;
- ah->supp_cals = IQ_MISMATCH_CAL;
- ah->is_pciexpress = 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;
+ /* Not yet */
+ case AR_SREV_VERSION_9271:
+ default:
+ break;
}
- ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+ return false;
+}
+static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
if (AR_SREV_9160_10_OR_LATER(ah)) {
if (AR_SREV_9280_10_OR_LATER(ah)) {
ah->iq_caldata.calData = &iq_cal_single_sample;
@@ -702,10 +668,18 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
}
+}
+
+static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
+{
+ if (AR_SREV_9271(ah)) {
+ INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271_1_0,
+ ARRAY_SIZE(ar9271Modes_9271_1_0), 6);
+ INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271_1_0,
+ ARRAY_SIZE(ar9271Common_9271_1_0), 2);
+ return;
+ }
- 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);
@@ -867,16 +841,10 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
ARRAY_SIZE(ar5416Addac), 2);
}
+}
- if (ah->is_pciexpress)
- ath9k_hw_configpcipowersave(ah, 0);
- else
- ath9k_hw_disablepcie(ah);
-
- ecode = ath9k_hw_post_attach(ah);
- if (ecode != 0)
- goto bad;
-
+static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
if (AR_SREV_9287_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9287Modes_rx_gain_9287_1_1,
@@ -913,8 +881,11 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
}
+}
- ath9k_hw_fill_cap_info(ah);
+static void ath9k_hw_init_11a_eeprom_fix(struct ath_hw *ah)
+{
+ u32 i, j;
if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
@@ -933,29 +904,97 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
}
}
}
+}
+
+int ath9k_hw_init(struct ath_hw *ah)
+{
+ int r = 0;
+
+ if (!ath9k_hw_devid_supported(ah->hw_version.devid))
+ return -EOPNOTSUPP;
+
+ ath9k_hw_init_defaults(ah);
+ ath9k_hw_init_config(ah);
+
+ if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't reset chip\n");
+ return -EIO;
+ }
+
+ if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
+ return -EIO;
+ }
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+ if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+ (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
+ ah->config.serialize_regmode =
+ SER_REG_MODE_ON;
+ } else {
+ ah->config.serialize_regmode =
+ SER_REG_MODE_OFF;
+ }
+ }
+
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET, "serialize_regmode is %d\n",
+ ah->config.serialize_regmode);
+
+ 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);
+ return -EOPNOTSUPP;
+ }
+
+ if (AR_SREV_9100(ah)) {
+ ah->iq_caldata.calData = &iq_cal_multi_sample;
+ ah->supp_cals = IQ_MISMATCH_CAL;
+ ah->is_pciexpress = false;
+ }
+
+ if (AR_SREV_9271(ah))
+ ah->is_pciexpress = false;
+
+ ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
+
+ ath9k_hw_init_cal_settings(ah);
+
+ ah->ani_function = ATH9K_ANI_ALL;
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
- ecode = ath9k_hw_init_macaddr(ah);
- if (ecode != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
+ ath9k_hw_init_mode_regs(ah);
+
+ if (ah->is_pciexpress)
+ ath9k_hw_configpcipowersave(ah, 0);
+ else
+ ath9k_hw_disablepcie(ah);
+
+ r = ath9k_hw_post_init(ah);
+ if (r)
+ return r;
+
+ ath9k_hw_init_mode_gain_regs(ah);
+ ath9k_hw_fill_cap_info(ah);
+ ath9k_hw_init_11a_eeprom_fix(ah);
+
+ r = ath9k_hw_init_macaddr(ah);
+ if (r) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"Failed to initialize MAC address\n");
- goto bad;
+ return r;
}
- if (AR_SREV_9285(ah))
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
else
ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
ath9k_init_nfcal_hist_buffer(ah);
- return ah;
-bad:
- if (ah)
- ath9k_hw_detach(ah);
- if (status)
- *status = ecode;
-
- return NULL;
+ return 0;
}
static void ath9k_hw_init_bb(struct ath_hw *ah,
@@ -1194,35 +1233,12 @@ const char *ath9k_hw_probe(u16 vendorid, u16 devid)
void ath9k_hw_detach(struct ath_hw *ah)
{
if (!AR_SREV_9100(ah))
- ath9k_hw_ani_detach(ah);
+ ath9k_hw_ani_disable(ah);
- ath9k_hw_rfdetach(ah);
+ ath9k_hw_rf_free(ah);
ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
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:
- case AR5416_DEVID_AR9287_PCI:
- case AR5416_DEVID_AR9287_PCIE:
- ah = ath9k_hw_do_attach(devid, sc, error);
- break;
- default:
- *error = -ENXIO;
- break;
- }
-
- return ah;
+ ah = NULL;
}
/*******/
@@ -1232,6 +1248,27 @@ struct ath_hw *ath9k_hw_attach(u16 devid, struct ath_softc *sc, int *error)
static void ath9k_hw_override_ini(struct ath_hw *ah,
struct ath9k_channel *chan)
{
+ u32 val;
+
+ if (AR_SREV_9271(ah)) {
+ /*
+ * Enable spectral scan to solution for issues with stuck
+ * beacons on AR9271 1.0. The beacon stuck issue is not seeon on
+ * AR9271 1.1
+ */
+ if (AR_SREV_9271_10(ah)) {
+ val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) | AR_PHY_SPECTRAL_SCAN_ENABLE;
+ REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
+ }
+ else if (AR_SREV_9271_11(ah))
+ /*
+ * change AR_PHY_RF_CTL3 setting to fix MAC issue
+ * present on AR9271 1.1
+ */
+ REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001);
+ return;
+ }
+
/*
* Set the RX_ABORT and RX_DIS and clear if off only after
* RXE is set for MAC. This prevents frames with corrupted
@@ -1243,7 +1280,10 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
if (!AR_SREV_5416_20_OR_LATER(ah) ||
AR_SREV_9280_10_OR_LATER(ah))
return;
-
+ /*
+ * Disable BB clock gating
+ * Necessary to avoid issues on AR5416 2.0
+ */
REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
}
@@ -1475,23 +1515,48 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
{
u32 regval;
+ /*
+ * set AHB_MODE not to do cacheline prefetches
+ */
regval = REG_READ(ah, AR_AHB_MODE);
REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+ /*
+ * let mac dma reads be in 128 byte chunks
+ */
regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+ /*
+ * Restore TX Trigger Level to its pre-reset value.
+ * The initial value depends on whether aggregation is enabled, and is
+ * adjusted whenever underruns are detected.
+ */
REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+ /*
+ * let mac dma writes be in 128 byte chunks
+ */
regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+ /*
+ * Setup receive FIFO threshold to hold off TX activities
+ */
REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
+ /*
+ * reduce the number of usable entries in PCU TXBUF to avoid
+ * wrap around issues.
+ */
if (AR_SREV_9285(ah)) {
+ /* For AR9285 the number of Fifos are reduced to half.
+ * So set the usable tx buf size also to half to
+ * avoid data/delimiter underruns
+ */
REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE);
- } else {
+ } else if (!AR_SREV_9271(ah)) {
REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
AR_PCU_TXBUF_CTRL_USABLE_SIZE);
}
@@ -2297,11 +2362,26 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_mark_phy_inactive(ah);
+ if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+ REG_WRITE(ah,
+ AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_RADIO_RF_RST);
+ udelay(50);
+ }
+
if (!ath9k_hw_chip_reset(ah, chan)) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL, "Chip reset failed\n");
return -EINVAL;
}
+ if (AR_SREV_9271(ah) && ah->htc_reset_init) {
+ ah->htc_reset_init = false;
+ REG_WRITE(ah,
+ AR9271_RESET_POWER_DOWN_CONTROL,
+ AR9271_GATE_MAC_CTL);
+ udelay(50);
+ }
+
if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
@@ -2437,6 +2517,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
+ /*
+ * For big endian systems turn on swapping for descriptors
+ */
if (AR_SREV_9100(ah)) {
u32 mask;
mask = REG_READ(ah, AR_CFG);
@@ -2451,8 +2534,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
+ /* Configure AR9271 target WLAN */
+ if (AR_SREV_9271(ah))
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
#ifdef __BIG_ENDIAN
- REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
#endif
}
@@ -2494,9 +2581,6 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry)
}
- if (ah->curchan == NULL)
- return true;
-
return true;
}
@@ -2921,7 +3005,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_init()
*/
for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
@@ -2982,7 +3066,7 @@ void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore)
if (ah->config.pcie_waen) {
REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
} else {
- if (AR_SREV_9285(ah))
+ if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT);
/*
* On AR9280 chips bit 22 of 0x4004 needs to be set to
@@ -3152,11 +3236,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;
@@ -3451,10 +3530,17 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
+ /*
+ * For AR9271 we will temporarilly uses the rx chainmax as read from
+ * the EEPROM.
+ */
if ((ah->hw_version.devid == AR5416_DEVID_PCI) &&
- !(eeval & AR5416_OPFLAGS_11A))
+ !(eeval & AR5416_OPFLAGS_11A) &&
+ !(AR_SREV_9271(ah)))
+ /* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
else
+ /* Use rx_chainmask from EEPROM. */
pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))