18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/ath9k_platform.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/of.h> 248c2ecf20Sopenharmony_ci#include <linux/of_net.h> 258c2ecf20Sopenharmony_ci#include <linux/relay.h> 268c2ecf20Sopenharmony_ci#include <linux/dmi.h> 278c2ecf20Sopenharmony_ci#include <net/ieee80211_radiotap.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "ath9k.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct ath9k_eeprom_ctx { 328c2ecf20Sopenharmony_ci struct completion complete; 338c2ecf20Sopenharmony_ci struct ath_hw *ah; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic char *dev_info = "ath9k"; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Atheros Communications"); 398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); 408c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); 418c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic unsigned int ath9k_debug = ATH_DBG_DEFAULT; 448c2ecf20Sopenharmony_cimodule_param_named(debug, ath9k_debug, uint, 0); 458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debugging mask"); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ciint ath9k_modparam_nohwcrypt; 488c2ecf20Sopenharmony_cimodule_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); 498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ciint ath9k_led_blink; 528c2ecf20Sopenharmony_cimodule_param_named(blink, ath9k_led_blink, int, 0444); 538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(blink, "Enable LED blink on activity"); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int ath9k_led_active_high = -1; 568c2ecf20Sopenharmony_cimodule_param_named(led_active_high, ath9k_led_active_high, int, 0444); 578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(led_active_high, "Invert LED polarity"); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int ath9k_btcoex_enable; 608c2ecf20Sopenharmony_cimodule_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444); 618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence"); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int ath9k_bt_ant_diversity; 648c2ecf20Sopenharmony_cimodule_param_named(bt_ant_diversity, ath9k_bt_ant_diversity, int, 0444); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bt_ant_diversity, "Enable WLAN/BT RX antenna diversity"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic int ath9k_ps_enable; 688c2ecf20Sopenharmony_cimodule_param_named(ps_enable, ath9k_ps_enable, int, 0444); 698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave"); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint ath9k_use_chanctx; 748c2ecf20Sopenharmony_cimodule_param_named(use_chanctx, ath9k_use_chanctx, int, 0444); 758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_chanctx, "Enable channel context for concurrency"); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint ath9k_use_msi; 808c2ecf20Sopenharmony_cimodule_param_named(use_msi, ath9k_use_msi, int, 0444); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_msi, "Use MSI instead of INTx if possible"); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cibool is_ath9k_unloaded; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_LEDS 868c2ecf20Sopenharmony_cistatic const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { 878c2ecf20Sopenharmony_ci { .throughput = 0 * 1024, .blink_time = 334 }, 888c2ecf20Sopenharmony_ci { .throughput = 1 * 1024, .blink_time = 260 }, 898c2ecf20Sopenharmony_ci { .throughput = 5 * 1024, .blink_time = 220 }, 908c2ecf20Sopenharmony_ci { .throughput = 10 * 1024, .blink_time = 190 }, 918c2ecf20Sopenharmony_ci { .throughput = 20 * 1024, .blink_time = 170 }, 928c2ecf20Sopenharmony_ci { .throughput = 50 * 1024, .blink_time = 150 }, 938c2ecf20Sopenharmony_ci { .throughput = 70 * 1024, .blink_time = 130 }, 948c2ecf20Sopenharmony_ci { .throughput = 100 * 1024, .blink_time = 110 }, 958c2ecf20Sopenharmony_ci { .throughput = 200 * 1024, .blink_time = 80 }, 968c2ecf20Sopenharmony_ci { .throughput = 300 * 1024, .blink_time = 50 }, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int __init set_use_msi(const struct dmi_system_id *dmi) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci ath9k_use_msi = 1; 1038c2ecf20Sopenharmony_ci return 1; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic const struct dmi_system_id ath9k_quirks[] __initconst = { 1078c2ecf20Sopenharmony_ci { 1088c2ecf20Sopenharmony_ci .callback = set_use_msi, 1098c2ecf20Sopenharmony_ci .ident = "Dell Inspiron 24-3460", 1108c2ecf20Sopenharmony_ci .matches = { 1118c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1128c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 24-3460"), 1138c2ecf20Sopenharmony_ci }, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci { 1168c2ecf20Sopenharmony_ci .callback = set_use_msi, 1178c2ecf20Sopenharmony_ci .ident = "Dell Vostro 3262", 1188c2ecf20Sopenharmony_ci .matches = { 1198c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1208c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3262"), 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci }, 1238c2ecf20Sopenharmony_ci { 1248c2ecf20Sopenharmony_ci .callback = set_use_msi, 1258c2ecf20Sopenharmony_ci .ident = "Dell Inspiron 3472", 1268c2ecf20Sopenharmony_ci .matches = { 1278c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1288c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3472"), 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci }, 1318c2ecf20Sopenharmony_ci { 1328c2ecf20Sopenharmony_ci .callback = set_use_msi, 1338c2ecf20Sopenharmony_ci .ident = "Dell Vostro 15-3572", 1348c2ecf20Sopenharmony_ci .matches = { 1358c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1368c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 15-3572"), 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci }, 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci .callback = set_use_msi, 1418c2ecf20Sopenharmony_ci .ident = "Dell Inspiron 14-3473", 1428c2ecf20Sopenharmony_ci .matches = { 1438c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1448c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 14-3473"), 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci {} 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void ath9k_deinit_softc(struct ath_softc *sc); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void ath9k_op_ps_wakeup(struct ath_common *common) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci ath9k_ps_wakeup((struct ath_softc *) common->priv); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void ath9k_op_ps_restore(struct ath_common *common) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci ath9k_ps_restore((struct ath_softc *) common->priv); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic const struct ath_ps_ops ath9k_ps_ops = { 1638c2ecf20Sopenharmony_ci .wakeup = ath9k_op_ps_wakeup, 1648c2ecf20Sopenharmony_ci .restore = ath9k_op_ps_restore, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* 1688c2ecf20Sopenharmony_ci * Read and write, they both share the same lock. We do this to serialize 1698c2ecf20Sopenharmony_ci * reads and writes on Atheros 802.11n PCI devices only. This is required 1708c2ecf20Sopenharmony_ci * as the FIFO on these devices can only accept sanely 2 requests. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct ath_hw *ah = hw_priv; 1768c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 1778c2ecf20Sopenharmony_ci struct ath_softc *sc = (struct ath_softc *) common->priv; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { 1808c2ecf20Sopenharmony_ci unsigned long flags; 1818c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->sc_serial_rw, flags); 1828c2ecf20Sopenharmony_ci iowrite32(val, sc->mem + reg_offset); 1838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 1848c2ecf20Sopenharmony_ci } else 1858c2ecf20Sopenharmony_ci iowrite32(val, sc->mem + reg_offset); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct ath_hw *ah = hw_priv; 1918c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 1928c2ecf20Sopenharmony_ci struct ath_softc *sc = (struct ath_softc *) common->priv; 1938c2ecf20Sopenharmony_ci u32 val; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { 1968c2ecf20Sopenharmony_ci unsigned long flags; 1978c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->sc_serial_rw, flags); 1988c2ecf20Sopenharmony_ci val = ioread32(sc->mem + reg_offset); 1998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 2008c2ecf20Sopenharmony_ci } else 2018c2ecf20Sopenharmony_ci val = ioread32(sc->mem + reg_offset); 2028c2ecf20Sopenharmony_ci return val; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void ath9k_multi_ioread32(void *hw_priv, u32 *addr, 2068c2ecf20Sopenharmony_ci u32 *val, u16 count) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci int i; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 2118c2ecf20Sopenharmony_ci val[i] = ath9k_ioread32(hw_priv, addr[i]); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic unsigned int __ath9k_reg_rmw(struct ath_softc *sc, u32 reg_offset, 2168c2ecf20Sopenharmony_ci u32 set, u32 clr) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci u32 val; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci val = ioread32(sc->mem + reg_offset); 2218c2ecf20Sopenharmony_ci val &= ~clr; 2228c2ecf20Sopenharmony_ci val |= set; 2238c2ecf20Sopenharmony_ci iowrite32(val, sc->mem + reg_offset); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return val; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct ath_hw *ah = hw_priv; 2318c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 2328c2ecf20Sopenharmony_ci struct ath_softc *sc = (struct ath_softc *) common->priv; 2338c2ecf20Sopenharmony_ci unsigned long flags; 2348c2ecf20Sopenharmony_ci u32 val; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { 2378c2ecf20Sopenharmony_ci spin_lock_irqsave(&sc->sc_serial_rw, flags); 2388c2ecf20Sopenharmony_ci val = __ath9k_reg_rmw(sc, reg_offset, set, clr); 2398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sc->sc_serial_rw, flags); 2408c2ecf20Sopenharmony_ci } else 2418c2ecf20Sopenharmony_ci val = __ath9k_reg_rmw(sc, reg_offset, set, clr); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return val; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/**************************/ 2478c2ecf20Sopenharmony_ci/* Initialization */ 2488c2ecf20Sopenharmony_ci/**************************/ 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void ath9k_reg_notifier(struct wiphy *wiphy, 2518c2ecf20Sopenharmony_ci struct regulatory_request *request) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); 2548c2ecf20Sopenharmony_ci struct ath_softc *sc = hw->priv; 2558c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 2568c2ecf20Sopenharmony_ci struct ath_regulatory *reg = ath9k_hw_regulatory(ah); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ath_reg_notifier_apply(wiphy, request, reg); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* synchronize DFS detector if regulatory domain changed */ 2618c2ecf20Sopenharmony_ci if (sc->dfs_detector != NULL) 2628c2ecf20Sopenharmony_ci sc->dfs_detector->set_dfs_domain(sc->dfs_detector, 2638c2ecf20Sopenharmony_ci request->dfs_region); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Set tx power */ 2668c2ecf20Sopenharmony_ci if (!ah->curchan) 2678c2ecf20Sopenharmony_ci return; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; 2708c2ecf20Sopenharmony_ci ath9k_ps_wakeup(sc); 2718c2ecf20Sopenharmony_ci ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); 2728c2ecf20Sopenharmony_ci ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, 2738c2ecf20Sopenharmony_ci sc->cur_chan->txpower, 2748c2ecf20Sopenharmony_ci &sc->cur_chan->cur_txpower); 2758c2ecf20Sopenharmony_ci ath9k_ps_restore(sc); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* 2798c2ecf20Sopenharmony_ci * This function will allocate both the DMA descriptor structure, and the 2808c2ecf20Sopenharmony_ci * buffers it contains. These are used to contain the descriptors used 2818c2ecf20Sopenharmony_ci * by the system. 2828c2ecf20Sopenharmony_ci*/ 2838c2ecf20Sopenharmony_ciint ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, 2848c2ecf20Sopenharmony_ci struct list_head *head, const char *name, 2858c2ecf20Sopenharmony_ci int nbuf, int ndesc, bool is_tx) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 2888c2ecf20Sopenharmony_ci u8 *ds; 2898c2ecf20Sopenharmony_ci int i, bsize, desc_len; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n", 2928c2ecf20Sopenharmony_ci name, nbuf, ndesc); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(head); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (is_tx) 2978c2ecf20Sopenharmony_ci desc_len = sc->sc_ah->caps.tx_desc_len; 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci desc_len = sizeof(struct ath_desc); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* ath_desc must be a multiple of DWORDs */ 3028c2ecf20Sopenharmony_ci if ((desc_len % 4) != 0) { 3038c2ecf20Sopenharmony_ci ath_err(common, "ath_desc not DWORD aligned\n"); 3048c2ecf20Sopenharmony_ci BUG_ON((desc_len % 4) != 0); 3058c2ecf20Sopenharmony_ci return -ENOMEM; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci dd->dd_desc_len = desc_len * nbuf * ndesc; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * Need additional DMA memory because we can't use 3128c2ecf20Sopenharmony_ci * descriptors that cross the 4K page boundary. Assume 3138c2ecf20Sopenharmony_ci * one skipped descriptor per 4K page. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { 3168c2ecf20Sopenharmony_ci u32 ndesc_skipped = 3178c2ecf20Sopenharmony_ci ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); 3188c2ecf20Sopenharmony_ci u32 dma_len; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci while (ndesc_skipped) { 3218c2ecf20Sopenharmony_ci dma_len = ndesc_skipped * desc_len; 3228c2ecf20Sopenharmony_ci dd->dd_desc_len += dma_len; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* allocate descriptors */ 3298c2ecf20Sopenharmony_ci dd->dd_desc = dmam_alloc_coherent(sc->dev, dd->dd_desc_len, 3308c2ecf20Sopenharmony_ci &dd->dd_desc_paddr, GFP_KERNEL); 3318c2ecf20Sopenharmony_ci if (!dd->dd_desc) 3328c2ecf20Sopenharmony_ci return -ENOMEM; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ds = dd->dd_desc; 3358c2ecf20Sopenharmony_ci ath_dbg(common, CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", 3368c2ecf20Sopenharmony_ci name, ds, (u32) dd->dd_desc_len, 3378c2ecf20Sopenharmony_ci ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* allocate buffers */ 3408c2ecf20Sopenharmony_ci if (is_tx) { 3418c2ecf20Sopenharmony_ci struct ath_buf *bf; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci bsize = sizeof(struct ath_buf) * nbuf; 3448c2ecf20Sopenharmony_ci bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); 3458c2ecf20Sopenharmony_ci if (!bf) 3468c2ecf20Sopenharmony_ci return -ENOMEM; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { 3498c2ecf20Sopenharmony_ci bf->bf_desc = ds; 3508c2ecf20Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & 3538c2ecf20Sopenharmony_ci ATH9K_HW_CAP_4KB_SPLITTRANS)) { 3548c2ecf20Sopenharmony_ci /* 3558c2ecf20Sopenharmony_ci * Skip descriptor addresses which can cause 4KB 3568c2ecf20Sopenharmony_ci * boundary crossing (addr + length) with a 32 dword 3578c2ecf20Sopenharmony_ci * descriptor fetch. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { 3608c2ecf20Sopenharmony_ci BUG_ON((caddr_t) bf->bf_desc >= 3618c2ecf20Sopenharmony_ci ((caddr_t) dd->dd_desc + 3628c2ecf20Sopenharmony_ci dd->dd_desc_len)); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ds += (desc_len * ndesc); 3658c2ecf20Sopenharmony_ci bf->bf_desc = ds; 3668c2ecf20Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci list_add_tail(&bf->list, head); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } else { 3728c2ecf20Sopenharmony_ci struct ath_rxbuf *bf; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci bsize = sizeof(struct ath_rxbuf) * nbuf; 3758c2ecf20Sopenharmony_ci bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL); 3768c2ecf20Sopenharmony_ci if (!bf) 3778c2ecf20Sopenharmony_ci return -ENOMEM; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) { 3808c2ecf20Sopenharmony_ci bf->bf_desc = ds; 3818c2ecf20Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (!(sc->sc_ah->caps.hw_caps & 3848c2ecf20Sopenharmony_ci ATH9K_HW_CAP_4KB_SPLITTRANS)) { 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * Skip descriptor addresses which can cause 4KB 3878c2ecf20Sopenharmony_ci * boundary crossing (addr + length) with a 32 dword 3888c2ecf20Sopenharmony_ci * descriptor fetch. 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { 3918c2ecf20Sopenharmony_ci BUG_ON((caddr_t) bf->bf_desc >= 3928c2ecf20Sopenharmony_ci ((caddr_t) dd->dd_desc + 3938c2ecf20Sopenharmony_ci dd->dd_desc_len)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci ds += (desc_len * ndesc); 3968c2ecf20Sopenharmony_ci bf->bf_desc = ds; 3978c2ecf20Sopenharmony_ci bf->bf_daddr = DS2PHYS(dd, ds); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci list_add_tail(&bf->list, head); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int ath9k_init_queues(struct ath_softc *sc) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci int i = 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); 4118c2ecf20Sopenharmony_ci sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); 4128c2ecf20Sopenharmony_ci ath_cabq_update(sc); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci for (i = 0; i < IEEE80211_NUM_ACS; i++) { 4178c2ecf20Sopenharmony_ci sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); 4188c2ecf20Sopenharmony_ci sc->tx.txq_map[i]->mac80211_qnum = i; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic void ath9k_init_misc(struct ath_softc *sc) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(sc->sc_ah); 4268c2ecf20Sopenharmony_ci int i = 0; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci timer_setup(&common->ani.timer, ath_ani_calibrate, 0); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci common->last_rssi = ATH_RSSI_DUMMY_MARKER; 4318c2ecf20Sopenharmony_ci eth_broadcast_addr(common->bssidmask); 4328c2ecf20Sopenharmony_ci sc->beacon.slottime = 9; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) 4358c2ecf20Sopenharmony_ci sc->beacon.bslot[i] = NULL; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) 4388c2ecf20Sopenharmony_ci sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci sc->spec_priv.ah = sc->sc_ah; 4418c2ecf20Sopenharmony_ci sc->spec_priv.spec_config.enabled = 0; 4428c2ecf20Sopenharmony_ci sc->spec_priv.spec_config.short_repeat = true; 4438c2ecf20Sopenharmony_ci sc->spec_priv.spec_config.count = 8; 4448c2ecf20Sopenharmony_ci sc->spec_priv.spec_config.endless = false; 4458c2ecf20Sopenharmony_ci sc->spec_priv.spec_config.period = 0xFF; 4468c2ecf20Sopenharmony_ci sc->spec_priv.spec_config.fft_period = 0xF; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic void ath9k_init_pcoem_platform(struct ath_softc *sc) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 4528c2ecf20Sopenharmony_ci struct ath9k_hw_capabilities *pCap = &ah->caps; 4538c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ATH9K_PCOEM)) 4568c2ecf20Sopenharmony_ci return; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (common->bus_ops->ath_bus_type != ATH_PCI) 4598c2ecf20Sopenharmony_ci return; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (sc->driver_data & (ATH9K_PCI_CUS198 | 4628c2ecf20Sopenharmony_ci ATH9K_PCI_CUS230)) { 4638c2ecf20Sopenharmony_ci ah->config.xlna_gpio = 9; 4648c2ecf20Sopenharmony_ci ah->config.xatten_margin_cfg = true; 4658c2ecf20Sopenharmony_ci ah->config.alt_mingainidx = true; 4668c2ecf20Sopenharmony_ci ah->config.ant_ctrl_comm2g_switch_enable = 0x000BBB88; 4678c2ecf20Sopenharmony_ci sc->ant_comb.low_rssi_thresh = 20; 4688c2ecf20Sopenharmony_ci sc->ant_comb.fast_div_bias = 3; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ath_info(common, "Set parameters for %s\n", 4718c2ecf20Sopenharmony_ci (sc->driver_data & ATH9K_PCI_CUS198) ? 4728c2ecf20Sopenharmony_ci "CUS198" : "CUS230"); 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_CUS217) 4768c2ecf20Sopenharmony_ci ath_info(common, "CUS217 card detected\n"); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_CUS252) 4798c2ecf20Sopenharmony_ci ath_info(common, "CUS252 card detected\n"); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_AR9565_1ANT) 4828c2ecf20Sopenharmony_ci ath_info(common, "WB335 1-ANT card detected\n"); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_AR9565_2ANT) 4858c2ecf20Sopenharmony_ci ath_info(common, "WB335 2-ANT card detected\n"); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_KILLER) 4888c2ecf20Sopenharmony_ci ath_info(common, "Killer Wireless card detected\n"); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * Some WB335 cards do not support antenna diversity. Since 4928c2ecf20Sopenharmony_ci * we use a hardcoded value for AR9565 instead of using the 4938c2ecf20Sopenharmony_ci * EEPROM/OTP data, remove the combining feature from 4948c2ecf20Sopenharmony_ci * the HW capabilities bitmap. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci if (sc->driver_data & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) { 4978c2ecf20Sopenharmony_ci if (!(sc->driver_data & ATH9K_PCI_BT_ANT_DIV)) 4988c2ecf20Sopenharmony_ci pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) { 5028c2ecf20Sopenharmony_ci pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV; 5038c2ecf20Sopenharmony_ci ath_info(common, "Set BT/WLAN RX diversity capability\n"); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_D3_L1_WAR) { 5078c2ecf20Sopenharmony_ci ah->config.pcie_waen = 0x0040473b; 5088c2ecf20Sopenharmony_ci ath_info(common, "Enable WAR for ASPM D3/L1\n"); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* 5128c2ecf20Sopenharmony_ci * The default value of pll_pwrsave is 1. 5138c2ecf20Sopenharmony_ci * For certain AR9485 cards, it is set to 0. 5148c2ecf20Sopenharmony_ci * For AR9462, AR9565 it's set to 7. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci ah->config.pll_pwrsave = 1; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_NO_PLL_PWRSAVE) { 5198c2ecf20Sopenharmony_ci ah->config.pll_pwrsave = 0; 5208c2ecf20Sopenharmony_ci ath_info(common, "Disable PLL PowerSave\n"); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (sc->driver_data & ATH9K_PCI_LED_ACT_HI) 5248c2ecf20Sopenharmony_ci ah->config.led_active_high = true; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, 5288c2ecf20Sopenharmony_ci void *ctx) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct ath9k_eeprom_ctx *ec = ctx; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (eeprom_blob) 5338c2ecf20Sopenharmony_ci ec->ah->eeprom_blob = eeprom_blob; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci complete(&ec->complete); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int ath9k_eeprom_request(struct ath_softc *sc, const char *name) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct ath9k_eeprom_ctx ec; 5418c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 5428c2ecf20Sopenharmony_ci int err; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* try to load the EEPROM content asynchronously */ 5458c2ecf20Sopenharmony_ci init_completion(&ec.complete); 5468c2ecf20Sopenharmony_ci ec.ah = sc->sc_ah; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci err = request_firmware_nowait(THIS_MODULE, 1, name, sc->dev, GFP_KERNEL, 5498c2ecf20Sopenharmony_ci &ec, ath9k_eeprom_request_cb); 5508c2ecf20Sopenharmony_ci if (err < 0) { 5518c2ecf20Sopenharmony_ci ath_err(ath9k_hw_common(ah), 5528c2ecf20Sopenharmony_ci "EEPROM request failed\n"); 5538c2ecf20Sopenharmony_ci return err; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci wait_for_completion(&ec.complete); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (!ah->eeprom_blob) { 5598c2ecf20Sopenharmony_ci ath_err(ath9k_hw_common(ah), 5608c2ecf20Sopenharmony_ci "Unable to load EEPROM file %s\n", name); 5618c2ecf20Sopenharmony_ci return -EINVAL; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic void ath9k_eeprom_release(struct ath_softc *sc) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci release_firmware(sc->sc_ah->eeprom_blob); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int ath9k_init_platform(struct ath_softc *sc) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct ath9k_platform_data *pdata = sc->dev->platform_data; 5758c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 5768c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 5778c2ecf20Sopenharmony_ci int ret; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (!pdata) 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (!pdata->use_eeprom) { 5838c2ecf20Sopenharmony_ci ah->ah_flags &= ~AH_USE_EEPROM; 5848c2ecf20Sopenharmony_ci ah->gpio_mask = pdata->gpio_mask; 5858c2ecf20Sopenharmony_ci ah->gpio_val = pdata->gpio_val; 5868c2ecf20Sopenharmony_ci ah->led_pin = pdata->led_pin; 5878c2ecf20Sopenharmony_ci ah->is_clk_25mhz = pdata->is_clk_25mhz; 5888c2ecf20Sopenharmony_ci ah->get_mac_revision = pdata->get_mac_revision; 5898c2ecf20Sopenharmony_ci ah->external_reset = pdata->external_reset; 5908c2ecf20Sopenharmony_ci ah->disable_2ghz = pdata->disable_2ghz; 5918c2ecf20Sopenharmony_ci ah->disable_5ghz = pdata->disable_5ghz; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!pdata->endian_check) 5948c2ecf20Sopenharmony_ci ah->ah_flags |= AH_NO_EEP_SWAP; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (pdata->eeprom_name) { 5988c2ecf20Sopenharmony_ci ret = ath9k_eeprom_request(sc, pdata->eeprom_name); 5998c2ecf20Sopenharmony_ci if (ret) 6008c2ecf20Sopenharmony_ci return ret; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (pdata->led_active_high) 6048c2ecf20Sopenharmony_ci ah->config.led_active_high = true; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (pdata->tx_gain_buffalo) 6078c2ecf20Sopenharmony_ci ah->config.tx_gain_buffalo = true; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (pdata->macaddr) 6108c2ecf20Sopenharmony_ci ether_addr_copy(common->macaddr, pdata->macaddr); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_cistatic int ath9k_of_init(struct ath_softc *sc) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct device_node *np = sc->dev->of_node; 6188c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 6198c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 6208c2ecf20Sopenharmony_ci enum ath_bus_type bus_type = common->bus_ops->ath_bus_type; 6218c2ecf20Sopenharmony_ci const char *mac; 6228c2ecf20Sopenharmony_ci char eeprom_name[100]; 6238c2ecf20Sopenharmony_ci int ret; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci ath_dbg(common, CONFIG, "parsing configuration from OF node\n"); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "qca,no-eeprom")) { 6318c2ecf20Sopenharmony_ci /* ath9k-eeprom-<bus>-<id>.bin */ 6328c2ecf20Sopenharmony_ci scnprintf(eeprom_name, sizeof(eeprom_name), 6338c2ecf20Sopenharmony_ci "ath9k-eeprom-%s-%s.bin", 6348c2ecf20Sopenharmony_ci ath_bus_type_to_string(bus_type), dev_name(ah->dev)); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ret = ath9k_eeprom_request(sc, eeprom_name); 6378c2ecf20Sopenharmony_ci if (ret) 6388c2ecf20Sopenharmony_ci return ret; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ah->ah_flags &= ~AH_USE_EEPROM; 6418c2ecf20Sopenharmony_ci ah->ah_flags |= AH_NO_EEP_SWAP; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci mac = of_get_mac_address(np); 6458c2ecf20Sopenharmony_ci if (!IS_ERR(mac)) 6468c2ecf20Sopenharmony_ci ether_addr_copy(common->macaddr, mac); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return 0; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic int ath9k_init_softc(u16 devid, struct ath_softc *sc, 6528c2ecf20Sopenharmony_ci const struct ath_bus_ops *bus_ops) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct ath_hw *ah = NULL; 6558c2ecf20Sopenharmony_ci struct ath9k_hw_capabilities *pCap; 6568c2ecf20Sopenharmony_ci struct ath_common *common; 6578c2ecf20Sopenharmony_ci int ret = 0, i; 6588c2ecf20Sopenharmony_ci int csz = 0; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci ah = devm_kzalloc(sc->dev, sizeof(struct ath_hw), GFP_KERNEL); 6618c2ecf20Sopenharmony_ci if (!ah) 6628c2ecf20Sopenharmony_ci return -ENOMEM; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ah->dev = sc->dev; 6658c2ecf20Sopenharmony_ci ah->hw = sc->hw; 6668c2ecf20Sopenharmony_ci ah->hw_version.devid = devid; 6678c2ecf20Sopenharmony_ci ah->ah_flags |= AH_USE_EEPROM; 6688c2ecf20Sopenharmony_ci ah->led_pin = -1; 6698c2ecf20Sopenharmony_ci ah->reg_ops.read = ath9k_ioread32; 6708c2ecf20Sopenharmony_ci ah->reg_ops.multi_read = ath9k_multi_ioread32; 6718c2ecf20Sopenharmony_ci ah->reg_ops.write = ath9k_iowrite32; 6728c2ecf20Sopenharmony_ci ah->reg_ops.rmw = ath9k_reg_rmw; 6738c2ecf20Sopenharmony_ci pCap = &ah->caps; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci common = ath9k_hw_common(ah); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* Will be cleared in ath9k_start() */ 6788c2ecf20Sopenharmony_ci set_bit(ATH_OP_INVALID, &common->op_flags); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci sc->sc_ah = ah; 6818c2ecf20Sopenharmony_ci sc->dfs_detector = dfs_pattern_detector_init(common, NL80211_DFS_UNSET); 6828c2ecf20Sopenharmony_ci sc->tx99_power = MAX_RATE_POWER + 1; 6838c2ecf20Sopenharmony_ci init_waitqueue_head(&sc->tx_wait); 6848c2ecf20Sopenharmony_ci sc->cur_chan = &sc->chanctx[0]; 6858c2ecf20Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 6868c2ecf20Sopenharmony_ci sc->cur_chan->hw_queue_base = 0; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci common->ops = &ah->reg_ops; 6898c2ecf20Sopenharmony_ci common->bus_ops = bus_ops; 6908c2ecf20Sopenharmony_ci common->ps_ops = &ath9k_ps_ops; 6918c2ecf20Sopenharmony_ci common->ah = ah; 6928c2ecf20Sopenharmony_ci common->hw = sc->hw; 6938c2ecf20Sopenharmony_ci common->priv = sc; 6948c2ecf20Sopenharmony_ci common->debug_mask = ath9k_debug; 6958c2ecf20Sopenharmony_ci common->btcoex_enabled = ath9k_btcoex_enable == 1; 6968c2ecf20Sopenharmony_ci common->disable_ani = false; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * Platform quirks. 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_ci ath9k_init_pcoem_platform(sc); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = ath9k_init_platform(sc); 7048c2ecf20Sopenharmony_ci if (ret) 7058c2ecf20Sopenharmony_ci return ret; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ret = ath9k_of_init(sc); 7088c2ecf20Sopenharmony_ci if (ret) 7098c2ecf20Sopenharmony_ci return ret; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (ath9k_led_active_high != -1) 7128c2ecf20Sopenharmony_ci ah->config.led_active_high = ath9k_led_active_high == 1; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* 7158c2ecf20Sopenharmony_ci * Enable WLAN/BT RX Antenna diversity only when: 7168c2ecf20Sopenharmony_ci * 7178c2ecf20Sopenharmony_ci * - BTCOEX is disabled. 7188c2ecf20Sopenharmony_ci * - the user manually requests the feature. 7198c2ecf20Sopenharmony_ci * - the HW cap is set using the platform data. 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci if (!common->btcoex_enabled && ath9k_bt_ant_diversity && 7228c2ecf20Sopenharmony_ci (pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) 7238c2ecf20Sopenharmony_ci common->bt_ant_diversity = 1; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci spin_lock_init(&common->cc_lock); 7268c2ecf20Sopenharmony_ci spin_lock_init(&sc->intr_lock); 7278c2ecf20Sopenharmony_ci spin_lock_init(&sc->sc_serial_rw); 7288c2ecf20Sopenharmony_ci spin_lock_init(&sc->sc_pm_lock); 7298c2ecf20Sopenharmony_ci spin_lock_init(&sc->chan_lock); 7308c2ecf20Sopenharmony_ci mutex_init(&sc->mutex); 7318c2ecf20Sopenharmony_ci tasklet_setup(&sc->intr_tq, ath9k_tasklet); 7328c2ecf20Sopenharmony_ci tasklet_setup(&sc->bcon_tasklet, ath9k_beacon_tasklet); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci timer_setup(&sc->sleep_timer, ath_ps_full_sleep, 0); 7358c2ecf20Sopenharmony_ci INIT_WORK(&sc->hw_reset_work, ath_reset_work); 7368c2ecf20Sopenharmony_ci INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); 7378c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); 7388c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&sc->hw_check_work, ath_hw_check_work); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci ath9k_init_channel_context(sc); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* 7438c2ecf20Sopenharmony_ci * Cache line size is used to size and align various 7448c2ecf20Sopenharmony_ci * structures used to communicate with the hardware. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci ath_read_cachesize(common, &csz); 7478c2ecf20Sopenharmony_ci common->cachelsz = csz << 2; /* convert to bytes */ 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Initializes the hardware for all supported chipsets */ 7508c2ecf20Sopenharmony_ci ret = ath9k_hw_init(ah); 7518c2ecf20Sopenharmony_ci if (ret) 7528c2ecf20Sopenharmony_ci goto err_hw; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci ret = ath9k_init_queues(sc); 7558c2ecf20Sopenharmony_ci if (ret) 7568c2ecf20Sopenharmony_ci goto err_queues; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci ret = ath9k_init_btcoex(sc); 7598c2ecf20Sopenharmony_ci if (ret) 7608c2ecf20Sopenharmony_ci goto err_btcoex; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci ret = ath9k_cmn_init_channels_rates(common); 7638c2ecf20Sopenharmony_ci if (ret) 7648c2ecf20Sopenharmony_ci goto err_btcoex; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ret = ath9k_init_p2p(sc); 7678c2ecf20Sopenharmony_ci if (ret) 7688c2ecf20Sopenharmony_ci goto err_btcoex; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ath9k_cmn_init_crypto(sc->sc_ah); 7718c2ecf20Sopenharmony_ci ath9k_init_misc(sc); 7728c2ecf20Sopenharmony_ci ath_chanctx_init(sc); 7738c2ecf20Sopenharmony_ci ath9k_offchannel_init(sc); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (common->bus_ops->aspm_init) 7768c2ecf20Sopenharmony_ci common->bus_ops->aspm_init(common); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci return 0; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cierr_btcoex: 7818c2ecf20Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) 7828c2ecf20Sopenharmony_ci if (ATH_TXQ_SETUP(sc, i)) 7838c2ecf20Sopenharmony_ci ath_tx_cleanupq(sc, &sc->tx.txq[i]); 7848c2ecf20Sopenharmony_cierr_queues: 7858c2ecf20Sopenharmony_ci ath9k_hw_deinit(ah); 7868c2ecf20Sopenharmony_cierr_hw: 7878c2ecf20Sopenharmony_ci ath9k_eeprom_release(sc); 7888c2ecf20Sopenharmony_ci dev_kfree_skb_any(sc->tx99_skb); 7898c2ecf20Sopenharmony_ci return ret; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic void ath9k_init_band_txpower(struct ath_softc *sc, int band) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 7958c2ecf20Sopenharmony_ci struct ieee80211_channel *chan; 7968c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 7978c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 7988c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 7998c2ecf20Sopenharmony_ci int i; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci sband = &common->sbands[band]; 8028c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 8038c2ecf20Sopenharmony_ci chan = &sband->channels[i]; 8048c2ecf20Sopenharmony_ci ah->curchan = &ah->channels[chan->hw_value]; 8058c2ecf20Sopenharmony_ci cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); 8068c2ecf20Sopenharmony_ci ath9k_cmn_get_channel(sc->hw, ah, &chandef); 8078c2ecf20Sopenharmony_ci ath9k_hw_set_txpowerlimit(ah, MAX_COMBINED_POWER, true); 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic void ath9k_init_txpower_limits(struct ath_softc *sc) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 8148c2ecf20Sopenharmony_ci struct ath9k_channel *curchan = ah->curchan; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 8178c2ecf20Sopenharmony_ci ath9k_init_band_txpower(sc, NL80211_BAND_2GHZ); 8188c2ecf20Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 8198c2ecf20Sopenharmony_ci ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci ah->curchan = curchan; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_limit if_limits[] = { 8258c2ecf20Sopenharmony_ci { .max = 2048, .types = BIT(NL80211_IFTYPE_STATION) }, 8268c2ecf20Sopenharmony_ci { .max = 8, .types = 8278c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_MESH 8288c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 8298c2ecf20Sopenharmony_ci#endif 8308c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_AP) }, 8318c2ecf20Sopenharmony_ci { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | 8328c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) }, 8338c2ecf20Sopenharmony_ci}; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci#ifdef CONFIG_WIRELESS_WDS 8368c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_limit wds_limits[] = { 8378c2ecf20Sopenharmony_ci { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, 8388c2ecf20Sopenharmony_ci}; 8398c2ecf20Sopenharmony_ci#endif 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_limit if_limits_multi[] = { 8448c2ecf20Sopenharmony_ci { .max = 2, .types = BIT(NL80211_IFTYPE_STATION) | 8458c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 8468c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 8478c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) }, 8488c2ecf20Sopenharmony_ci { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) }, 8498c2ecf20Sopenharmony_ci { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) }, 8508c2ecf20Sopenharmony_ci}; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_combination if_comb_multi[] = { 8538c2ecf20Sopenharmony_ci { 8548c2ecf20Sopenharmony_ci .limits = if_limits_multi, 8558c2ecf20Sopenharmony_ci .n_limits = ARRAY_SIZE(if_limits_multi), 8568c2ecf20Sopenharmony_ci .max_interfaces = 3, 8578c2ecf20Sopenharmony_ci .num_different_channels = 2, 8588c2ecf20Sopenharmony_ci .beacon_int_infra_match = true, 8598c2ecf20Sopenharmony_ci }, 8608c2ecf20Sopenharmony_ci}; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic const struct ieee80211_iface_combination if_comb[] = { 8658c2ecf20Sopenharmony_ci { 8668c2ecf20Sopenharmony_ci .limits = if_limits, 8678c2ecf20Sopenharmony_ci .n_limits = ARRAY_SIZE(if_limits), 8688c2ecf20Sopenharmony_ci .max_interfaces = 2048, 8698c2ecf20Sopenharmony_ci .num_different_channels = 1, 8708c2ecf20Sopenharmony_ci .beacon_int_infra_match = true, 8718c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_DFS_CERTIFIED 8728c2ecf20Sopenharmony_ci .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | 8738c2ecf20Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_20) | 8748c2ecf20Sopenharmony_ci BIT(NL80211_CHAN_WIDTH_40), 8758c2ecf20Sopenharmony_ci#endif 8768c2ecf20Sopenharmony_ci }, 8778c2ecf20Sopenharmony_ci#ifdef CONFIG_WIRELESS_WDS 8788c2ecf20Sopenharmony_ci { 8798c2ecf20Sopenharmony_ci .limits = wds_limits, 8808c2ecf20Sopenharmony_ci .n_limits = ARRAY_SIZE(wds_limits), 8818c2ecf20Sopenharmony_ci .max_interfaces = 2048, 8828c2ecf20Sopenharmony_ci .num_different_channels = 1, 8838c2ecf20Sopenharmony_ci .beacon_int_infra_match = true, 8848c2ecf20Sopenharmony_ci }, 8858c2ecf20Sopenharmony_ci#endif 8868c2ecf20Sopenharmony_ci}; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 8898c2ecf20Sopenharmony_cistatic void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 8928c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (!ath9k_is_chanctx_enabled()) 8958c2ecf20Sopenharmony_ci return; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, QUEUE_CONTROL); 8988c2ecf20Sopenharmony_ci hw->queues = ATH9K_NUM_TX_QUEUES; 8998c2ecf20Sopenharmony_ci hw->offchannel_tx_hw_queue = hw->queues - 1; 9008c2ecf20Sopenharmony_ci hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS); 9018c2ecf20Sopenharmony_ci hw->wiphy->iface_combinations = if_comb_multi; 9028c2ecf20Sopenharmony_ci hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); 9038c2ecf20Sopenharmony_ci hw->wiphy->max_scan_ssids = 255; 9048c2ecf20Sopenharmony_ci hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 9058c2ecf20Sopenharmony_ci hw->wiphy->max_remain_on_channel_duration = 10000; 9068c2ecf20Sopenharmony_ci hw->chanctx_data_size = sizeof(void *); 9078c2ecf20Sopenharmony_ci hw->extra_beacon_tailroom = 9088c2ecf20Sopenharmony_ci sizeof(struct ieee80211_p2p_noa_attr) + 9; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci ath_dbg(common, CHAN_CTX, "Use channel contexts\n"); 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 9178c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 9208c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 9218c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 9228c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SPECTRUM_MGMT); 9238c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 9248c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 9258c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, RX_INCLUDES_FCS); 9268c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); 9278c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); 9288c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (ath9k_ps_enable) 9318c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_PS); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { 9348c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) 9378c2ecf20Sopenharmony_ci hw->radiotap_mcs_details |= 9388c2ecf20Sopenharmony_ci IEEE80211_RADIOTAP_MCS_HAVE_STBC; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) 9428c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | 9458c2ecf20Sopenharmony_ci NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | 9468c2ecf20Sopenharmony_ci NL80211_FEATURE_P2P_GO_CTWIN; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_ATH9K_TX99)) { 9498c2ecf20Sopenharmony_ci hw->wiphy->interface_modes = 9508c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_GO) | 9518c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_CLIENT) | 9528c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_AP) | 9538c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_STATION) | 9548c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_ADHOC) | 9558c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_MESH_POINT) | 9568c2ecf20Sopenharmony_ci#ifdef CONFIG_WIRELESS_WDS 9578c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_WDS) | 9588c2ecf20Sopenharmony_ci#endif 9598c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_OCB); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (ath9k_is_chanctx_enabled()) 9628c2ecf20Sopenharmony_ci hw->wiphy->interface_modes |= 9638c2ecf20Sopenharmony_ci BIT(NL80211_IFTYPE_P2P_DEVICE); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci hw->wiphy->iface_combinations = if_comb; 9668c2ecf20Sopenharmony_ci hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 9728c2ecf20Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; 9738c2ecf20Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 9748c2ecf20Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_5_10_MHZ; 9758c2ecf20Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; 9768c2ecf20Sopenharmony_ci hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci hw->queues = 4; 9798c2ecf20Sopenharmony_ci hw->max_rates = 4; 9808c2ecf20Sopenharmony_ci hw->max_listen_interval = 10; 9818c2ecf20Sopenharmony_ci hw->max_rate_tries = 10; 9828c2ecf20Sopenharmony_ci hw->sta_data_size = sizeof(struct ath_node); 9838c2ecf20Sopenharmony_ci hw->vif_data_size = sizeof(struct ath_vif); 9848c2ecf20Sopenharmony_ci hw->txq_data_size = sizeof(struct ath_atx_tid); 9858c2ecf20Sopenharmony_ci hw->extra_tx_headroom = 4; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; 9888c2ecf20Sopenharmony_ci hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* single chain devices with rx diversity */ 9918c2ecf20Sopenharmony_ci if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) 9928c2ecf20Sopenharmony_ci hw->wiphy->available_antennas_rx = BIT(0) | BIT(1); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci sc->ant_rx = hw->wiphy->available_antennas_rx; 9958c2ecf20Sopenharmony_ci sc->ant_tx = hw->wiphy->available_antennas_tx; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) 9988c2ecf20Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_2GHZ] = 9998c2ecf20Sopenharmony_ci &common->sbands[NL80211_BAND_2GHZ]; 10008c2ecf20Sopenharmony_ci if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) 10018c2ecf20Sopenharmony_ci hw->wiphy->bands[NL80211_BAND_5GHZ] = 10028c2ecf20Sopenharmony_ci &common->sbands[NL80211_BAND_5GHZ]; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT 10058c2ecf20Sopenharmony_ci ath9k_set_mcc_capab(sc, hw); 10068c2ecf20Sopenharmony_ci#endif 10078c2ecf20Sopenharmony_ci ath9k_init_wow(hw); 10088c2ecf20Sopenharmony_ci ath9k_cmn_reload_chainmask(ah); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, common->macaddr); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 10138c2ecf20Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); 10148c2ecf20Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, 10158c2ecf20Sopenharmony_ci NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); 10168c2ecf20Sopenharmony_ci wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ciint ath9k_init_device(u16 devid, struct ath_softc *sc, 10208c2ecf20Sopenharmony_ci const struct ath_bus_ops *bus_ops) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 10238c2ecf20Sopenharmony_ci struct ath_common *common; 10248c2ecf20Sopenharmony_ci struct ath_hw *ah; 10258c2ecf20Sopenharmony_ci int error = 0; 10268c2ecf20Sopenharmony_ci struct ath_regulatory *reg; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* Bring up device */ 10298c2ecf20Sopenharmony_ci error = ath9k_init_softc(devid, sc, bus_ops); 10308c2ecf20Sopenharmony_ci if (error) 10318c2ecf20Sopenharmony_ci return error; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci ah = sc->sc_ah; 10348c2ecf20Sopenharmony_ci common = ath9k_hw_common(ah); 10358c2ecf20Sopenharmony_ci ath9k_set_hw_capab(sc, hw); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Initialize regulatory */ 10388c2ecf20Sopenharmony_ci error = ath_regd_init(&common->regulatory, sc->hw->wiphy, 10398c2ecf20Sopenharmony_ci ath9k_reg_notifier); 10408c2ecf20Sopenharmony_ci if (error) 10418c2ecf20Sopenharmony_ci goto deinit; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci reg = &common->regulatory; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* Setup TX DMA */ 10468c2ecf20Sopenharmony_ci error = ath_tx_init(sc, ATH_TXBUF); 10478c2ecf20Sopenharmony_ci if (error != 0) 10488c2ecf20Sopenharmony_ci goto deinit; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci /* Setup RX DMA */ 10518c2ecf20Sopenharmony_ci error = ath_rx_init(sc, ATH_RXBUF); 10528c2ecf20Sopenharmony_ci if (error != 0) 10538c2ecf20Sopenharmony_ci goto deinit; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci ath9k_init_txpower_limits(sc); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci#ifdef CONFIG_MAC80211_LEDS 10588c2ecf20Sopenharmony_ci /* must be initialized before ieee80211_register_hw */ 10598c2ecf20Sopenharmony_ci sc->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(sc->hw, 10608c2ecf20Sopenharmony_ci IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_tpt_blink, 10618c2ecf20Sopenharmony_ci ARRAY_SIZE(ath9k_tpt_blink)); 10628c2ecf20Sopenharmony_ci#endif 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Register with mac80211 */ 10658c2ecf20Sopenharmony_ci error = ieee80211_register_hw(hw); 10668c2ecf20Sopenharmony_ci if (error) 10678c2ecf20Sopenharmony_ci goto rx_cleanup; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci error = ath9k_init_debug(ah); 10708c2ecf20Sopenharmony_ci if (error) { 10718c2ecf20Sopenharmony_ci ath_err(common, "Unable to create debugfs files\n"); 10728c2ecf20Sopenharmony_ci goto unregister; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* Handle world regulatory */ 10768c2ecf20Sopenharmony_ci if (!ath_is_world_regd(reg)) { 10778c2ecf20Sopenharmony_ci error = regulatory_hint(hw->wiphy, reg->alpha2); 10788c2ecf20Sopenharmony_ci if (error) 10798c2ecf20Sopenharmony_ci goto debug_cleanup; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci ath_init_leds(sc); 10838c2ecf20Sopenharmony_ci ath_start_rfkill_poll(sc); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci return 0; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cidebug_cleanup: 10888c2ecf20Sopenharmony_ci ath9k_deinit_debug(sc); 10898c2ecf20Sopenharmony_ciunregister: 10908c2ecf20Sopenharmony_ci ieee80211_unregister_hw(hw); 10918c2ecf20Sopenharmony_cirx_cleanup: 10928c2ecf20Sopenharmony_ci ath_rx_cleanup(sc); 10938c2ecf20Sopenharmony_cideinit: 10948c2ecf20Sopenharmony_ci ath9k_deinit_softc(sc); 10958c2ecf20Sopenharmony_ci return error; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci/*****************************/ 10998c2ecf20Sopenharmony_ci/* De-Initialization */ 11008c2ecf20Sopenharmony_ci/*****************************/ 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic void ath9k_deinit_softc(struct ath_softc *sc) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci int i = 0; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci ath9k_deinit_p2p(sc); 11078c2ecf20Sopenharmony_ci ath9k_deinit_btcoex(sc); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) 11108c2ecf20Sopenharmony_ci if (ATH_TXQ_SETUP(sc, i)) 11118c2ecf20Sopenharmony_ci ath_tx_cleanupq(sc, &sc->tx.txq[i]); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci del_timer_sync(&sc->sleep_timer); 11148c2ecf20Sopenharmony_ci ath9k_hw_deinit(sc->sc_ah); 11158c2ecf20Sopenharmony_ci if (sc->dfs_detector != NULL) 11168c2ecf20Sopenharmony_ci sc->dfs_detector->exit(sc->dfs_detector); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci ath9k_eeprom_release(sc); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_civoid ath9k_deinit_device(struct ath_softc *sc) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = sc->hw; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci ath9k_ps_wakeup(sc); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci wiphy_rfkill_stop_polling(sc->hw->wiphy); 11288c2ecf20Sopenharmony_ci ath_deinit_leds(sc); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci ath9k_ps_restore(sc); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci ath9k_deinit_debug(sc); 11338c2ecf20Sopenharmony_ci ath9k_deinit_wow(hw); 11348c2ecf20Sopenharmony_ci ieee80211_unregister_hw(hw); 11358c2ecf20Sopenharmony_ci ath_rx_cleanup(sc); 11368c2ecf20Sopenharmony_ci ath9k_deinit_softc(sc); 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/************************/ 11408c2ecf20Sopenharmony_ci/* Module Hooks */ 11418c2ecf20Sopenharmony_ci/************************/ 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic int __init ath9k_init(void) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci int error; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci error = ath_pci_init(); 11488c2ecf20Sopenharmony_ci if (error < 0) { 11498c2ecf20Sopenharmony_ci pr_err("No PCI devices found, driver not installed\n"); 11508c2ecf20Sopenharmony_ci error = -ENODEV; 11518c2ecf20Sopenharmony_ci goto err_out; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci error = ath_ahb_init(); 11558c2ecf20Sopenharmony_ci if (error < 0) { 11568c2ecf20Sopenharmony_ci error = -ENODEV; 11578c2ecf20Sopenharmony_ci goto err_pci_exit; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci dmi_check_system(ath9k_quirks); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci return 0; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci err_pci_exit: 11658c2ecf20Sopenharmony_ci ath_pci_exit(); 11668c2ecf20Sopenharmony_ci err_out: 11678c2ecf20Sopenharmony_ci return error; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_cimodule_init(ath9k_init); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_cistatic void __exit ath9k_exit(void) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci is_ath9k_unloaded = true; 11748c2ecf20Sopenharmony_ci ath_ahb_exit(); 11758c2ecf20Sopenharmony_ci ath_pci_exit(); 11768c2ecf20Sopenharmony_ci pr_info("%s: Driver unloaded\n", dev_info); 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_cimodule_exit(ath9k_exit); 1179