diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/init.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 218 |
1 files changed, 133 insertions, 85 deletions
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fd9a61834c17..ee951493e993 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -18,11 +18,12 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <linux/ath9k_platform.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_net.h> +#include <linux/nvmem-consumer.h> #include <linux/relay.h> +#include <linux/dmi.h> #include <net/ieee80211_radiotap.h> #include "ath9k.h" @@ -36,7 +37,6 @@ static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); -MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); static unsigned int ath9k_debug = ATH_DBG_DEFAULT; @@ -75,6 +75,10 @@ MODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ +int ath9k_use_msi; +module_param_named(use_msi, ath9k_use_msi, int, 0444); +MODULE_PARM_DESC(use_msi, "Use MSI instead of INTx if possible"); + bool is_ath9k_unloaded; #ifdef CONFIG_MAC80211_LEDS @@ -92,19 +96,69 @@ static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { }; #endif +static int __init set_use_msi(const struct dmi_system_id *dmi) +{ + ath9k_use_msi = 1; + return 1; +} + +static const struct dmi_system_id ath9k_quirks[] __initconst = { + { + .callback = set_use_msi, + .ident = "Dell Inspiron 24-3460", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 24-3460"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Vostro 3262", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3262"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Inspiron 3472", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3472"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Vostro 15-3572", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15-3572"), + }, + }, + { + .callback = set_use_msi, + .ident = "Dell Inspiron 14-3473", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 14-3473"), + }, + }, + {} +}; + static void ath9k_deinit_softc(struct ath_softc *sc); static void ath9k_op_ps_wakeup(struct ath_common *common) { - ath9k_ps_wakeup((struct ath_softc *) common->priv); + ath9k_ps_wakeup(common->priv); } static void ath9k_op_ps_restore(struct ath_common *common) { - ath9k_ps_restore((struct ath_softc *) common->priv); + ath9k_ps_restore(common->priv); } -static struct ath_ps_ops ath9k_ps_ops = { +static const struct ath_ps_ops ath9k_ps_ops = { .wakeup = ath9k_op_ps_wakeup, .restore = ath9k_op_ps_restore, }; @@ -117,9 +171,9 @@ static struct ath_ps_ops ath9k_ps_ops = { static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { unsigned long flags; @@ -132,9 +186,9 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_softc *sc = common->priv; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { @@ -172,10 +226,10 @@ static unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset, static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) { - struct ath_hw *ah = (struct ath_hw *) hw_priv; + struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); - struct ath_softc *sc = (struct ath_softc *) common->priv; - unsigned long uninitialized_var(flags); + struct ath_softc *sc = common->priv; + unsigned long flags; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { @@ -202,6 +256,11 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath_reg_notifier_apply(wiphy, request, reg); + /* synchronize DFS detector if regulatory domain changed */ + if (sc->dfs_detector != NULL) + sc->dfs_detector->set_dfs_domain(sc->dfs_detector, + request->dfs_region); + /* Set tx power */ if (!ah->curchan) return; @@ -212,10 +271,6 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, sc->cur_chan->txpower, &sc->cur_chan->cur_txpower); - /* synchronize DFS detector if regulatory domain changed */ - if (sc->dfs_detector != NULL) - sc->dfs_detector->set_dfs_domain(sc->dfs_detector, - request->dfs_region); ath9k_ps_restore(sc); } @@ -275,7 +330,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, if (!dd->dd_desc) return -ENOMEM; - ds = (u8 *) dd->dd_desc; + ds = dd->dd_desc; ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", name, ds, (u32) dd->dd_desc_len, ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); @@ -369,10 +424,10 @@ static void ath9k_init_misc(struct ath_softc *sc) struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; - setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc); + timer_setup(&common->ani.timer, ath_ani_calibrate, 0); common->last_rssi = ATH_RSSI_DUMMY_MARKER; - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->bssidmask); sc->beacon.slottime = 9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) @@ -513,45 +568,53 @@ static void ath9k_eeprom_release(struct ath_softc *sc) release_firmware(sc->sc_ah->eeprom_blob); } -static int ath9k_init_platform(struct ath_softc *sc) +static int ath9k_nvmem_request_eeprom(struct ath_softc *sc) { - struct ath9k_platform_data *pdata = sc->dev->platform_data; struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - int ret; + struct nvmem_cell *cell; + void *buf; + size_t len; + int err; - if (!pdata) - return 0; + cell = devm_nvmem_cell_get(sc->dev, "calibration"); + if (IS_ERR(cell)) { + err = PTR_ERR(cell); - if (!pdata->use_eeprom) { - ah->ah_flags &= ~AH_USE_EEPROM; - ah->gpio_mask = pdata->gpio_mask; - ah->gpio_val = pdata->gpio_val; - ah->led_pin = pdata->led_pin; - ah->is_clk_25mhz = pdata->is_clk_25mhz; - ah->get_mac_revision = pdata->get_mac_revision; - ah->external_reset = pdata->external_reset; - ah->disable_2ghz = pdata->disable_2ghz; - ah->disable_5ghz = pdata->disable_5ghz; - - if (!pdata->endian_check) - ah->ah_flags |= AH_NO_EEP_SWAP; - } + /* nvmem cell might not be defined, or the nvmem + * subsystem isn't included. In this case, follow + * the established "just return 0;" convention + * to say: + * "All good. Nothing to see here. Please go on." + */ + if (err == -ENOENT || err == -EOPNOTSUPP) + return 0; - if (pdata->eeprom_name) { - ret = ath9k_eeprom_request(sc, pdata->eeprom_name); - if (ret) - return ret; + return err; } - if (pdata->led_active_high) - ah->config.led_active_high = true; + buf = nvmem_cell_read(cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* run basic sanity checks on the returned nvram cell length. + * That length has to be a multiple of a "u16" (i.e.: & 1). + * Furthermore, it has to be more than "let's say" 512 bytes + * but less than the maximum of AR9300_EEPROM_SIZE (16kb). + */ + if ((len & 1) == 1 || len < 512 || len >= AR9300_EEPROM_SIZE) { + kfree(buf); + return -EINVAL; + } - if (pdata->tx_gain_buffalo) - ah->config.tx_gain_buffalo = true; + /* devres manages the calibration values release on shutdown */ + ah->nvmem_blob = devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); + kfree(buf); + if (!ah->nvmem_blob) + return -ENOMEM; - if (pdata->macaddr) - ether_addr_copy(common->macaddr, pdata->macaddr); + ah->nvmem_blob_len = len; + ah->ah_flags &= ~AH_USE_EEPROM; + ah->ah_flags |= AH_NO_EEP_SWAP; return 0; } @@ -562,7 +625,6 @@ static int ath9k_of_init(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); enum ath_bus_type bus_type = common->bus_ops->ath_bus_type; - const char *mac; char eeprom_name[100]; int ret; @@ -580,14 +642,14 @@ static int ath9k_of_init(struct ath_softc *sc) ret = ath9k_eeprom_request(sc, eeprom_name); if (ret) return ret; - } - mac = of_get_mac_address(np); - if (mac) - ether_addr_copy(common->macaddr, mac); + ah->ah_flags &= ~AH_USE_EEPROM; + ah->ah_flags |= AH_NO_EEP_SWAP; + } - ah->ah_flags &= ~AH_USE_EEPROM; - ah->ah_flags |= AH_NO_EEP_SWAP; + ret = of_get_mac_address(np, common->macaddr); + if (ret == -EPROBE_DEFER) + return ret; return 0; } @@ -620,8 +682,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, /* Will be cleared in ath9k_start() */ set_bit(ATH_OP_INVALID, &common->op_flags); - sc->airtime_flags = (AIRTIME_USE_TX | AIRTIME_USE_RX | - AIRTIME_USE_NEW_QUEUES); sc->sc_ah = ah; sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); @@ -646,11 +706,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, */ ath9k_init_pcoem_platform(sc); - ret = ath9k_init_platform(sc); + ret = ath9k_of_init(sc); if (ret) return ret; - ret = ath9k_of_init(sc); + ret = ath9k_nvmem_request_eeprom(sc); if (ret) return ret; @@ -674,11 +734,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, spin_lock_init(&sc->sc_pm_lock); spin_lock_init(&sc->chan_lock); mutex_init(&sc->mutex); - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, - (unsigned long)sc); + tasklet_setup(&sc->intr_tq, ath9k_tasklet); + tasklet_setup(&sc->bcon_tasklet, ath9k_beacon_tasklet); - setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); + timer_setup(&sc->sleep_timer, ath_ps_full_sleep, 0); INIT_WORK(&sc->hw_reset_work, ath_reset_work); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); @@ -751,7 +810,7 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) ah->curchan = &ah->channels[chan->hw_value]; cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); ath9k_cmn_get_channel(sc->hw, ah, &chandef); - ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true); + ath9k_hw_set_txpowerlimit(ah, MAX_COMBINED_POWER, true); } } @@ -779,12 +838,6 @@ static const struct ieee80211_iface_limit if_limits[] = { BIT(NL80211_IFTYPE_P2P_GO) }, }; -#ifdef CONFIG_WIRELESS_WDS -static const struct ieee80211_iface_limit wds_limits[] = { - { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, -}; -#endif - #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT static const struct ieee80211_iface_limit if_limits_multi[] = { @@ -821,15 +874,6 @@ static const struct ieee80211_iface_combination if_comb[] = { BIT(NL80211_CHAN_WIDTH_40), #endif }, -#ifdef CONFIG_WIRELESS_WDS - { - .limits = wds_limits, - .n_limits = ARRAY_SIZE(wds_limits), - .max_interfaces = 2048, - .num_different_channels = 1, - .beacon_int_infra_match = true, - }, -#endif }; #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT @@ -844,7 +888,6 @@ static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ieee80211_hw_set(hw, QUEUE_CONTROL); hw->queues = ATH9K_NUM_TX_QUEUES; hw->offchannel_tx_hw_queue = hw->queues - 1; - hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS); hw->wiphy->iface_combinations = if_comb_multi; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); hw->wiphy->max_scan_ssids = 255; @@ -900,9 +943,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT) | -#ifdef CONFIG_WIRELESS_WDS - BIT(NL80211_IFTYPE_WDS) | -#endif BIT(NL80211_IFTYPE_OCB); if (ath9k_is_chanctx_enabled()) @@ -957,6 +997,10 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) SET_IEEE80211_PERM_ADDR(hw, common->macaddr); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); } int ath9k_init_device(u16 devid, struct ath_softc *sc, @@ -1004,6 +1048,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, ARRAY_SIZE(ath9k_tpt_blink)); #endif + wiphy_read_of_freq_limits(hw->wiphy); + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) @@ -1053,7 +1099,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) if (ATH_TXQ_SETUP(sc, i)) ath_tx_cleanupq(sc, &sc->tx.txq[i]); - del_timer_sync(&sc->sleep_timer); + timer_delete_sync(&sc->sleep_timer); ath9k_hw_deinit(sc->sc_ah); if (sc->dfs_detector != NULL) sc->dfs_detector->exit(sc->dfs_detector); @@ -1100,6 +1146,8 @@ static int __init ath9k_init(void) goto err_pci_exit; } + dmi_check_system(ath9k_quirks); + return 0; err_pci_exit: |
