162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/ath9k_platform.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/of_net.h> 2562306a36Sopenharmony_ci#include <linux/nvmem-consumer.h> 2662306a36Sopenharmony_ci#include <linux/relay.h> 2762306a36Sopenharmony_ci#include <linux/dmi.h> 2862306a36Sopenharmony_ci#include <net/ieee80211_radiotap.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "ath9k.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct ath9k_eeprom_ctx { 3362306a36Sopenharmony_ci struct completion complete; 3462306a36Sopenharmony_ci struct ath_hw *ah; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic char *dev_info = "ath9k"; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciMODULE_AUTHOR("Atheros Communications"); 4062306a36Sopenharmony_ciMODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); 4162306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic unsigned int ath9k_debug = ATH_DBG_DEFAULT; 4462306a36Sopenharmony_cimodule_param_named(debug, ath9k_debug, uint, 0); 4562306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debugging mask"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint ath9k_modparam_nohwcrypt; 4862306a36Sopenharmony_cimodule_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); 4962306a36Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciint ath9k_led_blink; 5262306a36Sopenharmony_cimodule_param_named(blink, ath9k_led_blink, int, 0444); 5362306a36Sopenharmony_ciMODULE_PARM_DESC(blink, "Enable LED blink on activity"); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int ath9k_led_active_high = -1; 5662306a36Sopenharmony_cimodule_param_named(led_active_high, ath9k_led_active_high, int, 0444); 5762306a36Sopenharmony_ciMODULE_PARM_DESC(led_active_high, "Invert LED polarity"); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int ath9k_btcoex_enable; 6062306a36Sopenharmony_cimodule_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); 6162306a36Sopenharmony_ciMODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int ath9k_bt_ant_diversity; 6462306a36Sopenharmony_cimodule_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444); 6562306a36Sopenharmony_ciMODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int ath9k_ps_enable; 6862306a36Sopenharmony_cimodule_param_named(ps_enable, ath9k_ps_enable, int, 0444); 6962306a36Sopenharmony_ciMODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciint ath9k_use_chanctx; 7462306a36Sopenharmony_cimodule_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); 7562306a36Sopenharmony_ciMODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciint ath9k_use_msi; 8062306a36Sopenharmony_cimodule_param_named(use_msi, ath9k_use_msi, int, 0444); 8162306a36Sopenharmony_ciMODULE_PARM_DESC(use_msi, "Use MSI instead of INTx if possible"); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cibool is_ath9k_unloaded; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_LEDS 8662306a36Sopenharmony_cistatic const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { 8762306a36Sopenharmony_ci { .throughput = 0 * 1024, .blink_time = 334 }, 8862306a36Sopenharmony_ci { .throughput = 1 * 1024, .blink_time = 260 }, 8962306a36Sopenharmony_ci { .throughput = 5 * 1024, .blink_time = 220 }, 9062306a36Sopenharmony_ci { .throughput = 10 * 1024, .blink_time = 190 }, 9162306a36Sopenharmony_ci { .throughput = 20 * 1024, .blink_time = 170 }, 9262306a36Sopenharmony_ci { .throughput = 50 * 1024, .blink_time = 150 }, 9362306a36Sopenharmony_ci { .throughput = 70 * 1024, .blink_time = 130 }, 9462306a36Sopenharmony_ci { .throughput = 100 * 1024, .blink_time = 110 }, 9562306a36Sopenharmony_ci { .throughput = 200 * 1024, .blink_time = 80 }, 9662306a36Sopenharmony_ci { .throughput = 300 * 1024, .blink_time = 50 }, 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int __init set_use_msi(const struct dmi_system_id *dmi) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci ath9k_use_msi = 1; 10362306a36Sopenharmony_ci return 1; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct dmi_system_id ath9k_quirks[] __initconst = { 10762306a36Sopenharmony_ci { 10862306a36Sopenharmony_ci .callback = set_use_msi, 10962306a36Sopenharmony_ci .ident = "Dell Inspiron 24-3460", 11062306a36Sopenharmony_ci .matches = { 11162306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 11262306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 24-3460"), 11362306a36Sopenharmony_ci }, 11462306a36Sopenharmony_ci }, 11562306a36Sopenharmony_ci { 11662306a36Sopenharmony_ci .callback = set_use_msi, 11762306a36Sopenharmony_ci .ident = "Dell Vostro 3262", 11862306a36Sopenharmony_ci .matches = { 11962306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 12062306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3262"), 12162306a36Sopenharmony_ci }, 12262306a36Sopenharmony_ci }, 12362306a36Sopenharmony_ci { 12462306a36Sopenharmony_ci .callback = set_use_msi, 12562306a36Sopenharmony_ci .ident = "Dell Inspiron 3472", 12662306a36Sopenharmony_ci .matches = { 12762306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 12862306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3472"), 12962306a36Sopenharmony_ci }, 13062306a36Sopenharmony_ci }, 13162306a36Sopenharmony_ci { 13262306a36Sopenharmony_ci .callback = set_use_msi, 13362306a36Sopenharmony_ci .ident = "Dell Vostro 15-3572", 13462306a36Sopenharmony_ci .matches = { 13562306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 13662306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15-3572"), 13762306a36Sopenharmony_ci }, 13862306a36Sopenharmony_ci }, 13962306a36Sopenharmony_ci { 14062306a36Sopenharmony_ci .callback = set_use_msi, 14162306a36Sopenharmony_ci .ident = "Dell Inspiron 14-3473", 14262306a36Sopenharmony_ci .matches = { 14362306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 14462306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 14-3473"), 14562306a36Sopenharmony_ci }, 14662306a36Sopenharmony_ci }, 14762306a36Sopenharmony_ci {} 14862306a36Sopenharmony_ci}; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void ath9k_deinit_softc(struct ath_softc *sc); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void ath9k_op_ps_wakeup(struct ath_common *common) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci ath9k_ps_wakeup((struct ath_softc *) common->priv); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic void ath9k_op_ps_restore(struct ath_common *common) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci ath9k_ps_restore((struct ath_softc *) common->priv); 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic const struct ath_ps_ops ath9k_ps_ops = { 16362306a36Sopenharmony_ci .wakeup = ath9k_op_ps_wakeup, 16462306a36Sopenharmony_ci .restore = ath9k_op_ps_restore, 16562306a36Sopenharmony_ci}; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * Read and write, they both share the same lock. We do this to serialize 16962306a36Sopenharmony_ci * reads and writes on Atheros 802.11n PCI devices only. This is required 17062306a36Sopenharmony_ci * as the FIFO on these devices can only accept sanely 2 requests. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct ath_hw *ah = hw_priv; 17662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 17762306a36Sopenharmony_ci struct ath_softc *sc = (struct ath_softc *) common->priv; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { 18062306a36Sopenharmony_ci unsigned long flags; 18162306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_serial_rw, flags); 18262306a36Sopenharmony_ci iowrite32(val, sc->mem + reg_offset); 18362306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 18462306a36Sopenharmony_ci } else 18562306a36Sopenharmony_ci iowrite32(val, sc->mem + reg_offset); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct ath_hw *ah = hw_priv; 19162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 19262306a36Sopenharmony_ci struct ath_softc *sc = (struct ath_softc *) common->priv; 19362306a36Sopenharmony_ci u32 val; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { 19662306a36Sopenharmony_ci unsigned long flags; 19762306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_serial_rw, flags); 19862306a36Sopenharmony_ci val = ioread32(sc->mem + reg_offset); 19962306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 20062306a36Sopenharmony_ci } else 20162306a36Sopenharmony_ci val = ioread32(sc->mem + reg_offset); 20262306a36Sopenharmony_ci return val; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic void ath9k_multi_ioread32(void *hw_priv, u32 *addr, 20662306a36Sopenharmony_ci u32 *val, u16 count) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci int i; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci for (i = 0; i < count; i++) 21162306a36Sopenharmony_ci val[i] = ath9k_ioread32(hw_priv, addr[i]); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset, 21662306a36Sopenharmony_ci u32 set, u32 clr) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci u32 val; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci val = ioread32(sc->mem + reg_offset); 22162306a36Sopenharmony_ci val &= ~clr; 22262306a36Sopenharmony_ci val |= set; 22362306a36Sopenharmony_ci iowrite32(val, sc->mem + reg_offset); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return val; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct ath_hw *ah = hw_priv; 23162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 23262306a36Sopenharmony_ci struct ath_softc *sc = (struct ath_softc *) common->priv; 23362306a36Sopenharmony_ci unsigned long flags; 23462306a36Sopenharmony_ci u32 val; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { 23762306a36Sopenharmony_ci spin_lock_irqsave(&sc->sc_serial_rw, flags); 23862306a36Sopenharmony_ci val = __ath9k_reg_rmw(sc, reg_offset, set, clr); 23962306a36Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 24062306a36Sopenharmony_ci } else 24162306a36Sopenharmony_ci val = __ath9k_reg_rmw(sc, reg_offset, set, clr); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return val; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/**************************/ 24762306a36Sopenharmony_ci/* Initialization */ 24862306a36Sopenharmony_ci/**************************/ 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic void ath9k_reg_notifier(struct wiphy *wiphy, 25162306a36Sopenharmony_ci struct regulatory_request *request) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 25462306a36Sopenharmony_ci struct ath_softc *sc = hw->priv; 25562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 25662306a36Sopenharmony_ci struct ath_regulatory *reg = ath9k_hw_regulatory(ah); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ath_reg_notifier_apply(wiphy, request, reg); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* synchronize DFS detector if regulatory domain changed */ 26162306a36Sopenharmony_ci if (sc->dfs_detector != NULL) 26262306a36Sopenharmony_ci sc->dfs_detector->set_dfs_domain(sc->dfs_detector, 26362306a36Sopenharmony_ci request->dfs_region); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Set tx power */ 26662306a36Sopenharmony_ci if (!ah->curchan) 26762306a36Sopenharmony_ci return; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; 27062306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 27162306a36Sopenharmony_ci ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); 27262306a36Sopenharmony_ci ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, 27362306a36Sopenharmony_ci sc->cur_chan->txpower, 27462306a36Sopenharmony_ci &sc->cur_chan->cur_txpower); 27562306a36Sopenharmony_ci ath9k_ps_restore(sc); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * This function will allocate both the DMA descriptor structure, and the 28062306a36Sopenharmony_ci * buffers it contains. These are used to contain the descriptors used 28162306a36Sopenharmony_ci * by the system. 28262306a36Sopenharmony_ci*/ 28362306a36Sopenharmony_ciint ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, 28462306a36Sopenharmony_ci struct list_head *head, const char *name, 28562306a36Sopenharmony_ci int nbuf, int ndesc, bool is_tx) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 28862306a36Sopenharmony_ci u8 *ds; 28962306a36Sopenharmony_ci int i, bsize, desc_len; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", 29262306a36Sopenharmony_ci name, nbuf, ndesc); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci INIT_LIST_HEAD(head); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (is_tx) 29762306a36Sopenharmony_ci desc_len = sc->sc_ah->caps.tx_desc_len; 29862306a36Sopenharmony_ci else 29962306a36Sopenharmony_ci desc_len = sizeof(struct ath_desc); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* ath_desc must be a multiple of DWORDs */ 30262306a36Sopenharmony_ci if ((desc_len % 4) != 0) { 30362306a36Sopenharmony_ci ath_err(common, "ath_desc not DWORD aligned\n"); 30462306a36Sopenharmony_ci BUG_ON((desc_len % 4) != 0); 30562306a36Sopenharmony_ci return -ENOMEM; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci dd->dd_desc_len = desc_len * nbuf * ndesc; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* 31162306a36Sopenharmony_ci * Need additional DMA memory because we can't use 31262306a36Sopenharmony_ci * descriptors that cross the 4K page boundary. Assume 31362306a36Sopenharmony_ci * one skipped descriptor per 4K page. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { 31662306a36Sopenharmony_ci u32 ndesc_skipped = 31762306a36Sopenharmony_ci ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); 31862306a36Sopenharmony_ci u32 dma_len; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci while (ndesc_skipped) { 32162306a36Sopenharmony_ci dma_len = ndesc_skipped * desc_len; 32262306a36Sopenharmony_ci dd->dd_desc_len += dma_len; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* allocate descriptors */ 32962306a36Sopenharmony_ci dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, 33062306a36Sopenharmony_ci &dd->dd_desc_paddr, GFP_KERNEL); 33162306a36Sopenharmony_ci if (!dd->dd_desc) 33262306a36Sopenharmony_ci return -ENOMEM; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ds = dd->dd_desc; 33562306a36Sopenharmony_ci ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", 33662306a36Sopenharmony_ci name, ds, (u32) dd->dd_desc_len, 33762306a36Sopenharmony_ci ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* allocate buffers */ 34062306a36Sopenharmony_ci if (is_tx) { 34162306a36Sopenharmony_ci struct ath_buf *bf; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci bsize = sizeof(struct ath_buf) * nbuf; 34462306a36Sopenharmony_ci bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); 34562306a36Sopenharmony_ci if (!bf) 34662306a36Sopenharmony_ci return -ENOMEM; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { 34962306a36Sopenharmony_ci bf->bf_desc = ds; 35062306a36Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & 35362306a36Sopenharmony_ci ATH9K_HW_CAP_4KB_SPLITTRANS)) { 35462306a36Sopenharmony_ci /* 35562306a36Sopenharmony_ci * Skip descriptor addresses which can cause 4KB 35662306a36Sopenharmony_ci * boundary crossing (addr + length) with a 32 dword 35762306a36Sopenharmony_ci * descriptor fetch. 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_ci while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { 36062306a36Sopenharmony_ci BUG_ON((caddr_t) bf->bf_desc >= 36162306a36Sopenharmony_ci ((caddr_t) dd->dd_desc + 36262306a36Sopenharmony_ci dd->dd_desc_len)); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ds += (desc_len * ndesc); 36562306a36Sopenharmony_ci bf->bf_desc = ds; 36662306a36Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci list_add_tail(&bf->list, head); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci } else { 37262306a36Sopenharmony_ci struct ath_rxbuf *bf; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci bsize = sizeof(struct ath_rxbuf) * nbuf; 37562306a36Sopenharmony_ci bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); 37662306a36Sopenharmony_ci if (!bf) 37762306a36Sopenharmony_ci return -ENOMEM; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { 38062306a36Sopenharmony_ci bf->bf_desc = ds; 38162306a36Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & 38462306a36Sopenharmony_ci ATH9K_HW_CAP_4KB_SPLITTRANS)) { 38562306a36Sopenharmony_ci /* 38662306a36Sopenharmony_ci * Skip descriptor addresses which can cause 4KB 38762306a36Sopenharmony_ci * boundary crossing (addr + length) with a 32 dword 38862306a36Sopenharmony_ci * descriptor fetch. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { 39162306a36Sopenharmony_ci BUG_ON((caddr_t) bf->bf_desc >= 39262306a36Sopenharmony_ci ((caddr_t) dd->dd_desc + 39362306a36Sopenharmony_ci dd->dd_desc_len)); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci ds += (desc_len * ndesc); 39662306a36Sopenharmony_ci bf->bf_desc = ds; 39762306a36Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci list_add_tail(&bf->list, head); 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic int ath9k_init_queues(struct ath_softc *sc) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci int i = 0; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); 41162306a36Sopenharmony_ci sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); 41262306a36Sopenharmony_ci ath_cabq_update(sc); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 41762306a36Sopenharmony_ci sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); 41862306a36Sopenharmony_ci sc->tx.txq_map[i]->mac80211_qnum = i; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void ath9k_init_misc(struct ath_softc *sc) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 42662306a36Sopenharmony_ci int i = 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci timer_setup(&common->ani.timer, ath_ani_calibrate, 0); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci common->last_rssi = ATH_RSSI_DUMMY_MARKER; 43162306a36Sopenharmony_ci eth_broadcast_addr(common->bssidmask); 43262306a36Sopenharmony_ci sc->beacon.slottime = 9; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) 43562306a36Sopenharmony_ci sc->beacon.bslot[i] = NULL; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) 43862306a36Sopenharmony_ci sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci sc->spec_priv.ah = sc->sc_ah; 44162306a36Sopenharmony_ci sc->spec_priv.spec_config.enabled = 0; 44262306a36Sopenharmony_ci sc->spec_priv.spec_config.short_repeat = true; 44362306a36Sopenharmony_ci sc->spec_priv.spec_config.count = 8; 44462306a36Sopenharmony_ci sc->spec_priv.spec_config.endless = false; 44562306a36Sopenharmony_ci sc->spec_priv.spec_config.period = 0xFF; 44662306a36Sopenharmony_ci sc->spec_priv.spec_config.fft_period = 0xF; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void ath9k_init_pcoem_platform(struct ath_softc *sc) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 45262306a36Sopenharmony_ci struct ath9k_hw_capabilities *pCap = &ah->caps; 45362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_ATH9K_PCOEM)) 45662306a36Sopenharmony_ci return; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (common->bus_ops->ath_bus_type != ATH_PCI) 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (sc->driver_data & (ATH9K_PCI_CUS198 | 46262306a36Sopenharmony_ci ATH9K_PCI_CUS230)) { 46362306a36Sopenharmony_ci ah->config.xlna_gpio = 9; 46462306a36Sopenharmony_ci ah->config.xatten_margin_cfg = true; 46562306a36Sopenharmony_ci ah->config.alt_mingainidx = true; 46662306a36Sopenharmony_ci ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88; 46762306a36Sopenharmony_ci sc->ant_comb.low_rssi_thresh = 20; 46862306a36Sopenharmony_ci sc->ant_comb.fast_div_bias = 3; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ath_info(common, "Set parameters for %s\n", 47162306a36Sopenharmony_ci (sc->driver_data & ATH9K_PCI_CUS198) ? 47262306a36Sopenharmony_ci "CUS198" : "CUS230"); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_CUS217) 47662306a36Sopenharmony_ci ath_info(common, "CUS217 card detected\n"); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_CUS252) 47962306a36Sopenharmony_ci ath_info(common, "CUS252 card detected\n"); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_AR9565_1ANT) 48262306a36Sopenharmony_ci ath_info(common, "WB335 1-ANT card detected\n"); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_AR9565_2ANT) 48562306a36Sopenharmony_ci ath_info(common, "WB335 2-ANT card detected\n"); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_KILLER) 48862306a36Sopenharmony_ci ath_info(common, "Killer Wireless card detected\n"); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * Some WB335 cards do not support antenna diversity. Since 49262306a36Sopenharmony_ci * we use a hardcoded value for AR9565 instead of using the 49362306a36Sopenharmony_ci * EEPROM/OTP data, remove the combining feature from 49462306a36Sopenharmony_ci * the HW capabilities bitmap. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci if (sc->driver_data & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) { 49762306a36Sopenharmony_ci if (!(sc->driver_data & ATH9K_PCI_BT_ANT_DIV)) 49862306a36Sopenharmony_ci pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) { 50262306a36Sopenharmony_ci pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV; 50362306a36Sopenharmony_ci ath_info(common, "Set BT/WLAN RX diversity capability\n"); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_D3_L1_WAR) { 50762306a36Sopenharmony_ci ah->config.pcie_waen = 0x0040473b; 50862306a36Sopenharmony_ci ath_info(common, "Enable WAR for ASPM D3/L1\n"); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* 51262306a36Sopenharmony_ci * The default value of pll_pwrsave is 1. 51362306a36Sopenharmony_ci * For certain AR9485 cards, it is set to 0. 51462306a36Sopenharmony_ci * For AR9462, AR9565 it's set to 7. 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci ah->config.pll_pwrsave = 1; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_NO_PLL_PWRSAVE) { 51962306a36Sopenharmony_ci ah->config.pll_pwrsave = 0; 52062306a36Sopenharmony_ci ath_info(common, "Disable PLL PowerSave\n"); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_LED_ACT_HI) 52462306a36Sopenharmony_ci ah->config.led_active_high = true; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, 52862306a36Sopenharmony_ci void *ctx) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct ath9k_eeprom_ctx *ec = ctx; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (eeprom_blob) 53362306a36Sopenharmony_ci ec->ah->eeprom_blob = eeprom_blob; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci complete(&ec->complete); 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int ath9k_eeprom_request(struct ath_softc *sc, const char *name) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct ath9k_eeprom_ctx ec; 54162306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 54262306a36Sopenharmony_ci int err; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* try to load the EEPROM content asynchronously */ 54562306a36Sopenharmony_ci init_completion(&ec.complete); 54662306a36Sopenharmony_ci ec.ah = sc->sc_ah; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci err = request_firmware_nowait(THIS_MODULE, 1, name, sc->dev, GFP_KERNEL, 54962306a36Sopenharmony_ci &ec, ath9k_eeprom_request_cb); 55062306a36Sopenharmony_ci if (err < 0) { 55162306a36Sopenharmony_ci ath_err(ath9k_hw_common(ah), 55262306a36Sopenharmony_ci "EEPROM request failed\n"); 55362306a36Sopenharmony_ci return err; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci wait_for_completion(&ec.complete); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (!ah->eeprom_blob) { 55962306a36Sopenharmony_ci ath_err(ath9k_hw_common(ah), 56062306a36Sopenharmony_ci "Unable to load EEPROM file %s\n", name); 56162306a36Sopenharmony_ci return -EINVAL; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic void ath9k_eeprom_release(struct ath_softc *sc) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci release_firmware(sc->sc_ah->eeprom_blob); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int ath9k_nvmem_request_eeprom(struct ath_softc *sc) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 57562306a36Sopenharmony_ci struct nvmem_cell *cell; 57662306a36Sopenharmony_ci void *buf; 57762306a36Sopenharmony_ci size_t len; 57862306a36Sopenharmony_ci int err; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci cell = devm_nvmem_cell_get(sc->dev, "calibration"); 58162306a36Sopenharmony_ci if (IS_ERR(cell)) { 58262306a36Sopenharmony_ci err = PTR_ERR(cell); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* nvmem cell might not be defined, or the nvmem 58562306a36Sopenharmony_ci * subsystem isn't included. In this case, follow 58662306a36Sopenharmony_ci * the established "just return 0;" convention of 58762306a36Sopenharmony_ci * ath9k_init_platform to say: 58862306a36Sopenharmony_ci * "All good. Nothing to see here. Please go on." 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci if (err == -ENOENT || err == -EOPNOTSUPP) 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci return err; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci buf = nvmem_cell_read(cell, &len); 59762306a36Sopenharmony_ci if (IS_ERR(buf)) 59862306a36Sopenharmony_ci return PTR_ERR(buf); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* run basic sanity checks on the returned nvram cell length. 60162306a36Sopenharmony_ci * That length has to be a multiple of a "u16" (i.e.: & 1). 60262306a36Sopenharmony_ci * Furthermore, it has to be more than "let's say" 512 bytes 60362306a36Sopenharmony_ci * but less than the maximum of AR9300_EEPROM_SIZE (16kb). 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci if ((len & 1) == 1 || len < 512 || len >= AR9300_EEPROM_SIZE) { 60662306a36Sopenharmony_ci kfree(buf); 60762306a36Sopenharmony_ci return -EINVAL; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* devres manages the calibration values release on shutdown */ 61162306a36Sopenharmony_ci ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL); 61262306a36Sopenharmony_ci kfree(buf); 61362306a36Sopenharmony_ci if (!ah->nvmem_blob) 61462306a36Sopenharmony_ci return -ENOMEM; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci ah->nvmem_blob_len = len; 61762306a36Sopenharmony_ci ah->ah_flags &= ~AH_USE_EEPROM; 61862306a36Sopenharmony_ci ah->ah_flags |= AH_NO_EEP_SWAP; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int ath9k_init_platform(struct ath_softc *sc) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct ath9k_platform_data *pdata = sc->dev->platform_data; 62662306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 62762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 62862306a36Sopenharmony_ci int ret; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!pdata) 63162306a36Sopenharmony_ci return 0; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (!pdata->use_eeprom) { 63462306a36Sopenharmony_ci ah->ah_flags &= ~AH_USE_EEPROM; 63562306a36Sopenharmony_ci ah->gpio_mask = pdata->gpio_mask; 63662306a36Sopenharmony_ci ah->gpio_val = pdata->gpio_val; 63762306a36Sopenharmony_ci ah->led_pin = pdata->led_pin; 63862306a36Sopenharmony_ci ah->is_clk_25mhz = pdata->is_clk_25mhz; 63962306a36Sopenharmony_ci ah->get_mac_revision = pdata->get_mac_revision; 64062306a36Sopenharmony_ci ah->external_reset = pdata->external_reset; 64162306a36Sopenharmony_ci ah->disable_2ghz = pdata->disable_2ghz; 64262306a36Sopenharmony_ci ah->disable_5ghz = pdata->disable_5ghz; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (!pdata->endian_check) 64562306a36Sopenharmony_ci ah->ah_flags |= AH_NO_EEP_SWAP; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (pdata->eeprom_name) { 64962306a36Sopenharmony_ci ret = ath9k_eeprom_request(sc, pdata->eeprom_name); 65062306a36Sopenharmony_ci if (ret) 65162306a36Sopenharmony_ci return ret; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (pdata->led_active_high) 65562306a36Sopenharmony_ci ah->config.led_active_high = true; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (pdata->tx_gain_buffalo) 65862306a36Sopenharmony_ci ah->config.tx_gain_buffalo = true; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (pdata->macaddr) 66162306a36Sopenharmony_ci ether_addr_copy(common->macaddr, pdata->macaddr); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic int ath9k_of_init(struct ath_softc *sc) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct device_node *np = sc->dev->of_node; 66962306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 67062306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 67162306a36Sopenharmony_ci enum ath_bus_type bus_type = common->bus_ops->ath_bus_type; 67262306a36Sopenharmony_ci char eeprom_name[100]; 67362306a36Sopenharmony_ci int ret; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (!of_device_is_available(np)) 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ath_dbg(common, CONFIG, "parsing configuration from OF node\n"); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (of_property_read_bool(np, "qca,no-eeprom")) { 68162306a36Sopenharmony_ci /* ath9k-eeprom-<bus>-<id>.bin */ 68262306a36Sopenharmony_ci scnprintf(eeprom_name, sizeof(eeprom_name), 68362306a36Sopenharmony_ci "ath9k-eeprom-%s-%s.bin", 68462306a36Sopenharmony_ci ath_bus_type_to_string(bus_type), dev_name(ah->dev)); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci ret = ath9k_eeprom_request(sc, eeprom_name); 68762306a36Sopenharmony_ci if (ret) 68862306a36Sopenharmony_ci return ret; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ah->ah_flags &= ~AH_USE_EEPROM; 69162306a36Sopenharmony_ci ah->ah_flags |= AH_NO_EEP_SWAP; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci of_get_mac_address(np, common->macaddr); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci return 0; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int ath9k_init_softc(u16 devid, struct ath_softc *sc, 70062306a36Sopenharmony_ci const struct ath_bus_ops *bus_ops) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct ath_hw *ah = NULL; 70362306a36Sopenharmony_ci struct ath9k_hw_capabilities *pCap; 70462306a36Sopenharmony_ci struct ath_common *common; 70562306a36Sopenharmony_ci int ret = 0, i; 70662306a36Sopenharmony_ci int csz = 0; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL); 70962306a36Sopenharmony_ci if (!ah) 71062306a36Sopenharmony_ci return -ENOMEM; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ah->dev = sc->dev; 71362306a36Sopenharmony_ci ah->hw = sc->hw; 71462306a36Sopenharmony_ci ah->hw_version.devid = devid; 71562306a36Sopenharmony_ci ah->ah_flags |= AH_USE_EEPROM; 71662306a36Sopenharmony_ci ah->led_pin = -1; 71762306a36Sopenharmony_ci ah->reg_ops.read = ath9k_ioread32; 71862306a36Sopenharmony_ci ah->reg_ops.multi_read = ath9k_multi_ioread32; 71962306a36Sopenharmony_ci ah->reg_ops.write = ath9k_iowrite32; 72062306a36Sopenharmony_ci ah->reg_ops.rmw = ath9k_reg_rmw; 72162306a36Sopenharmony_ci pCap = &ah->caps; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci common = ath9k_hw_common(ah); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Will be cleared in ath9k_start() */ 72662306a36Sopenharmony_ci set_bit(ATH_OP_INVALID, &common->op_flags); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci sc->sc_ah = ah; 72962306a36Sopenharmony_ci sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); 73062306a36Sopenharmony_ci sc->tx99_power = MAX_RATE_POWER + 1; 73162306a36Sopenharmony_ci init_waitqueue_head(&sc->tx_wait); 73262306a36Sopenharmony_ci sc->cur_chan = &sc->chanctx[0]; 73362306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 73462306a36Sopenharmony_ci sc->cur_chan->hw_queue_base = 0; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci common->ops = &ah->reg_ops; 73762306a36Sopenharmony_ci common->bus_ops = bus_ops; 73862306a36Sopenharmony_ci common->ps_ops = &ath9k_ps_ops; 73962306a36Sopenharmony_ci common->ah = ah; 74062306a36Sopenharmony_ci common->hw = sc->hw; 74162306a36Sopenharmony_ci common->priv = sc; 74262306a36Sopenharmony_ci common->debug_mask = ath9k_debug; 74362306a36Sopenharmony_ci common->btcoex_enabled = ath9k_btcoex_enable == 1; 74462306a36Sopenharmony_ci common->disable_ani = false; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* 74762306a36Sopenharmony_ci * Platform quirks. 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_ci ath9k_init_pcoem_platform(sc); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci ret = ath9k_init_platform(sc); 75262306a36Sopenharmony_ci if (ret) 75362306a36Sopenharmony_ci return ret; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci ret = ath9k_of_init(sc); 75662306a36Sopenharmony_ci if (ret) 75762306a36Sopenharmony_ci return ret; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci ret = ath9k_nvmem_request_eeprom(sc); 76062306a36Sopenharmony_ci if (ret) 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (ath9k_led_active_high != -1) 76462306a36Sopenharmony_ci ah->config.led_active_high = ath9k_led_active_high == 1; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* 76762306a36Sopenharmony_ci * Enable WLAN/BT RX Antenna diversity only when: 76862306a36Sopenharmony_ci * 76962306a36Sopenharmony_ci * - BTCOEX is disabled. 77062306a36Sopenharmony_ci * - the user manually requests the feature. 77162306a36Sopenharmony_ci * - the HW cap is set using the platform data. 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci if (!common->btcoex_enabled && ath9k_bt_ant_diversity && 77462306a36Sopenharmony_ci (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) 77562306a36Sopenharmony_ci common->bt_ant_diversity = 1; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci spin_lock_init(&common->cc_lock); 77862306a36Sopenharmony_ci spin_lock_init(&sc->intr_lock); 77962306a36Sopenharmony_ci spin_lock_init(&sc->sc_serial_rw); 78062306a36Sopenharmony_ci spin_lock_init(&sc->sc_pm_lock); 78162306a36Sopenharmony_ci spin_lock_init(&sc->chan_lock); 78262306a36Sopenharmony_ci mutex_init(&sc->mutex); 78362306a36Sopenharmony_ci tasklet_setup(&sc->intr_tq, ath9k_tasklet); 78462306a36Sopenharmony_ci tasklet_setup(&sc->bcon_tasklet, ath9k_beacon_tasklet); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci timer_setup(&sc->sleep_timer, ath_ps_full_sleep, 0); 78762306a36Sopenharmony_ci INIT_WORK(&sc->hw_reset_work, ath_reset_work); 78862306a36Sopenharmony_ci INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); 78962306a36Sopenharmony_ci INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); 79062306a36Sopenharmony_ci INIT_DELAYED_WORK(&sc->hw_check_work, ath_hw_check_work); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci ath9k_init_channel_context(sc); 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * Cache line size is used to size and align various 79662306a36Sopenharmony_ci * structures used to communicate with the hardware. 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ci ath_read_cachesize(common, &csz); 79962306a36Sopenharmony_ci common->cachelsz = csz << 2; /* convert to bytes */ 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* Initializes the hardware for all supported chipsets */ 80262306a36Sopenharmony_ci ret = ath9k_hw_init(ah); 80362306a36Sopenharmony_ci if (ret) 80462306a36Sopenharmony_ci goto err_hw; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci ret = ath9k_init_queues(sc); 80762306a36Sopenharmony_ci if (ret) 80862306a36Sopenharmony_ci goto err_queues; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci ret = ath9k_init_btcoex(sc); 81162306a36Sopenharmony_ci if (ret) 81262306a36Sopenharmony_ci goto err_btcoex; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci ret = ath9k_cmn_init_channels_rates(common); 81562306a36Sopenharmony_ci if (ret) 81662306a36Sopenharmony_ci goto err_btcoex; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci ret = ath9k_init_p2p(sc); 81962306a36Sopenharmony_ci if (ret) 82062306a36Sopenharmony_ci goto err_btcoex; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci ath9k_cmn_init_crypto(sc->sc_ah); 82362306a36Sopenharmony_ci ath9k_init_misc(sc); 82462306a36Sopenharmony_ci ath_chanctx_init(sc); 82562306a36Sopenharmony_ci ath9k_offchannel_init(sc); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (common->bus_ops->aspm_init) 82862306a36Sopenharmony_ci common->bus_ops->aspm_init(common); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci return 0; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cierr_btcoex: 83362306a36Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) 83462306a36Sopenharmony_ci if (ATH_TXQ_SETUP(sc, i)) 83562306a36Sopenharmony_ci ath_tx_cleanupq(sc, &sc->tx.txq[i]); 83662306a36Sopenharmony_cierr_queues: 83762306a36Sopenharmony_ci ath9k_hw_deinit(ah); 83862306a36Sopenharmony_cierr_hw: 83962306a36Sopenharmony_ci ath9k_eeprom_release(sc); 84062306a36Sopenharmony_ci dev_kfree_skb_any(sc->tx99_skb); 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic void ath9k_init_band_txpower(struct ath_softc *sc, int band) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 84762306a36Sopenharmony_ci struct ieee80211_channel *chan; 84862306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 84962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 85062306a36Sopenharmony_ci struct cfg80211_chan_def chandef; 85162306a36Sopenharmony_ci int i; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci sband = &common->sbands[band]; 85462306a36Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 85562306a36Sopenharmony_ci chan = &sband->channels[i]; 85662306a36Sopenharmony_ci ah->curchan = &ah->channels[chan->hw_value]; 85762306a36Sopenharmony_ci cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); 85862306a36Sopenharmony_ci ath9k_cmn_get_channel(sc->hw, ah, &chandef); 85962306a36Sopenharmony_ci ath9k_hw_set_txpowerlimit(ah, MAX_COMBINED_POWER, true); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void ath9k_init_txpower_limits(struct ath_softc *sc) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 86662306a36Sopenharmony_ci struct ath9k_channel *curchan = ah->curchan; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 86962306a36Sopenharmony_ci ath9k_init_band_txpower(sc, NL80211_BAND_2GHZ); 87062306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 87162306a36Sopenharmony_ci ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci ah->curchan = curchan; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic const struct ieee80211_iface_limit if_limits[] = { 87762306a36Sopenharmony_ci { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, 87862306a36Sopenharmony_ci { .max = 8, .types = 87962306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 88062306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 88162306a36Sopenharmony_ci#endif 88262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) }, 88362306a36Sopenharmony_ci { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | 88462306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) }, 88562306a36Sopenharmony_ci}; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic const struct ieee80211_iface_limit if_limits_multi[] = { 89062306a36Sopenharmony_ci { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | 89162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 89262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 89362306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) }, 89462306a36Sopenharmony_ci { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, 89562306a36Sopenharmony_ci { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, 89662306a36Sopenharmony_ci}; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic const struct ieee80211_iface_combination if_comb_multi[] = { 89962306a36Sopenharmony_ci { 90062306a36Sopenharmony_ci .limits = if_limits_multi, 90162306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(if_limits_multi), 90262306a36Sopenharmony_ci .max_interfaces = 3, 90362306a36Sopenharmony_ci .num_different_channels = 2, 90462306a36Sopenharmony_ci .beacon_int_infra_match = true, 90562306a36Sopenharmony_ci }, 90662306a36Sopenharmony_ci}; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic const struct ieee80211_iface_combination if_comb[] = { 91162306a36Sopenharmony_ci { 91262306a36Sopenharmony_ci .limits = if_limits, 91362306a36Sopenharmony_ci .n_limits = ARRAY_SIZE(if_limits), 91462306a36Sopenharmony_ci .max_interfaces = 2048, 91562306a36Sopenharmony_ci .num_different_channels = 1, 91662306a36Sopenharmony_ci .beacon_int_infra_match = true, 91762306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_DFS_CERTIFIED 91862306a36Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 91962306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 92062306a36Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40), 92162306a36Sopenharmony_ci#endif 92262306a36Sopenharmony_ci }, 92362306a36Sopenharmony_ci}; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 92662306a36Sopenharmony_cistatic void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 92962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 93262306a36Sopenharmony_ci return; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci ieee80211_hw_set(hw, QUEUE_CONTROL); 93562306a36Sopenharmony_ci hw->queues = ATH9K_NUM_TX_QUEUES; 93662306a36Sopenharmony_ci hw->offchannel_tx_hw_queue = hw->queues - 1; 93762306a36Sopenharmony_ci hw->wiphy->iface_combinations = if_comb_multi; 93862306a36Sopenharmony_ci hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); 93962306a36Sopenharmony_ci hw->wiphy->max_scan_ssids = 255; 94062306a36Sopenharmony_ci hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 94162306a36Sopenharmony_ci hw->wiphy->max_remain_on_channel_duration = 10000; 94262306a36Sopenharmony_ci hw->chanctx_data_size = sizeof(void *); 94362306a36Sopenharmony_ci hw->extra_beacon_tailroom = 94462306a36Sopenharmony_ci sizeof(struct ieee80211_p2p_noa_attr) + 9; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 95362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 95662306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 95762306a36Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 95862306a36Sopenharmony_ci ieee80211_hw_set(hw, SPECTRUM_MGMT); 95962306a36Sopenharmony_ci ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 96062306a36Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 96162306a36Sopenharmony_ci ieee80211_hw_set(hw, RX_INCLUDES_FCS); 96262306a36Sopenharmony_ci ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 96362306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 96462306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (ath9k_ps_enable) 96762306a36Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { 97062306a36Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) 97362306a36Sopenharmony_ci hw->radiotap_mcs_details |= 97462306a36Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_STBC; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) 97862306a36Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 98162306a36Sopenharmony_ci NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 98262306a36Sopenharmony_ci NL80211_FEATURE_P2P_GO_CTWIN; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_ATH9K_TX99)) { 98562306a36Sopenharmony_ci hw->wiphy->interface_modes = 98662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | 98762306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 98862306a36Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 98962306a36Sopenharmony_ci BIT(NL80211_IFTYPE_STATION) | 99062306a36Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC) | 99162306a36Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 99262306a36Sopenharmony_ci BIT(NL80211_IFTYPE_OCB); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (ath9k_is_chanctx_enabled()) 99562306a36Sopenharmony_ci hw->wiphy->interface_modes |= 99662306a36Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci hw->wiphy->iface_combinations = if_comb; 99962306a36Sopenharmony_ci hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 100562306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; 100662306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 100762306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; 100862306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; 100962306a36Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci hw->queues = 4; 101262306a36Sopenharmony_ci hw->max_rates = 4; 101362306a36Sopenharmony_ci hw->max_listen_interval = 10; 101462306a36Sopenharmony_ci hw->max_rate_tries = 10; 101562306a36Sopenharmony_ci hw->sta_data_size = sizeof(struct ath_node); 101662306a36Sopenharmony_ci hw->vif_data_size = sizeof(struct ath_vif); 101762306a36Sopenharmony_ci hw->txq_data_size = sizeof(struct ath_atx_tid); 101862306a36Sopenharmony_ci hw->extra_tx_headroom = 4; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; 102162306a36Sopenharmony_ci hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* single chain devices with rx diversity */ 102462306a36Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) 102562306a36Sopenharmony_ci hw->wiphy->available_antennas_rx = BIT(0) | BIT(1); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci sc->ant_rx = hw->wiphy->available_antennas_rx; 102862306a36Sopenharmony_ci sc->ant_tx = hw->wiphy->available_antennas_tx; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 103162306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_2GHZ] = 103262306a36Sopenharmony_ci &common->sbands[NL80211_BAND_2GHZ]; 103362306a36Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 103462306a36Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_5GHZ] = 103562306a36Sopenharmony_ci &common->sbands[NL80211_BAND_5GHZ]; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 103862306a36Sopenharmony_ci ath9k_set_mcc_capab(sc, hw); 103962306a36Sopenharmony_ci#endif 104062306a36Sopenharmony_ci ath9k_init_wow(hw); 104162306a36Sopenharmony_ci ath9k_cmn_reload_chainmask(ah); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, common->macaddr); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 104662306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 104762306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, 104862306a36Sopenharmony_ci NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); 104962306a36Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ciint ath9k_init_device(u16 devid, struct ath_softc *sc, 105362306a36Sopenharmony_ci const struct ath_bus_ops *bus_ops) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 105662306a36Sopenharmony_ci struct ath_common *common; 105762306a36Sopenharmony_ci struct ath_hw *ah; 105862306a36Sopenharmony_ci int error = 0; 105962306a36Sopenharmony_ci struct ath_regulatory *reg; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* Bring up device */ 106262306a36Sopenharmony_ci error = ath9k_init_softc(devid, sc, bus_ops); 106362306a36Sopenharmony_ci if (error) 106462306a36Sopenharmony_ci return error; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci ah = sc->sc_ah; 106762306a36Sopenharmony_ci common = ath9k_hw_common(ah); 106862306a36Sopenharmony_ci ath9k_set_hw_capab(sc, hw); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Initialize regulatory */ 107162306a36Sopenharmony_ci error = ath_regd_init(&common->regulatory, sc->hw->wiphy, 107262306a36Sopenharmony_ci ath9k_reg_notifier); 107362306a36Sopenharmony_ci if (error) 107462306a36Sopenharmony_ci goto deinit; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci reg = &common->regulatory; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* Setup TX DMA */ 107962306a36Sopenharmony_ci error = ath_tx_init(sc, ATH_TXBUF); 108062306a36Sopenharmony_ci if (error != 0) 108162306a36Sopenharmony_ci goto deinit; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Setup RX DMA */ 108462306a36Sopenharmony_ci error = ath_rx_init(sc, ATH_RXBUF); 108562306a36Sopenharmony_ci if (error != 0) 108662306a36Sopenharmony_ci goto deinit; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci ath9k_init_txpower_limits(sc); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci#ifdef CONFIG_MAC80211_LEDS 109162306a36Sopenharmony_ci /* must be initialized before ieee80211_register_hw */ 109262306a36Sopenharmony_ci sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, 109362306a36Sopenharmony_ci IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink, 109462306a36Sopenharmony_ci ARRAY_SIZE(ath9k_tpt_blink)); 109562306a36Sopenharmony_ci#endif 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci wiphy_read_of_freq_limits(hw->wiphy); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci /* Register with mac80211 */ 110062306a36Sopenharmony_ci error = ieee80211_register_hw(hw); 110162306a36Sopenharmony_ci if (error) 110262306a36Sopenharmony_ci goto rx_cleanup; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci error = ath9k_init_debug(ah); 110562306a36Sopenharmony_ci if (error) { 110662306a36Sopenharmony_ci ath_err(common, "Unable to create debugfs files\n"); 110762306a36Sopenharmony_ci goto unregister; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Handle world regulatory */ 111162306a36Sopenharmony_ci if (!ath_is_world_regd(reg)) { 111262306a36Sopenharmony_ci error = regulatory_hint(hw->wiphy, reg->alpha2); 111362306a36Sopenharmony_ci if (error) 111462306a36Sopenharmony_ci goto debug_cleanup; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ath_init_leds(sc); 111862306a36Sopenharmony_ci ath_start_rfkill_poll(sc); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci return 0; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cidebug_cleanup: 112362306a36Sopenharmony_ci ath9k_deinit_debug(sc); 112462306a36Sopenharmony_ciunregister: 112562306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 112662306a36Sopenharmony_cirx_cleanup: 112762306a36Sopenharmony_ci ath_rx_cleanup(sc); 112862306a36Sopenharmony_cideinit: 112962306a36Sopenharmony_ci ath9k_deinit_softc(sc); 113062306a36Sopenharmony_ci return error; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci/*****************************/ 113462306a36Sopenharmony_ci/* De-Initialization */ 113562306a36Sopenharmony_ci/*****************************/ 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic void ath9k_deinit_softc(struct ath_softc *sc) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci int i = 0; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci ath9k_deinit_p2p(sc); 114262306a36Sopenharmony_ci ath9k_deinit_btcoex(sc); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) 114562306a36Sopenharmony_ci if (ATH_TXQ_SETUP(sc, i)) 114662306a36Sopenharmony_ci ath_tx_cleanupq(sc, &sc->tx.txq[i]); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci del_timer_sync(&sc->sleep_timer); 114962306a36Sopenharmony_ci ath9k_hw_deinit(sc->sc_ah); 115062306a36Sopenharmony_ci if (sc->dfs_detector != NULL) 115162306a36Sopenharmony_ci sc->dfs_detector->exit(sc->dfs_detector); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci ath9k_eeprom_release(sc); 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_civoid ath9k_deinit_device(struct ath_softc *sc) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci ath9k_ps_wakeup(sc); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci wiphy_rfkill_stop_polling(sc->hw->wiphy); 116362306a36Sopenharmony_ci ath_deinit_leds(sc); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci ath9k_ps_restore(sc); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci ath9k_deinit_debug(sc); 116862306a36Sopenharmony_ci ath9k_deinit_wow(hw); 116962306a36Sopenharmony_ci ieee80211_unregister_hw(hw); 117062306a36Sopenharmony_ci ath_rx_cleanup(sc); 117162306a36Sopenharmony_ci ath9k_deinit_softc(sc); 117262306a36Sopenharmony_ci} 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/************************/ 117562306a36Sopenharmony_ci/* Module Hooks */ 117662306a36Sopenharmony_ci/************************/ 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic int __init ath9k_init(void) 117962306a36Sopenharmony_ci{ 118062306a36Sopenharmony_ci int error; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci error = ath_pci_init(); 118362306a36Sopenharmony_ci if (error < 0) { 118462306a36Sopenharmony_ci pr_err("No PCI devices found, driver not installed\n"); 118562306a36Sopenharmony_ci error = -ENODEV; 118662306a36Sopenharmony_ci goto err_out; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci error = ath_ahb_init(); 119062306a36Sopenharmony_ci if (error < 0) { 119162306a36Sopenharmony_ci error = -ENODEV; 119262306a36Sopenharmony_ci goto err_pci_exit; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci dmi_check_system(ath9k_quirks); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci return 0; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci err_pci_exit: 120062306a36Sopenharmony_ci ath_pci_exit(); 120162306a36Sopenharmony_ci err_out: 120262306a36Sopenharmony_ci return error; 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_cimodule_init(ath9k_init); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic void __exit ath9k_exit(void) 120762306a36Sopenharmony_ci{ 120862306a36Sopenharmony_ci is_ath9k_unloaded = true; 120962306a36Sopenharmony_ci ath_ahb_exit(); 121062306a36Sopenharmony_ci ath_pci_exit(); 121162306a36Sopenharmony_ci pr_info("%s: Driver unloaded\n", dev_info); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_cimodule_exit(ath9k_exit); 1214