diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2020-08-06 14:15:47 +0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2020-08-06 14:15:47 +0300 |
commit | 94fb1afb14c4f0ceb8c5508ddddac6819f662e95 (patch) | |
tree | 4988e5769dc7482caa7f441475ae31f50bbd37ef /drivers/net/wireless | |
parent | c4735d990268399da9133b0ad445e488ece009ad (diff) | |
parent | 47ec5303d73ea344e84f46660fff693c57641386 (diff) | |
download | linux-94fb1afb14c4f0ceb8c5508ddddac6819f662e95.tar.xz |
Mgerge remote-tracking branch 'torvalds/master' into perf/core
To sync headers, for instance, in this case tools/perf was ahead of
upstream till Linus merged tip/perf/core to get the
PERF_RECORD_TEXT_POKE changes:
Warning: Kernel ABI header at 'tools/include/uapi/linux/perf_event.h' differs from latest version at 'include/uapi/linux/perf_event.h'
diff -u tools/include/uapi/linux/perf_event.h include/uapi/linux/perf_event.h
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'drivers/net/wireless')
244 files changed, 27990 insertions, 1889 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 8ab62bb6b853..170a64e67709 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -14,7 +14,7 @@ menuconfig WLAN device drivers. For a complete list of drivers and documentation on them refer to the wireless wiki: - http://wireless.kernel.org/en/users/Drivers + https://wireless.wiki.kernel.org/en/users/Drivers if WLAN @@ -40,6 +40,7 @@ source "drivers/net/wireless/intel/Kconfig" source "drivers/net/wireless/intersil/Kconfig" source "drivers/net/wireless/marvell/Kconfig" source "drivers/net/wireless/mediatek/Kconfig" +source "drivers/net/wireless/microchip/Kconfig" source "drivers/net/wireless/ralink/Kconfig" source "drivers/net/wireless/realtek/Kconfig" source "drivers/net/wireless/rsi/Kconfig" @@ -57,7 +58,8 @@ config PCMCIA_RAYCS help Say Y here if you intend to attach an Aviator/Raytheon PCMCIA (PC-card) wireless Ethernet networking card to your computer. - Please read the file <file:Documentation/networking/ray_cs.rst> for + Please read the file + <file:Documentation/networking/device_drivers/wifi/ray_cs.rst> for details. To compile this driver as a module, choose M here: the module will be diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 6cfe74515c95..80b324499786 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/ obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/ obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/ obj-$(CONFIG_WLAN_VENDOR_MEDIATEK) += mediatek/ +obj-$(CONFIG_WLAN_VENDOR_MICROCHIP) += microchip/ obj-$(CONFIG_WLAN_VENDOR_RALINK) += ralink/ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index ba326f6c1214..22f9f2f8af10 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1976,35 +1976,20 @@ static void adm8211_remove(struct pci_dev *pdev) } -#ifdef CONFIG_PM -static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state) -{ - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int adm8211_resume(struct pci_dev *pdev) -{ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - return 0; -} -#endif /* CONFIG_PM */ - +#define adm8211_suspend NULL +#define adm8211_resume NULL MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table); +static SIMPLE_DEV_PM_OPS(adm8211_pm_ops, adm8211_suspend, adm8211_resume); + /* TODO: implement enable_wake */ static struct pci_driver adm8211_driver = { .name = "adm8211", .id_table = adm8211_pci_id_table, .probe = adm8211_probe, .remove = adm8211_remove, -#ifdef CONFIG_PM - .suspend = adm8211_suspend, - .resume = adm8211_resume, -#endif /* CONFIG_PM */ + .driver.pm = &adm8211_pm_ops, }; module_pci_driver(adm8211_driver); diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 6e9d46b96555..d88edbf1bea3 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -15,11 +15,11 @@ config WLAN_VENDOR_ATH For more information and documentation on this module you can visit: - http://wireless.kernel.org/en/users/Drivers/ath + https://wireless.wiki.kernel.org/en/users/Drivers/ath For information on all Atheros wireless drivers visit: - http://wireless.kernel.org/en/users/Drivers/Atheros + https://wireless.wiki.kernel.org/en/users/Drivers/Atheros if WLAN_VENDOR_ATH diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 22b6937ac225..340ce327ac14 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2240,7 +2240,7 @@ static int ath10k_init_uart(struct ath10k *ar) static int ath10k_init_hw_params(struct ath10k *ar) { - const struct ath10k_hw_params *uninitialized_var(hw_params); + const struct ath10k_hw_params *hw_params; int i; for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 4fd10ac3a941..bbe869575855 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -1591,7 +1591,9 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt, err_unmap_msdu: dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_msdu_id: + spin_lock_bh(&htt->tx_lock); ath10k_htt_tx_free_msdu_id(htt, msdu_id); + spin_unlock_bh(&htt->tx_lock); err: return res; } @@ -1798,7 +1800,9 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, err_unmap_msdu: dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); err_free_msdu_id: + spin_lock_bh(&htt->tx_lock); ath10k_htt_tx_free_msdu_id(htt, msdu_id); + spin_unlock_bh(&htt->tx_lock); err: return res; } diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 919d15584d4a..3c0c33a9f30c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -568,11 +568,7 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) case NL80211_CHAN_WIDTH_40: phymode = MODE_11NG_HT40; break; - case NL80211_CHAN_WIDTH_5: - case NL80211_CHAN_WIDTH_10: - case NL80211_CHAN_WIDTH_80: - case NL80211_CHAN_WIDTH_80P80: - case NL80211_CHAN_WIDTH_160: + default: phymode = MODE_UNKNOWN; break; } @@ -597,8 +593,7 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef) case NL80211_CHAN_WIDTH_80P80: phymode = MODE_11AC_VHT80_80; break; - case NL80211_CHAN_WIDTH_5: - case NL80211_CHAN_WIDTH_10: + default: phymode = MODE_UNKNOWN; break; } diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index b7daf344d012..05a620ff6fe2 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -824,7 +824,7 @@ static int ath10k_usb_setup_pipe_resources(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_USB, "usb setting up pipes using interface\n"); - /* walk decriptors and setup pipes */ + /* walk descriptors and setup pipes */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig index 7acb42e2e6e2..88a97356f0a1 100644 --- a/drivers/net/wireless/ath/ath11k/Kconfig +++ b/drivers/net/wireless/ath/ath11k/Kconfig @@ -34,3 +34,12 @@ config ATH11K_TRACING depends on ATH11K && EVENT_TRACING help Select this to use ath11k tracing infrastructure. + +config ATH11K_SPECTRAL + bool "QCA ath11k spectral scan support" + depends on ATH11K_DEBUGFS + depends on RELAY + help + Enable ath11k spectral scan support + + Say Y to enable access to the FFT/spectral data via debugfs. diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index fe7736e53583..104186373c9e 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -15,12 +15,14 @@ ath11k-y += core.o \ dp_rx.o \ debug.o \ ce.o \ - peer.o + peer.o \ + dbring.o ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o ath11k-$(CONFIG_ATH11K_TRACING) += trace.o ath11k-$(CONFIG_THERMAL) += thermal.o +ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 02501cc154fe..905cd8beaf28 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -400,8 +400,16 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab) goto err_dp_pdev_free; } + ret = ath11k_spectral_init(ab); + if (ret) { + ath11k_err(ab, "failed to init spectral %d\n", ret); + goto err_thermal_unregister; + } + return 0; +err_thermal_unregister: + ath11k_thermal_unregister(ab); err_dp_pdev_free: ath11k_dp_pdev_free(ab); err_mac_unregister: @@ -414,6 +422,7 @@ err_pdev_debug: static void ath11k_core_pdev_destroy(struct ath11k_base *ab) { + ath11k_spectral_deinit(ab); ath11k_thermal_unregister(ab); ath11k_mac_unregister(ab); ath11k_hif_irq_disable(ab); @@ -582,6 +591,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) ath11k_thermal_unregister(ab); ath11k_hif_irq_disable(ab); ath11k_dp_pdev_free(ab); + ath11k_spectral_deinit(ab); ath11k_hif_stop(ab); ath11k_wmi_detach(ab); ath11k_dp_pdev_reo_cleanup(ab); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index e04f0e711779..e5c4e19020ee 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -21,6 +21,8 @@ #include "hal_rx.h" #include "reg.h" #include "thermal.h" +#include "dbring.h" +#include "spectral.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -215,12 +217,15 @@ struct ath11k_vif { bool is_started; bool is_up; + bool spectral_enabled; u32 aid; u8 bssid[ETH_ALEN]; struct cfg80211_bitrate_mask bitrate_mask; int num_legacy_stations; int rtscts_prot_mode; int txpower; + bool rsnie_present; + bool wpaie_present; }; struct ath11k_vif_iter { @@ -353,7 +358,10 @@ struct ath11k_sta { #endif }; -#define ATH11K_NUM_CHANS 41 +#define ATH11K_MIN_5G_FREQ 4150 +#define ATH11K_MIN_6G_FREQ 5945 +#define ATH11K_MAX_6G_FREQ 7115 +#define ATH11K_NUM_CHANS 100 #define ATH11K_MAX_5G_CHAN 173 enum ath11k_state { @@ -431,6 +439,7 @@ struct ath11k { u32 vht_cap_info; struct ath11k_he ar_he; enum ath11k_state state; + bool supports_6ghz; struct { struct completion started; struct completion completed; @@ -537,6 +546,9 @@ struct ath11k { #ifdef CONFIG_ATH11K_DEBUGFS struct ath11k_debug debug; #endif +#ifdef CONFIG_ATH11K_SPECTRAL + struct ath11k_spectral spectral; +#endif bool dfs_block_radar_events; struct ath11k_thermal thermal; }; @@ -548,6 +560,7 @@ struct ath11k_band_cap { u32 he_mcs; u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE]; struct ath11k_ppe_threshold he_ppet; + u16 he_6ghz_capa; }; struct ath11k_pdev_cap { @@ -579,12 +592,42 @@ struct ath11k_board_data { /* IPQ8074 HW channel counters frequency value in hertz */ #define IPQ8074_CC_FREQ_HERTZ 320000 -struct ath11k_soc_dp_rx_stats { +struct ath11k_bp_stats { + /* Head Pointer reported by the last HTT Backpressure event for the ring */ + u16 hp; + + /* Tail Pointer reported by the last HTT Backpressure event for the ring */ + u16 tp; + + /* Number of Backpressure events received for the ring */ + u32 count; + + /* Last recorded event timestamp */ + unsigned long jiffies; +}; + +struct ath11k_dp_ring_bp_stats { + struct ath11k_bp_stats umac_ring_bp_stats[HTT_SW_UMAC_RING_IDX_MAX]; + struct ath11k_bp_stats lmac_ring_bp_stats[HTT_SW_LMAC_RING_IDX_MAX][MAX_RADIOS]; +}; + +struct ath11k_soc_dp_tx_err_stats { + /* TCL Ring Descriptor unavailable */ + u32 desc_na[DP_TCL_NUM_RING_MAX]; + /* Other failures during dp_tx due to mem allocation failure + * idr unavailable etc. + */ + atomic_t misc_fail; +}; + +struct ath11k_soc_dp_stats { u32 err_ring_pkts; u32 invalid_rbm; u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX]; u32 hal_reo_error[DP_REO_DST_RING_MAX]; + struct ath11k_soc_dp_tx_err_stats tx_err; + struct ath11k_dp_ring_bp_stats bp_stats; }; /* Master structure to hold the hw data which may be used in core module */ @@ -653,7 +696,7 @@ struct ath11k_base { struct dentry *debugfs_soc; struct dentry *debugfs_ath11k; #endif - struct ath11k_soc_dp_rx_stats soc_stats; + struct ath11k_soc_dp_stats soc_stats; unsigned long dev_flags; struct completion driver_recovery; @@ -668,6 +711,9 @@ struct ath11k_base { /* Round robbin based TCL ring selector */ atomic_t tcl_ring_selector; + struct ath11k_dbring_cap *db_caps; + u32 num_db_cap; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c new file mode 100644 index 000000000000..cf20db370123 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + */ + +#include "core.h" +#include "debug.h" + +static int ath11k_dbring_bufs_replenish(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_element *buff, + gfp_t gfp) +{ + struct ath11k_base *ab = ar->ab; + struct hal_srng *srng; + dma_addr_t paddr; + void *ptr_aligned, *ptr_unaligned, *desc; + int ret; + int buf_id; + u32 cookie; + + srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; + + lockdep_assert_held(&srng->lock); + + ath11k_hal_srng_access_begin(ab, srng); + + ptr_unaligned = buff->payload; + ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align); + paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz, + DMA_FROM_DEVICE); + + ret = dma_mapping_error(ab->dev, paddr); + if (ret) + goto err; + + spin_lock_bh(&ring->idr_lock); + buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, gfp); + spin_unlock_bh(&ring->idr_lock); + if (buf_id < 0) { + ret = -ENOBUFS; + goto err_dma_unmap; + } + + desc = ath11k_hal_srng_src_get_next_entry(ab, srng); + if (!desc) { + ret = -ENOENT; + goto err_idr_remove; + } + + buff->paddr = paddr; + + cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, ar->pdev_idx) | + FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id); + + ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0); + + ath11k_hal_srng_access_end(ab, srng); + + return 0; + +err_idr_remove: + spin_lock_bh(&ring->idr_lock); + idr_remove(&ring->bufs_idr, buf_id); + spin_unlock_bh(&ring->idr_lock); +err_dma_unmap: + dma_unmap_single(ab->dev, paddr, ring->buf_sz, + DMA_FROM_DEVICE); +err: + ath11k_hal_srng_access_end(ab, srng); + return ret; +} + +static int ath11k_dbring_fill_bufs(struct ath11k *ar, + struct ath11k_dbring *ring, + gfp_t gfp) +{ + struct ath11k_dbring_element *buff; + struct hal_srng *srng; + int num_remain, req_entries, num_free; + u32 align; + int size, ret; + + srng = &ar->ab->hal.srng_list[ring->refill_srng.ring_id]; + + spin_lock_bh(&srng->lock); + + num_free = ath11k_hal_srng_src_num_free(ar->ab, srng, true); + req_entries = min(num_free, ring->bufs_max); + num_remain = req_entries; + align = ring->buf_align; + size = sizeof(*buff) + ring->buf_sz + align - 1; + + while (num_remain > 0) { + buff = kzalloc(size, gfp); + if (!buff) + break; + + ret = ath11k_dbring_bufs_replenish(ar, ring, buff, gfp); + if (ret) { + ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n", + num_remain, req_entries); + kfree(buff); + break; + } + num_remain--; + } + + spin_unlock_bh(&srng->lock); + + return num_remain; +} + +int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, + struct ath11k_dbring *ring, + enum wmi_direct_buffer_module id) +{ + struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {0}; + int ret; + + if (id >= WMI_DIRECT_BUF_MAX) + return -EINVAL; + + param.pdev_id = DP_SW2HW_MACID(ring->pdev_id); + param.module_id = id; + param.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr); + param.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr); + param.head_idx_paddr_lo = lower_32_bits(ring->hp_addr); + param.head_idx_paddr_hi = upper_32_bits(ring->hp_addr); + param.tail_idx_paddr_lo = lower_32_bits(ring->tp_addr); + param.tail_idx_paddr_hi = upper_32_bits(ring->tp_addr); + param.num_elems = ring->bufs_max; + param.buf_size = ring->buf_sz; + param.num_resp_per_event = ring->num_resp_per_event; + param.event_timeout_ms = ring->event_timeout_ms; + + ret = ath11k_wmi_pdev_dma_ring_cfg(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); + return ret; + } + + return 0; +} + +int ath11k_dbring_set_cfg(struct ath11k *ar, struct ath11k_dbring *ring, + u32 num_resp_per_event, u32 event_timeout_ms, + int (*handler)(struct ath11k *, + struct ath11k_dbring_data *)) +{ + if (WARN_ON(!ring)) + return -EINVAL; + + ring->num_resp_per_event = num_resp_per_event; + ring->event_timeout_ms = event_timeout_ms; + ring->handler = handler; + + return 0; +} + +int ath11k_dbring_buf_setup(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_cap *db_cap) +{ + struct ath11k_base *ab = ar->ab; + struct hal_srng *srng; + int ret; + + srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; + ring->bufs_max = ring->refill_srng.size / + ath11k_hal_srng_get_entrysize(HAL_RXDMA_DIR_BUF); + + ring->buf_sz = db_cap->min_buf_sz; + ring->buf_align = db_cap->min_buf_align; + ring->pdev_id = db_cap->pdev_id; + ring->hp_addr = ath11k_hal_srng_get_hp_addr(ar->ab, srng); + ring->tp_addr = ath11k_hal_srng_get_tp_addr(ar->ab, srng); + + ret = ath11k_dbring_fill_bufs(ar, ring, GFP_KERNEL); + + return ret; +} + +int ath11k_dbring_srng_setup(struct ath11k *ar, struct ath11k_dbring *ring, + int ring_num, int num_entries) +{ + int ret; + + ret = ath11k_dp_srng_setup(ar->ab, &ring->refill_srng, HAL_RXDMA_DIR_BUF, + ring_num, ar->pdev_idx, num_entries); + if (ret < 0) { + ath11k_warn(ar->ab, "failed to setup srng: %d ring_id %d\n", + ret, ring_num); + goto err; + } + + return 0; +err: + ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng); + return ret; +} + +int ath11k_dbring_get_cap(struct ath11k_base *ab, + u8 pdev_idx, + enum wmi_direct_buffer_module id, + struct ath11k_dbring_cap *db_cap) +{ + int i; + + if (!ab->num_db_cap || !ab->db_caps) + return -ENOENT; + + if (id >= WMI_DIRECT_BUF_MAX) + return -EINVAL; + + for (i = 0; i < ab->num_db_cap; i++) { + if (pdev_idx == ab->db_caps[i].pdev_id && + id == ab->db_caps[i].id) { + *db_cap = ab->db_caps[i]; + + return 0; + } + } + + return -ENOENT; +} + +int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, + struct ath11k_dbring_buf_release_event *ev) +{ + struct ath11k_dbring *ring; + struct hal_srng *srng; + struct ath11k *ar; + struct ath11k_dbring_element *buff; + struct ath11k_dbring_data handler_data; + struct ath11k_buffer_addr desc; + u8 *vaddr_unalign; + u32 num_entry, num_buff_reaped; + u8 pdev_idx, rbm; + u32 cookie; + int buf_id; + int size; + dma_addr_t paddr; + int ret = 0; + + pdev_idx = ev->fixed.pdev_id; + + if (pdev_idx >= ab->num_radios) { + ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx); + return -EINVAL; + } + + if (ev->fixed.num_buf_release_entry != + ev->fixed.num_meta_data_entry) { + ath11k_warn(ab, "Buffer entry %d mismatch meta entry %d\n", + ev->fixed.num_buf_release_entry, + ev->fixed.num_meta_data_entry); + return -EINVAL; + } + + ar = ab->pdevs[pdev_idx].ar; + + rcu_read_lock(); + if (!rcu_dereference(ab->pdevs_active[pdev_idx])) { + ret = -EINVAL; + goto rcu_unlock; + } + + switch (ev->fixed.module_id) { + case WMI_DIRECT_BUF_SPECTRAL: + ring = ath11k_spectral_get_dbring(ar); + break; + default: + ring = NULL; + ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n", + ev->fixed.module_id); + break; + } + + if (!ring) { + ret = -EINVAL; + goto rcu_unlock; + } + + srng = &ab->hal.srng_list[ring->refill_srng.ring_id]; + num_entry = ev->fixed.num_buf_release_entry; + size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1; + num_buff_reaped = 0; + + spin_lock_bh(&srng->lock); + + while (num_buff_reaped < num_entry) { + desc.info0 = ev->buf_entry[num_buff_reaped].paddr_lo; + desc.info1 = ev->buf_entry[num_buff_reaped].paddr_hi; + handler_data.meta = ev->meta_data[num_buff_reaped]; + + num_buff_reaped++; + + ath11k_hal_rx_buf_addr_info_get(&desc, &paddr, &cookie, &rbm); + + buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); + + spin_lock_bh(&ring->idr_lock); + buff = idr_find(&ring->bufs_idr, buf_id); + if (!buff) { + spin_unlock_bh(&ring->idr_lock); + continue; + } + idr_remove(&ring->bufs_idr, buf_id); + spin_unlock_bh(&ring->idr_lock); + + dma_unmap_single(ab->dev, buff->paddr, ring->buf_sz, + DMA_FROM_DEVICE); + + if (ring->handler) { + vaddr_unalign = buff->payload; + handler_data.data = PTR_ALIGN(vaddr_unalign, + ring->buf_align); + handler_data.data_sz = ring->buf_sz; + + ring->handler(ar, &handler_data); + } + + memset(buff, 0, size); + ath11k_dbring_bufs_replenish(ar, ring, buff, GFP_ATOMIC); + } + + spin_unlock_bh(&srng->lock); + +rcu_unlock: + rcu_read_unlock(); + + return ret; +} + +void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring) +{ + ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng); +} + +void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring) +{ + struct ath11k_dbring_element *buff; + int buf_id; + + spin_lock_bh(&ring->idr_lock); + idr_for_each_entry(&ring->bufs_idr, buff, buf_id) { + idr_remove(&ring->bufs_idr, buf_id); + dma_unmap_single(ar->ab->dev, buff->paddr, + ring->buf_sz, DMA_FROM_DEVICE); + kfree(buff); + } + + idr_destroy(&ring->bufs_idr); + spin_unlock_bh(&ring->idr_lock); +} diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h new file mode 100644 index 000000000000..f7fce9ef9c36 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/dbring.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + */ + +#ifndef ATH11K_DBRING_H +#define ATH11K_DBRING_H + +#include <linux/types.h> +#include <linux/idr.h> +#include <linux/spinlock.h> +#include "dp.h" + +struct ath11k_dbring_element { + dma_addr_t paddr; + u8 payload[0]; +}; + +struct ath11k_dbring_data { + void *data; + u32 data_sz; + struct wmi_dma_buf_release_meta_data meta; +}; + +struct ath11k_dbring_buf_release_event { + struct ath11k_wmi_dma_buf_release_fixed_param fixed; + struct wmi_dma_buf_release_entry *buf_entry; + struct wmi_dma_buf_release_meta_data *meta_data; + u32 num_buf_entry; + u32 num_meta; +}; + +struct ath11k_dbring_cap { + u32 pdev_id; + enum wmi_direct_buffer_module id; + u32 min_elem; + u32 min_buf_sz; + u32 min_buf_align; +}; + +struct ath11k_dbring { + struct dp_srng refill_srng; + struct idr bufs_idr; + /* Protects bufs_idr */ + spinlock_t idr_lock; + dma_addr_t tp_addr; + dma_addr_t hp_addr; + int bufs_max; + u32 pdev_id; + u32 buf_sz; + u32 buf_align; + u32 num_resp_per_event; + u32 event_timeout_ms; + int (*handler)(struct ath11k *, struct ath11k_dbring_data *); +}; + +int ath11k_dbring_set_cfg(struct ath11k *ar, + struct ath11k_dbring *ring, + u32 num_resp_per_event, + u32 event_timeout_ms, + int (*handler)(struct ath11k *, + struct ath11k_dbring_data *)); +int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, + struct ath11k_dbring *ring, + enum wmi_direct_buffer_module id); +int ath11k_dbring_buf_setup(struct ath11k *ar, + struct ath11k_dbring *ring, + struct ath11k_dbring_cap *db_cap); +int ath11k_dbring_srng_setup(struct ath11k *ar, struct ath11k_dbring *ring, + int ring_num, int num_entries); +int ath11k_dbring_buffer_release_event(struct ath11k_base *ab, + struct ath11k_dbring_buf_release_event *ev); +int ath11k_dbring_get_cap(struct ath11k_base *ab, + u8 pdev_idx, + enum wmi_direct_buffer_module id, + struct ath11k_dbring_cap *db_cap); +void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); +void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring); +#endif /* ATH11K_DBRING_H */ diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index 3fd6b5af073b..62a1aa0565a9 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -12,6 +12,43 @@ #include "debug_htt_stats.h" #include "peer.h" +static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = { + "REO2SW1_RING", + "REO2SW2_RING", + "REO2SW3_RING", + "REO2SW4_RING", + "WBM2REO_LINK_RING", + "REO2TCL_RING", + "REO2FW_RING", + "RELEASE_RING", + "PPE_RELEASE_RING", + "TCL2TQM_RING", + "TQM_RELEASE_RING", + "REO_RELEASE_RING", + "WBM2SW0_RELEASE_RING", + "WBM2SW1_RELEASE_RING", + "WBM2SW2_RELEASE_RING", + "WBM2SW3_RELEASE_RING", + "REO_CMD_RING", + "REO_STATUS_RING", +}; + +static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = { + "FW2RXDMA_BUF_RING", + "FW2RXDMA_STATUS_RING", + "FW2RXDMA_LINK_RING", + "SW2RXDMA_BUF_RING", + "WBM2RXDMA_LINK_RING", + "RXDMA2FW_RING", + "RXDMA2SW_RING", + "RXDMA2RELEASE_RING", + "RXDMA2REO_RING", + "MONITOR_STATUS_RING", + "MONITOR_BUF_RING", + "MONITOR_DESC_RING", + "MONITOR_DEST_RING", +}; + void ath11k_info(struct ath11k_base *ab, const char *fmt, ...) { struct va_format vaf = { @@ -739,12 +776,78 @@ static const struct file_operations fops_extd_rx_stats = { .open = simple_open, }; -static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file, +static int ath11k_fill_bp_stats(struct ath11k_base *ab, + struct ath11k_bp_stats *bp_stats, + char *buf, int len, int size) +{ + lockdep_assert_held(&ab->base_lock); + + len += scnprintf(buf + len, size - len, "count: %u\n", + bp_stats->count); + len += scnprintf(buf + len, size - len, "hp: %u\n", + bp_stats->hp); + len += scnprintf(buf + len, size - len, "tp: %u\n", + bp_stats->tp); + len += scnprintf(buf + len, size - len, "seen before: %ums\n\n", + jiffies_to_msecs(jiffies - bp_stats->jiffies)); + return len; +} + +static ssize_t ath11k_debug_dump_soc_ring_bp_stats(struct ath11k_base *ab, + char *buf, int size) +{ + struct ath11k_bp_stats *bp_stats; + bool stats_rxd = false; + u8 i, pdev_idx; + int len = 0; + + len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n"); + len += scnprintf(buf + len, size - len, "==================\n"); + + spin_lock_bh(&ab->base_lock); + for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) { + bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i]; + + if (!bp_stats->count) + continue; + + len += scnprintf(buf + len, size - len, "Ring: %s\n", + htt_bp_umac_ring[i]); + len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size); + stats_rxd = true; + } + + for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) { + for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) { + bp_stats = + &ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx]; + + if (!bp_stats->count) + continue; + + len += scnprintf(buf + len, size - len, "Ring: %s\n", + htt_bp_lmac_ring[i]); + len += scnprintf(buf + len, size - len, "pdev: %d\n", + pdev_idx); + len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size); + stats_rxd = true; + } + } + spin_unlock_bh(&ab->base_lock); + + if (!stats_rxd) + len += scnprintf(buf + len, size - len, + "No Ring Backpressure stats received\n\n"); + + return len; +} + +static ssize_t ath11k_debug_dump_soc_dp_stats(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath11k_base *ab = file->private_data; - struct ath11k_soc_dp_rx_stats *soc_stats = &ab->soc_stats; + struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats; int len = 0, i, retval; const int size = 4096; static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = { @@ -788,6 +891,19 @@ static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file, soc_stats->hal_reo_error[2], soc_stats->hal_reo_error[3]); + len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n"); + len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n"); + + for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) + len += scnprintf(buf + len, size - len, "ring%d: %u\n", + i, soc_stats->tx_err.desc_na[i]); + + len += scnprintf(buf + len, size - len, + "\nMisc Transmit Failures: %d\n", + atomic_read(&soc_stats->tx_err.misc_fail)); + + len += ath11k_debug_dump_soc_ring_bp_stats(ab, buf + len, size - len); + if (len > size) len = size; retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); @@ -796,8 +912,8 @@ static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file, return retval; } -static const struct file_operations fops_soc_rx_stats = { - .read = ath11k_debug_dump_soc_rx_stats, +static const struct file_operations fops_soc_dp_stats = { + .read = ath11k_debug_dump_soc_dp_stats, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, @@ -819,8 +935,8 @@ int ath11k_debug_pdev_create(struct ath11k_base *ab) debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab, &fops_simulate_fw_crash); - debugfs_create_file("soc_rx_stats", 0600, ab->debugfs_soc, ab, - &fops_soc_rx_stats); + debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab, + &fops_soc_dp_stats); return 0; } diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 9ae743e528af..1d64c3c51ac9 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -172,11 +172,12 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, case HAL_RXDMA_DST: case HAL_RXDMA_MONITOR_DST: case HAL_RXDMA_MONITOR_DESC: - case HAL_RXDMA_DIR_BUF: params.intr_batch_cntr_thres_entries = HAL_SRNG_INT_BATCH_THRESHOLD_OTHER; params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_OTHER; break; + case HAL_RXDMA_DIR_BUF: + break; default: ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index 058a5c1d86ff..7587862d2e32 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -999,6 +999,48 @@ struct htt_resp_msg { #define HTT_BACKPRESSURE_EVENT_HP_M GENMASK(15, 0) #define HTT_BACKPRESSURE_EVENT_TP_M GENMASK(31, 16) +#define HTT_BACKPRESSURE_UMAC_RING_TYPE 0 +#define HTT_BACKPRESSURE_LMAC_RING_TYPE 1 + +enum htt_backpressure_umac_ringid { + HTT_SW_RING_IDX_REO_REO2SW1_RING, + HTT_SW_RING_IDX_REO_REO2SW2_RING, + HTT_SW_RING_IDX_REO_REO2SW3_RING, + HTT_SW_RING_IDX_REO_REO2SW4_RING, + HTT_SW_RING_IDX_REO_WBM2REO_LINK_RING, + HTT_SW_RING_IDX_REO_REO2TCL_RING, + HTT_SW_RING_IDX_REO_REO2FW_RING, + HTT_SW_RING_IDX_REO_REO_RELEASE_RING, + HTT_SW_RING_IDX_WBM_PPE_RELEASE_RING, + HTT_SW_RING_IDX_TCL_TCL2TQM_RING, + HTT_SW_RING_IDX_WBM_TQM_RELEASE_RING, + HTT_SW_RING_IDX_WBM_REO_RELEASE_RING, + HTT_SW_RING_IDX_WBM_WBM2SW0_RELEASE_RING, + HTT_SW_RING_IDX_WBM_WBM2SW1_RELEASE_RING, + HTT_SW_RING_IDX_WBM_WBM2SW2_RELEASE_RING, + HTT_SW_RING_IDX_WBM_WBM2SW3_RELEASE_RING, + HTT_SW_RING_IDX_REO_REO_CMD_RING, + HTT_SW_RING_IDX_REO_REO_STATUS_RING, + HTT_SW_UMAC_RING_IDX_MAX, +}; + +enum htt_backpressure_lmac_ringid { + HTT_SW_RING_IDX_FW2RXDMA_BUF_RING, + HTT_SW_RING_IDX_FW2RXDMA_STATUS_RING, + HTT_SW_RING_IDX_FW2RXDMA_LINK_RING, + HTT_SW_RING_IDX_SW2RXDMA_BUF_RING, + HTT_SW_RING_IDX_WBM2RXDMA_LINK_RING, + HTT_SW_RING_IDX_RXDMA2FW_RING, + HTT_SW_RING_IDX_RXDMA2SW_RING, + HTT_SW_RING_IDX_RXDMA2RELEASE_RING, + HTT_SW_RING_IDX_RXDMA2REO_RING, + HTT_SW_RING_IDX_MONITOR_STATUS_RING, + HTT_SW_RING_IDX_MONITOR_BUF_RING, + HTT_SW_RING_IDX_MONITOR_DESC_RING, + HTT_SW_RING_IDX_MONITOR_DEST_RING, + HTT_SW_LMAC_RING_IDX_MAX, +}; + /* ppdu stats * * @details diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index a54610d75c40..791d971784ce 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -653,10 +653,8 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx, spin_lock_bh(&dp->reo_cmd_lock); list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list); dp->reo_cmd_cache_flush_count++; - spin_unlock_bh(&dp->reo_cmd_lock); /* Flush and invalidate aged REO desc from HW cache */ - spin_lock_bh(&dp->reo_cmd_lock); list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list, list) { if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD || @@ -1503,9 +1501,10 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, struct sk_buff *skb) { u32 *data = (u32 *)skb->data; - u8 pdev_id, ring_type, ring_id; + u8 pdev_id, ring_type, ring_id, pdev_idx; u16 hp, tp; u32 backpressure_time; + struct ath11k_bp_stats *bp_stats; pdev_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_PDEV_ID_M, *data); ring_type = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_TYPE_M, *data); @@ -1520,6 +1519,31 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n", pdev_id, ring_type, ring_id, hp, tp, backpressure_time); + + if (ring_type == HTT_BACKPRESSURE_UMAC_RING_TYPE) { + if (ring_id >= HTT_SW_UMAC_RING_IDX_MAX) + return; + + bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[ring_id]; + } else if (ring_type == HTT_BACKPRESSURE_LMAC_RING_TYPE) { + pdev_idx = DP_HW2SW_MACID(pdev_id); + + if (ring_id >= HTT_SW_LMAC_RING_IDX_MAX || pdev_idx >= MAX_RADIOS) + return; + + bp_stats = &ab->soc_stats.bp_stats.lmac_ring_bp_stats[ring_id][pdev_idx]; + } else { + ath11k_warn(ab, "unknown ring type received in htt bp event %d\n", + ring_type); + return; + } + + spin_lock_bh(&ab->base_lock); + bp_stats->hp = hp; + bp_stats->tp = tp; + bp_stats->count++; + bp_stats->jiffies = jiffies; + spin_unlock_bh(&ab->base_lock); } void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, @@ -2162,6 +2186,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, struct ieee80211_rx_status *rx_status) { u8 channel_num; + u32 center_freq; rx_status->freq = 0; rx_status->rate_idx = 0; @@ -2172,8 +2197,11 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc); + center_freq = ath11k_dp_rx_h_msdu_start_freq(rx_desc) >> 16; - if (channel_num >= 1 && channel_num <= 14) { + if (center_freq >= 5935 && center_freq <= 7105) { + rx_status->band = NL80211_BAND_6GHZ; + } else if (channel_num >= 1 && channel_num <= 14) { rx_status->band = NL80211_BAND_2GHZ; } else if (channel_num >= 36 && channel_num <= 173) { rx_status->band = NL80211_BAND_5GHZ; diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 41c990aec6b7..1af76775b1a8 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -121,8 +121,10 @@ tcl_ring_sel: spin_unlock_bh(&tx_ring->tx_idr_lock); if (ret < 0) { - if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) + if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); return -ENOSPC; + } /* Check if the next ring is available */ ring_selector++; @@ -180,11 +182,13 @@ tcl_ring_sel: default: /* TODO: Take care of other encap modes as well */ ret = -EINVAL; + atomic_inc(&ab->soc_stats.tx_err.misc_fail); goto fail_remove_idr; } ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); if (dma_mapping_error(ab->dev, ti.paddr)) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); ath11k_warn(ab, "failed to DMA map data Tx buffer\n"); ret = -ENOMEM; goto fail_remove_idr; @@ -208,6 +212,7 @@ tcl_ring_sel: * desc because the desc is directly enqueued onto hw queue. */ ath11k_hal_srng_access_end(ab, tcl_ring); + ab->soc_stats.tx_err.desc_na[ti.ring_id]++; spin_unlock_bh(&tcl_ring->lock); ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 2836a0f197ab..94ae2b9ea663 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -33,6 +33,15 @@ .max_power = 30, \ } +#define CHAN6G(_channel, _freq, _flags) { \ + .band = NL80211_BAND_6GHZ, \ + .hw_value = (_channel), \ + .center_freq = (_freq), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + /* frame mode values are mapped as per enum ath11k_hw_txrx_mode */ static unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI; module_param_named(frame_mode, ath11k_frame_mode, uint, 0644); @@ -86,6 +95,68 @@ static const struct ieee80211_channel ath11k_5ghz_channels[] = { CHAN5G(173, 5865, 0), }; +static const struct ieee80211_channel ath11k_6ghz_channels[] = { + CHAN6G(1, 5955, 0), + CHAN6G(5, 5975, 0), + CHAN6G(9, 5995, 0), + CHAN6G(13, 6015, 0), + CHAN6G(17, 6035, 0), + CHAN6G(21, 6055, 0), + CHAN6G(25, 6075, 0), + CHAN6G(29, 6095, 0), + CHAN6G(33, 6115, 0), + CHAN6G(37, 6135, 0), + CHAN6G(41, 6155, 0), + CHAN6G(45, 6175, 0), + CHAN6G(49, 6195, 0), + CHAN6G(53, 6215, 0), + CHAN6G(57, 6235, 0), + CHAN6G(61, 6255, 0), + CHAN6G(65, 6275, 0), + CHAN6G(69, 6295, 0), + CHAN6G(73, 6315, 0), + CHAN6G(77, 6335, 0), + CHAN6G(81, 6355, 0), + CHAN6G(85, 6375, 0), + CHAN6G(89, 6395, 0), + CHAN6G(93, 6415, 0), + CHAN6G(97, 6435, 0), + CHAN6G(101, 6455, 0), + CHAN6G(105, 6475, 0), + CHAN6G(109, 6495, 0), + CHAN6G(113, 6515, 0), + CHAN6G(117, 6535, 0), + CHAN6G(121, 6555, 0), + CHAN6G(125, 6575, 0), + CHAN6G(129, 6595, 0), + CHAN6G(133, 6615, 0), + CHAN6G(137, 6635, 0), + CHAN6G(141, 6655, 0), + CHAN6G(145, 6675, 0), + CHAN6G(149, 6695, 0), + CHAN6G(153, 6715, 0), + CHAN6G(157, 6735, 0), + CHAN6G(161, 6755, 0), + CHAN6G(165, 6775, 0), + CHAN6G(169, 6795, 0), + CHAN6G(173, 6815, 0), + CHAN6G(177, 6835, 0), + CHAN6G(181, 6855, 0), + CHAN6G(185, 6875, 0), + CHAN6G(189, 6895, 0), + CHAN6G(193, 6915, 0), + CHAN6G(197, 6935, 0), + CHAN6G(201, 6955, 0), + CHAN6G(205, 6975, 0), + CHAN6G(209, 6995, 0), + CHAN6G(213, 7015, 0), + CHAN6G(217, 7035, 0), + CHAN6G(221, 7055, 0), + CHAN6G(225, 7075, 0), + CHAN6G(229, 7095, 0), + CHAN6G(233, 7115, 0), +}; + static struct ieee80211_rate ath11k_legacy_rates[] = { { .bitrate = 10, .hw_value = ATH11K_HW_RATE_CCK_LP_1M }, @@ -134,6 +205,17 @@ ath11k_phymodes[NUM_NL80211_BANDS][ATH11K_CHAN_WIDTH_NUM] = { [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160, [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80, }, + [NL80211_BAND_6GHZ] = { + [NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN, + [NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN, + [NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20, + [NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20, + [NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40, + [NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80, + [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160, + [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80, + }, + }; const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default = { @@ -698,6 +780,8 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; struct sk_buff *bcn; + struct ieee80211_mgmt *mgmt; + u8 *ies; int ret; if (arvif->vdev_type != WMI_VDEV_TYPE_AP) @@ -709,6 +793,17 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) return -EPERM; } + ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); + ies += sizeof(mgmt->u.beacon); + + if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies))) + arvif->rsnie_present = true; + + if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + ies, (skb_tail_pointer(bcn) - ies))) + arvif->wpaie_present = true; + ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); kfree_skb(bcn); @@ -798,6 +893,7 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar, struct ieee80211_bss_conf *info = &vif->bss_conf; struct cfg80211_chan_def def; struct cfg80211_bss *bss; + struct ath11k_vif *arvif = (struct ath11k_vif *)vif->drv_priv; const u8 *rsnie = NULL; const u8 *wpaie = NULL; @@ -808,7 +904,12 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar, bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (bss) { + + if (arvif->rsnie_present || arvif->wpaie_present) { + arg->need_ptk_4_way = true; + if (arvif->wpaie_present) + arg->need_gtk_2_way = true; + } else if (bss) { const struct cfg80211_bss_ies *ies; rcu_read_lock(); @@ -1489,6 +1590,7 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, } break; case NL80211_BAND_5GHZ: + case NL80211_BAND_6GHZ: /* Check HE first */ if (sta->he_cap.has_he) { phymode = ath11k_mac_get_phymode_he(ar, sta); @@ -1970,7 +2072,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ret = ath11k_wmi_send_obss_color_collision_cfg_cmd( ar, arvif->vdev_id, info->he_bss_color.color, ATH11K_BSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS, - !info->he_bss_color.disabled); + info->he_bss_color.enabled); if (ret) ath11k_warn(ar->ab, "failed to set bss color collision on vdev %i: %d\n", arvif->vdev_id, ret); @@ -2125,6 +2227,9 @@ static int ath11k_start_scan(struct ath11k *ar, lockdep_assert_held(&ar->conf_mutex); + if (ath11k_spectral_get_mode(ar) == ATH11K_SPECTRAL_BACKGROUND) + ath11k_spectral_reset_buffer(ar); + ret = ath11k_wmi_send_scan_start_cmd(ar, arg); if (ret) return ret; @@ -3411,7 +3516,7 @@ static void ath11k_mac_setup_ht_vht_cap(struct ath11k *ar, rate_cap_rx_chainmask); } - if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) { + if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && !ar->supports_6ghz) { band = &ar->mac.sbands[NL80211_BAND_5GHZ]; ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info; if (ht_cap_info) @@ -3532,6 +3637,35 @@ ath11k_mac_filter_he_cap_mesh(struct ieee80211_he_cap_elem *he_cap_elem) he_cap_elem->phy_cap_info[9] &= ~m; } +static __le16 ath11k_mac_setup_he_6ghz_cap(struct ath11k_pdev_cap *pcap, + struct ath11k_band_cap *bcap) +{ + u8 val; + + bcap->he_6ghz_capa = IEEE80211_HT_MPDU_DENSITY_NONE; + if (bcap->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) + bcap->he_6ghz_capa |= + FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS, + WLAN_HT_CAP_SM_PS_DYNAMIC); + else + bcap->he_6ghz_capa |= + FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS, + WLAN_HT_CAP_SM_PS_DISABLED); + val = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + pcap->vht_cap); + bcap->he_6ghz_capa |= + FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP, val); + val = FIELD_GET(IEEE80211_VHT_CAP_MAX_MPDU_MASK, pcap->vht_cap); + bcap->he_6ghz_capa |= + FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN, val); + if (pcap->vht_cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN) + bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; + if (pcap->vht_cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN) + bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS; + + return cpu_to_le16(bcap->he_6ghz_capa); +} + static int ath11k_mac_copy_he_cap(struct ath11k *ar, struct ath11k_pdev_cap *cap, struct ieee80211_sband_iftype_data *data, @@ -3614,6 +3748,11 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) ath11k_gen_ppe_thresh(&band_cap->he_ppet, he_cap->ppe_thres); + + if (band == NL80211_BAND_6GHZ) { + data[idx].he_6ghz_capa.capa = + ath11k_mac_setup_he_6ghz_cap(cap, band_cap); + } idx++; } @@ -3643,6 +3782,16 @@ static void ath11k_mac_setup_he_cap(struct ath11k *ar, band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ]; band->n_iftype_data = count; } + + if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && + ar->supports_6ghz) { + count = ath11k_mac_copy_he_cap(ar, cap, + ar->mac.iftype[NL80211_BAND_6GHZ], + NL80211_BAND_6GHZ); + band = &ar->mac.sbands[NL80211_BAND_6GHZ]; + band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ]; + band->n_iftype_data = count; + } } static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant) @@ -4085,6 +4234,11 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, params->chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains; params->chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains; } + if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP && + ar->supports_6ghz) { + params->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains; + params->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains; + } } static u32 @@ -5217,7 +5371,7 @@ ath11k_mac_get_single_legacy_rate(struct ath11k *ar, rate_idx = ffs(mask->control[band].legacy) - 1; - if (band == NL80211_BAND_5GHZ) + if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ) rate_idx += ATH11K_MAC_FIRST_OFDM_RATE_IDX; hw_rate = ath11k_legacy_rates[rate_idx].hw_value; @@ -5683,7 +5837,8 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, void *channels; BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) + - ARRAY_SIZE(ath11k_5ghz_channels)) != + ARRAY_SIZE(ath11k_5ghz_channels) + + ARRAY_SIZE(ath11k_6ghz_channels)) != ATH11K_NUM_CHANS); reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx]; @@ -5696,6 +5851,7 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, return -ENOMEM; band = &ar->mac.sbands[NL80211_BAND_2GHZ]; + band->band = NL80211_BAND_2GHZ; band->n_channels = ARRAY_SIZE(ath11k_2ghz_channels); band->channels = channels; band->n_bitrates = ath11k_g_rates_size; @@ -5707,23 +5863,48 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, } if (supported_bands & WMI_HOST_WLAN_5G_CAP) { - channels = kmemdup(ath11k_5ghz_channels, - sizeof(ath11k_5ghz_channels), - GFP_KERNEL); - if (!channels) { - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - return -ENOMEM; + if (reg_cap->high_5ghz_chan >= ATH11K_MAX_6G_FREQ) { + channels = kmemdup(ath11k_6ghz_channels, + sizeof(ath11k_6ghz_channels), GFP_KERNEL); + if (!channels) { + kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); + return -ENOMEM; + } + + ar->supports_6ghz = true; + band = &ar->mac.sbands[NL80211_BAND_6GHZ]; + band->band = NL80211_BAND_6GHZ; + band->n_channels = ARRAY_SIZE(ath11k_6ghz_channels); + band->channels = channels; + band->n_bitrates = ath11k_a_rates_size; + band->bitrates = ath11k_a_rates; + ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band; + ath11k_mac_update_ch_list(ar, band, + reg_cap->low_5ghz_chan, + reg_cap->high_5ghz_chan); } - band = &ar->mac.sbands[NL80211_BAND_5GHZ]; - band->n_channels = ARRAY_SIZE(ath11k_5ghz_channels); - band->channels = channels; - band->n_bitrates = ath11k_a_rates_size; - band->bitrates = ath11k_a_rates; - ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; - ath11k_mac_update_ch_list(ar, band, - reg_cap->low_5ghz_chan, - reg_cap->high_5ghz_chan); + if (reg_cap->low_5ghz_chan < ATH11K_MIN_6G_FREQ) { + channels = kmemdup(ath11k_5ghz_channels, + sizeof(ath11k_5ghz_channels), + GFP_KERNEL); + if (!channels) { + kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); + kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); + return -ENOMEM; + } + + band = &ar->mac.sbands[NL80211_BAND_5GHZ]; + band->band = NL80211_BAND_5GHZ; + band->n_channels = ARRAY_SIZE(ath11k_5ghz_channels); + band->channels = channels; + band->n_bitrates = ath11k_a_rates_size; + band->bitrates = ath11k_a_rates; + ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + ath11k_mac_update_ch_list(ar, band, + reg_cap->low_5ghz_chan, + reg_cap->high_5ghz_chan); + } } return 0; @@ -5777,6 +5958,7 @@ static void __ath11k_mac_unregister(struct ath11k *ar) kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); + kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); SET_IEEE80211_DEV(ar->hw, NULL); } diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 453aa9c06969..7c9dc91cc48a 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -161,6 +161,10 @@ int ath11k_reg_update_chan_list(struct ath11k *ar) else ch->phy_mode = MODE_11A; + if (channel->band == NL80211_BAND_6GHZ && + cfg80211_channel_is_psc(channel)) + ch->psc_channel = true; + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "mac channel [%d/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", i, params->nallchans, diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c new file mode 100644 index 000000000000..1c5d65bb411f --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -0,0 +1,1023 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + */ + +#include <linux/relay.h> +#include "core.h" +#include "debug.h" + +#define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT 2 +#define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 + +#define ATH11K_SPECTRAL_DWORD_SIZE 4 +/* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes */ +#define ATH11K_SPECTRAL_BIN_SIZE 4 +#define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64 +#define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32 +#define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256 + +#define ATH11K_SPECTRAL_SAMPLE_FFT_BIN_MASK 0xFF + +#define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095 + +/* Max channel computed by sum of 2g and 5g band channels */ +#define ATH11K_SPECTRAL_TOTAL_CHANNEL 41 +#define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70 +#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE (sizeof(struct fft_sample_ath11k) + \ + ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS) +#define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \ + ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL) +#define ATH11K_SPECTRAL_SUB_BUFF_SIZE ATH11K_SPECTRAL_PER_SAMPLE_SIZE +#define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE + +#define ATH11K_SPECTRAL_20MHZ 20 +#define ATH11K_SPECTRAL_40MHZ 40 +#define ATH11K_SPECTRAL_80MHZ 80 + +#define ATH11K_SPECTRAL_SIGNATURE 0xFA + +#define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY 0x0 +#define ATH11K_SPECTRAL_TAG_RADAR_FFT 0x1 +#define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY 0x2 +#define ATH11K_SPECTRAL_TAG_SCAN_SEARCH 0x3 + +#define SPECTRAL_TLV_HDR_LEN GENMASK(15, 0) +#define SPECTRAL_TLV_HDR_TAG GENMASK(23, 16) +#define SPECTRAL_TLV_HDR_SIGN GENMASK(31, 24) + +#define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN GENMASK(7, 0) +#define SPECTRAL_SUMMARY_INFO0_OB_FLAG BIT(8) +#define SPECTRAL_SUMMARY_INFO0_GRP_IDX GENMASK(16, 9) +#define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT BIT(17) +#define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB GENMASK(27, 18) +#define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN BIT(28) +#define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID GENMASK(30, 29) +#define SPECTRAL_SUMMARY_INFO0_PRI80 BIT(31) + +#define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX GENMASK(11, 0) +#define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE GENMASK(21, 12) +#define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK GENMASK(29, 22) +#define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE BIT(30) + +struct spectral_tlv { + __le32 timestamp; + __le32 header; +} __packed; + +struct spectral_summary_fft_report { + __le32 timestamp; + __le32 tlv_header; + __le32 info0; + __le32 reserve0; + __le32 info2; + __le32 reserve1; +} __packed; + +struct ath11k_spectral_summary_report { + struct wmi_dma_buf_release_meta_data meta; + u32 timestamp; + u8 agc_total_gain; + u8 grp_idx; + u16 inb_pwr_db; + s16 peak_idx; + u16 peak_mag; + u8 detector_id; + bool out_of_band_flag; + bool rf_saturation; + bool primary80; + bool gain_change; + bool false_scan; +}; + +#define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID GENMASK(1, 0) +#define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM GENMASK(4, 2) +#define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK GENMASK(16, 5) +#define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX GENMASK(27, 17) +#define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX GENMASK(30, 28) + +#define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB GENMASK(8, 0) +#define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB GENMASK(16, 9) + +#define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS GENMASK(7, 0) +#define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE GENMASK(17, 8) +#define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB GENMASK(24, 18) +#define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB GENMASK(31, 25) + +struct spectral_search_fft_report { + __le32 timestamp; + __le32 tlv_header; + __le32 info0; + __le32 info1; + __le32 info2; + __le32 reserve0; + u8 bins[0]; +} __packed; + +struct ath11k_spectral_search_report { + u32 timestamp; + u8 detector_id; + u8 fft_count; + u16 radar_check; + s16 peak_idx; + u8 chain_idx; + u16 base_pwr_db; + u8 total_gain_db; + u8 strong_bin_count; + u16 peak_mag; + u8 avg_pwr_db; + u8 rel_pwr_db; +}; + +static struct dentry *create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct dentry *buf_file; + + buf_file = debugfs_create_file(filename, mode, parent, buf, + &relay_file_operations); + *is_global = 1; + return buf_file; +} + +static int remove_buf_file_handler(struct dentry *dentry) +{ + debugfs_remove(dentry); + + return 0; +} + +static struct rchan_callbacks rfs_scan_cb = { + .create_buf_file = create_buf_file_handler, + .remove_buf_file = remove_buf_file_handler, +}; + +static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar) +{ + struct ath11k_vif *arvif; + + lockdep_assert_held(&ar->conf_mutex); + + if (list_empty(&ar->arvifs)) + return NULL; + + /* if there already is a vif doing spectral, return that. */ + list_for_each_entry(arvif, &ar->arvifs, list) + if (arvif->spectral_enabled) + return arvif; + + /* otherwise, return the first vif. */ + return list_first_entry(&ar->arvifs, typeof(*arvif), list); +} + +static int ath11k_spectral_scan_trigger(struct ath11k *ar) +{ + struct ath11k_vif *arvif; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + arvif = ath11k_spectral_get_vdev(ar); + if (!arvif) + return -ENODEV; + + if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED) + return 0; + + ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id, + ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR, + ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE); + if (ret) + return ret; + + ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id, + ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER, + ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE); + if (ret) + return ret; + + return 0; +} + +static int ath11k_spectral_scan_config(struct ath11k *ar, + enum ath11k_spectral_mode mode) +{ + struct ath11k_wmi_vdev_spectral_conf_param param = { 0 }; + struct ath11k_vif *arvif; + int ret, count; + + lockdep_assert_held(&ar->conf_mutex); + + arvif = ath11k_spectral_get_vdev(ar); + if (!arvif) + return -ENODEV; + + arvif->spectral_enabled = (mode != ATH11K_SPECTRAL_DISABLED); + ar->spectral.mode = mode; + + ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id, + ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR, + ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE); + if (ret) { + ath11k_warn(ar->ab, "failed to enable spectral scan: %d\n", ret); + return ret; + } + + if (mode == ATH11K_SPECTRAL_DISABLED) + return 0; + + if (mode == ATH11K_SPECTRAL_BACKGROUND) + count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT; + else + count = max_t(u16, 1, ar->spectral.count); + + param.vdev_id = arvif->vdev_id; + param.scan_count = count; + param.scan_fft_size = ar->spectral.fft_size; + param.scan_period = ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT; + param.scan_priority = ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT; + param.scan_gc_ena = ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT; + param.scan_restart_ena = ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT; + param.scan_noise_floor_ref = ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT; + param.scan_init_delay = ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT; + param.scan_nb_tone_thr = ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT; + param.scan_str_bin_thr = ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT; + param.scan_wb_rpt_mode = ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT; + param.scan_rssi_rpt_mode = ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT; + param.scan_rssi_thr = ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT; + param.scan_pwr_format = ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT; + param.scan_rpt_mode = ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT; + param.scan_bin_scale = ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT; + param.scan_dbm_adj = ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT; + param.scan_chn_mask = ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT; + + ret = ath11k_wmi_vdev_spectral_conf(ar, ¶m); + if (ret) { + ath11k_warn(ar->ab, "failed to configure spectral scan: %d\n", ret); + return ret; + } + + return 0; +} + +static ssize_t ath11k_read_file_spec_scan_ctl(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char *mode = ""; + size_t len; + enum ath11k_spectral_mode spectral_mode; + + mutex_lock(&ar->conf_mutex); + spectral_mode = ar->spectral.mode; + mutex_unlock(&ar->conf_mutex); + + switch (spectral_mode) { + case ATH11K_SPECTRAL_DISABLED: + mode = "disable"; + break; + case ATH11K_SPECTRAL_BACKGROUND: + mode = "background"; + break; + case ATH11K_SPECTRAL_MANUAL: + mode = "manual"; + break; + } + + len = strlen(mode); + return simple_read_from_buffer(user_buf, count, ppos, mode, len); +} + +static ssize_t ath11k_write_file_spec_scan_ctl(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[32]; + ssize_t len; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + + mutex_lock(&ar->conf_mutex); + + if (strncmp("trigger", buf, 7) == 0) { + if (ar->spectral.mode == ATH11K_SPECTRAL_MANUAL || + ar->spectral.mode == ATH11K_SPECTRAL_BACKGROUND) { + /* reset the configuration to adopt possibly changed + * debugfs parameters + */ + ret = ath11k_spectral_scan_config(ar, ar->spectral.mode); + if (ret) { + ath11k_warn(ar->ab, "failed to reconfigure spectral scan: %d\n", + ret); + goto unlock; + } + + ret = ath11k_spectral_scan_trigger(ar); + if (ret) { + ath11k_warn(ar->ab, "failed to trigger spectral scan: %d\n", + ret); + } + } else { + ret = -EINVAL; + } + } else if (strncmp("background", buf, 10) == 0) { + ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_BACKGROUND); + } else if (strncmp("manual", buf, 6) == 0) { + ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_MANUAL); + } else if (strncmp("disable", buf, 7) == 0) { + ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED); + } else { + ret = -EINVAL; + } + +unlock: + mutex_unlock(&ar->conf_mutex); + + if (ret) + return ret; + + return count; +} + +static const struct file_operations fops_scan_ctl = { + .read = ath11k_read_file_spec_scan_ctl, + .write = ath11k_write_file_spec_scan_ctl, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath11k_read_file_spectral_count(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[32]; + size_t len; + u16 spectral_count; + + mutex_lock(&ar->conf_mutex); + spectral_count = ar->spectral.count; + mutex_unlock(&ar->conf_mutex); + + len = sprintf(buf, "%d\n", spectral_count); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_file_spectral_count(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + ar->spectral.count = val; + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_scan_count = { + .read = ath11k_read_file_spectral_count, + .write = ath11k_write_file_spectral_count, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath11k_read_file_spectral_bins(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + char buf[32]; + unsigned int bins, fft_size; + size_t len; + + mutex_lock(&ar->conf_mutex); + + fft_size = ar->spectral.fft_size; + bins = 1 << fft_size; + + mutex_unlock(&ar->conf_mutex); + + len = sprintf(buf, "%d\n", bins); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath11k_write_file_spectral_bins(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath11k *ar = file->private_data; + unsigned long val; + char buf[32]; + ssize_t len; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < ATH11K_SPECTRAL_ATH11K_MIN_BINS || + val > SPECTRAL_ATH11K_MAX_NUM_BINS) + return -EINVAL; + + if (!is_power_of_2(val)) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + ar->spectral.fft_size = ilog2(val); + mutex_unlock(&ar->conf_mutex); + + return count; +} + +static const struct file_operations fops_scan_bins = { + .read = ath11k_read_file_spectral_bins, + .write = ath11k_write_file_spectral_bins, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static int ath11k_spectral_pull_summary(struct ath11k *ar, + struct wmi_dma_buf_release_meta_data *meta, + struct spectral_summary_fft_report *summary, + struct ath11k_spectral_summary_report *report) +{ + report->timestamp = __le32_to_cpu(summary->timestamp); + report->agc_total_gain = FIELD_GET(SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN, + __le32_to_cpu(summary->info0)); + report->out_of_band_flag = FIELD_GET(SPECTRAL_SUMMARY_INFO0_OB_FLAG, + __le32_to_cpu(summary->info0)); + report->grp_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO0_GRP_IDX, + __le32_to_cpu(summary->info0)); + report->rf_saturation = FIELD_GET(SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT, + __le32_to_cpu(summary->info0)); + report->inb_pwr_db = FIELD_GET(SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB, + __le32_to_cpu(summary->info0)); + report->false_scan = FIELD_GET(SPECTRAL_SUMMARY_INFO0_FALSE_SCAN, + __le32_to_cpu(summary->info0)); + report->detector_id = FIELD_GET(SPECTRAL_SUMMARY_INFO0_DETECTOR_ID, + __le32_to_cpu(summary->info0)); + report->primary80 = FIELD_GET(SPECTRAL_SUMMARY_INFO0_PRI80, + __le32_to_cpu(summary->info0)); + report->peak_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX, + __le32_to_cpu(summary->info2)); + report->peak_mag = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE, + __le32_to_cpu(summary->info2)); + report->gain_change = FIELD_GET(SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE, + __le32_to_cpu(summary->info2)); + + memcpy(&report->meta, meta, sizeof(*meta)); + + return 0; +} + +static int ath11k_spectral_pull_search(struct ath11k *ar, + struct spectral_search_fft_report *search, + struct ath11k_spectral_search_report *report) +{ + report->timestamp = __le32_to_cpu(search->timestamp); + report->detector_id = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID, + __le32_to_cpu(search->info0)); + report->fft_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_FFT_NUM, + __le32_to_cpu(search->info0)); + report->radar_check = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK, + __le32_to_cpu(search->info0)); + report->peak_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX, + __le32_to_cpu(search->info0)); + report->chain_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX, + __le32_to_cpu(search->info0)); + report->base_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB, + __le32_to_cpu(search->info1)); + report->total_gain_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB, + __le32_to_cpu(search->info1)); + report->strong_bin_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS, + __le32_to_cpu(search->info2)); + report->peak_mag = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE, + __le32_to_cpu(search->info2)); + report->avg_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB, + __le32_to_cpu(search->info2)); + report->rel_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB, + __le32_to_cpu(search->info2)); + + return 0; +} + +static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude, + int bin_len, u8 *bins) +{ + int dc_pos; + u8 max_exp; + + dc_pos = bin_len / 2; + + /* peak index outside of bins */ + if (dc_pos <= max_index || -dc_pos >= max_index) + return 0; + + for (max_exp = 0; max_exp < 8; max_exp++) { + if (bins[dc_pos + max_index] == (max_magnitude >> max_exp)) + break; + } + + /* max_exp not found */ + if (bins[dc_pos + max_index] != (max_magnitude >> max_exp)) + return 0; + + return max_exp; +} + +static void ath11k_spectral_parse_16bit_fft(u8 *outbins, u8 *inbins, int num_bins) +{ + int i; + __le16 *data = (__le16 *)inbins; + + i = 0; + while (i < num_bins) { + outbins[i] = (__le16_to_cpu(data[i])) & + ATH11K_SPECTRAL_SAMPLE_FFT_BIN_MASK; + i++; + } +} + +static +int ath11k_spectral_process_fft(struct ath11k *ar, + struct ath11k_spectral_summary_report *summary, + void *data, + struct fft_sample_ath11k *fft_sample, + u32 data_len) +{ + struct ath11k_base *ab = ar->ab; + struct spectral_search_fft_report *fft_report = data; + struct ath11k_spectral_search_report search; + struct spectral_tlv *tlv; + int tlv_len, bin_len, num_bins; + u16 length, freq; + u8 chan_width_mhz; + int ret; + + lockdep_assert_held(&ar->spectral.lock); + + tlv = (struct spectral_tlv *)data; + tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header)); + /* convert Dword into bytes */ + tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; + bin_len = tlv_len - (sizeof(*fft_report) - sizeof(*tlv)); + + if (data_len < (bin_len + sizeof(*fft_report))) { + ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n", + bin_len, data_len); + return -EINVAL; + } + + num_bins = bin_len / ATH11K_SPECTRAL_BIN_SIZE; + /* Only In-band bins are useful to user for visualize */ + num_bins >>= 1; + + if (num_bins < ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS || + num_bins > ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS || + !is_power_of_2(num_bins)) { + ath11k_warn(ab, "Invalid num of bins %d\n", num_bins); + return -EINVAL; + } + + ret = ath11k_spectral_pull_search(ar, data, &search); + if (ret) { + ath11k_warn(ab, "failed to pull search report %d\n", ret); + return ret; + } + + chan_width_mhz = summary->meta.ch_width; + + switch (chan_width_mhz) { + case ATH11K_SPECTRAL_20MHZ: + case ATH11K_SPECTRAL_40MHZ: + case ATH11K_SPECTRAL_80MHZ: + fft_sample->chan_width_mhz = chan_width_mhz; + break; + default: + ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz); + return -EINVAL; + } + + length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + num_bins; + fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH11K; + fft_sample->tlv.length = __cpu_to_be16(length); + + fft_sample->tsf = __cpu_to_be32(search.timestamp); + fft_sample->max_magnitude = __cpu_to_be16(search.peak_mag); + fft_sample->max_index = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX, + __le32_to_cpu(fft_report->info0)); + + summary->inb_pwr_db >>= 1; + fft_sample->rssi = __cpu_to_be16(summary->inb_pwr_db); + fft_sample->noise = __cpu_to_be32(summary->meta.noise_floor[search.chain_idx]); + + freq = summary->meta.freq1; + fft_sample->freq1 = __cpu_to_be16(freq); + + freq = summary->meta.freq2; + fft_sample->freq2 = __cpu_to_be16(freq); + + ath11k_spectral_parse_16bit_fft(fft_sample->data, + fft_report->bins, + num_bins); + + fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index, + search.peak_mag, + num_bins, + fft_sample->data); + + if (ar->spectral.rfs_scan) + relay_write(ar->spectral.rfs_scan, fft_sample, + length + sizeof(struct fft_sample_tlv)); + + return 0; +} + +static int ath11k_spectral_process_data(struct ath11k *ar, + struct ath11k_dbring_data *param) +{ + struct ath11k_base *ab = ar->ab; + struct spectral_tlv *tlv; + struct spectral_summary_fft_report *summary = NULL; + struct ath11k_spectral_summary_report summ_rpt; + struct fft_sample_ath11k *fft_sample = NULL; + u8 *data; + u32 data_len, i; + u8 sign, tag; + int tlv_len, sample_sz; + int ret; + bool quit = false; + + spin_lock_bh(&ar->spectral.lock); + + if (!ar->spectral.enabled) { + ret = -EINVAL; + goto unlock; + } + + sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS; + fft_sample = kmalloc(sample_sz, GFP_ATOMIC); + if (!fft_sample) { + ret = -ENOBUFS; + goto unlock; + } + + data = param->data; + data_len = param->data_sz; + i = 0; + while (!quit && (i < data_len)) { + if ((i + sizeof(*tlv)) > data_len) { + ath11k_warn(ab, "failed to parse spectral tlv hdr at bytes %d\n", + i); + ret = -EINVAL; + goto err; + } + + tlv = (struct spectral_tlv *)&data[i]; + sign = FIELD_GET(SPECTRAL_TLV_HDR_SIGN, + __le32_to_cpu(tlv->header)); + if (sign != ATH11K_SPECTRAL_SIGNATURE) { + ath11k_warn(ab, "Invalid sign 0x%x at bytes %d\n", + sign, i); + ret = -EINVAL; + goto err; + } + + tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, + __le32_to_cpu(tlv->header)); + /* convert Dword into bytes */ + tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; + if ((i + sizeof(*tlv) + tlv_len) > data_len) { + ath11k_warn(ab, "failed to parse spectral tlv payload at bytes %d tlv_len:%d data_len:%d\n", + i, tlv_len, data_len); + ret = -EINVAL; + goto err; + } + + tag = FIELD_GET(SPECTRAL_TLV_HDR_TAG, + __le32_to_cpu(tlv->header)); + switch (tag) { + case ATH11K_SPECTRAL_TAG_SCAN_SUMMARY: + /* HW bug in tlv length of summary report, + * HW report 3 DWORD size but the data payload + * is 4 DWORD size (16 bytes). + * Need to remove this workaround once HW bug fixed + */ + tlv_len = sizeof(*summary) - sizeof(*tlv); + + if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) { + ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n", + i, tlv_len); + ret = -EINVAL; + goto err; + } + + summary = (struct spectral_summary_fft_report *)tlv; + ath11k_spectral_pull_summary(ar, ¶m->meta, + summary, &summ_rpt); + break; + case ATH11K_SPECTRAL_TAG_SCAN_SEARCH: + if (tlv_len < (sizeof(struct spectral_search_fft_report) - + sizeof(*tlv))) { + ath11k_warn(ab, "failed to parse spectral search fft at bytes %d\n", + i); + ret = -EINVAL; + goto err; + } + + memset(fft_sample, 0, sample_sz); + ret = ath11k_spectral_process_fft(ar, &summ_rpt, tlv, + fft_sample, + data_len - i); + if (ret) { + ath11k_warn(ab, "failed to process spectral fft at bytes %d\n", + i); + goto err; + } + quit = true; + break; + } + + i += sizeof(*tlv) + tlv_len; + } + +err: + kfree(fft_sample); +unlock: + spin_unlock_bh(&ar->spectral.lock); + return ret; +} + +static int ath11k_spectral_ring_alloc(struct ath11k *ar, + struct ath11k_dbring_cap *db_cap) +{ + struct ath11k_spectral *sp = &ar->spectral; + int ret; + + ret = ath11k_dbring_srng_setup(ar, &sp->rx_ring, + 0, db_cap->min_elem); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring\n"); + return ret; + } + + ath11k_dbring_set_cfg(ar, &sp->rx_ring, + ATH11K_SPECTRAL_NUM_RESP_PER_EVENT, + ATH11K_SPECTRAL_EVENT_TIMEOUT_MS, + ath11k_spectral_process_data); + + ret = ath11k_dbring_buf_setup(ar, &sp->rx_ring, db_cap); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring buffer\n"); + goto srng_cleanup; + } + + ret = ath11k_dbring_wmi_cfg_setup(ar, &sp->rx_ring, + WMI_DIRECT_BUF_SPECTRAL); + if (ret) { + ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); + goto buffer_cleanup; + } + + return 0; + +buffer_cleanup: + ath11k_dbring_buf_cleanup(ar, &sp->rx_ring); +srng_cleanup: + ath11k_dbring_srng_cleanup(ar, &sp->rx_ring); + return ret; +} + +static inline void ath11k_spectral_ring_free(struct ath11k *ar) +{ + struct ath11k_spectral *sp = &ar->spectral; + + if (!sp->enabled) + return; + + ath11k_dbring_srng_cleanup(ar, &sp->rx_ring); + ath11k_dbring_buf_cleanup(ar, &sp->rx_ring); +} + +static inline void ath11k_spectral_debug_unregister(struct ath11k *ar) +{ + debugfs_remove(ar->spectral.scan_bins); + ar->spectral.scan_bins = NULL; + + debugfs_remove(ar->spectral.scan_count); + ar->spectral.scan_count = NULL; + + debugfs_remove(ar->spectral.scan_ctl); + ar->spectral.scan_ctl = NULL; + + if (ar->spectral.rfs_scan) { + relay_close(ar->spectral.rfs_scan); + ar->spectral.rfs_scan = NULL; + } +} + +int ath11k_spectral_vif_stop(struct ath11k_vif *arvif) +{ + if (!arvif->spectral_enabled) + return 0; + + return ath11k_spectral_scan_config(arvif->ar, ATH11K_SPECTRAL_DISABLED); +} + +void ath11k_spectral_reset_buffer(struct ath11k *ar) +{ + if (!ar->spectral.enabled) + return; + + if (ar->spectral.rfs_scan) + relay_reset(ar->spectral.rfs_scan); +} + +void ath11k_spectral_deinit(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_spectral *sp; + int i; + + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + sp = &ar->spectral; + + if (!sp->enabled) + continue; + + ath11k_spectral_debug_unregister(ar); + ath11k_spectral_ring_free(ar); + + spin_lock_bh(&sp->lock); + + sp->mode = ATH11K_SPECTRAL_DISABLED; + sp->enabled = false; + + spin_unlock_bh(&sp->lock); + } +} + +static inline int ath11k_spectral_debug_register(struct ath11k *ar) +{ + int ret; + + ar->spectral.rfs_scan = relay_open("spectral_scan", + ar->debug.debugfs_pdev, + ATH11K_SPECTRAL_SUB_BUFF_SIZE, + ATH11K_SPECTRAL_NUM_SUB_BUF, + &rfs_scan_cb, NULL); + if (!ar->spectral.rfs_scan) { + ath11k_warn(ar->ab, "failed to open relay in pdev %d\n", + ar->pdev_idx); + return -EINVAL; + } + + ar->spectral.scan_ctl = debugfs_create_file("spectral_scan_ctl", + 0600, + ar->debug.debugfs_pdev, ar, + &fops_scan_ctl); + if (!ar->spectral.scan_ctl) { + ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n", + ar->pdev_idx); + ret = -EINVAL; + goto debug_unregister; + } + + ar->spectral.scan_count = debugfs_create_file("spectral_count", + 0600, + ar->debug.debugfs_pdev, ar, + &fops_scan_count); + if (!ar->spectral.scan_count) { + ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n", + ar->pdev_idx); + ret = -EINVAL; + goto debug_unregister; + } + + ar->spectral.scan_bins = debugfs_create_file("spectral_bins", + 0600, + ar->debug.debugfs_pdev, ar, + &fops_scan_bins); + if (!ar->spectral.scan_bins) { + ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n", + ar->pdev_idx); + ret = -EINVAL; + goto debug_unregister; + } + + return 0; + +debug_unregister: + ath11k_spectral_debug_unregister(ar); + return ret; +} + +int ath11k_spectral_init(struct ath11k_base *ab) +{ + struct ath11k *ar; + struct ath11k_spectral *sp; + struct ath11k_dbring_cap db_cap; + int ret; + int i; + + if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA, + ab->wmi_ab.svc_map)) { + ath11k_info(ab, "spectral not supported\n"); + return 0; + } + + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + sp = &ar->spectral; + + ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx, + WMI_DIRECT_BUF_SPECTRAL, + &db_cap); + if (ret) { + ath11k_info(ab, "spectral not enabled for pdev %d\n", i); + continue; + } + + idr_init(&sp->rx_ring.bufs_idr); + spin_lock_init(&sp->rx_ring.idr_lock); + spin_lock_init(&sp->lock); + + ret = ath11k_spectral_ring_alloc(ar, &db_cap); + if (ret) { + ath11k_warn(ab, "failed to init spectral ring for pdev %d\n", + i); + goto deinit; + } + + spin_lock_bh(&sp->lock); + + sp->mode = ATH11K_SPECTRAL_DISABLED; + sp->count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT; + sp->fft_size = ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT; + sp->enabled = true; + + spin_unlock_bh(&sp->lock); + + ret = ath11k_spectral_debug_register(ar); + if (ret) { + ath11k_warn(ab, "failed to register spectral for pdev %d\n", + i); + goto deinit; + } + } + + return 0; + +deinit: + ath11k_spectral_deinit(ab); + return ret; +} + +enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar) +{ + if (ar->spectral.enabled) + return ar->spectral.mode; + else + return ATH11K_SPECTRAL_DISABLED; +} + +struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar) +{ + if (ar->spectral.enabled) + return &ar->spectral.rx_ring; + else + return NULL; +} diff --git a/drivers/net/wireless/ath/ath11k/spectral.h b/drivers/net/wireless/ath/ath11k/spectral.h new file mode 100644 index 000000000000..081744265f2a --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/spectral.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + */ + +#ifndef ATH11K_SPECTRAL_H +#define ATH11K_SPECTRAL_H + +#include "../spectral_common.h" +#include "dbring.h" + +/* enum ath11k_spectral_mode: + * + * @SPECTRAL_DISABLED: spectral mode is disabled + * @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with + * something else. + * @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples + * is performed manually. + */ +enum ath11k_spectral_mode { + ATH11K_SPECTRAL_DISABLED = 0, + ATH11K_SPECTRAL_BACKGROUND, + ATH11K_SPECTRAL_MANUAL, +}; + +struct ath11k_spectral { + struct ath11k_dbring rx_ring; + /* Protects enabled */ + spinlock_t lock; + struct rchan *rfs_scan; /* relay(fs) channel for spectral scan */ + struct dentry *scan_ctl; + struct dentry *scan_count; + struct dentry *scan_bins; + enum ath11k_spectral_mode mode; + u16 count; + u8 fft_size; + bool enabled; +}; + +#ifdef CONFIG_ATH11K_SPECTRAL + +int ath11k_spectral_init(struct ath11k_base *ab); +void ath11k_spectral_deinit(struct ath11k_base *ab); +int ath11k_spectral_vif_stop(struct ath11k_vif *arvif); +void ath11k_spectral_reset_buffer(struct ath11k *ar); +enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar); +struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar); + +#else + +static inline int ath11k_spectral_init(struct ath11k_base *ab) +{ + return 0; +} + +static inline void ath11k_spectral_deinit(struct ath11k_base *ab) +{ +} + +static inline int ath11k_spectral_vif_stop(struct ath11k_vif *arvif) +{ + return 0; +} + +static inline void ath11k_spectral_reset_buffer(struct ath11k *ar) +{ +} + +static inline +enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar) +{ + return ATH11K_SPECTRAL_DISABLED; +} + +static inline +struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar) +{ + return NULL; +} + +#endif /* CONFIG_ATH11K_SPECTRAL */ +#endif /* ATH11K_SPECTRAL_H */ diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index c2a972377687..8e3437a65673 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -27,6 +27,11 @@ struct wmi_tlv_svc_ready_parse { bool wmi_svc_bitmap_done; }; +struct wmi_tlv_dma_ring_caps_parse { + struct wmi_dma_ring_capabilities *dma_ring_caps; + u32 n_dma_ring_caps; +}; + struct wmi_tlv_svc_rdy_ext_parse { struct ath11k_service_ext_param param; struct wmi_soc_mac_phy_hw_mode_caps *hw_caps; @@ -39,15 +44,35 @@ struct wmi_tlv_svc_rdy_ext_parse { struct wmi_soc_hal_reg_capabilities *soc_hal_reg_caps; struct wmi_hal_reg_capabilities_ext *ext_hal_reg_caps; u32 n_ext_hal_reg_caps; + struct wmi_tlv_dma_ring_caps_parse dma_caps_parse; bool hw_mode_done; bool mac_phy_done; bool ext_hal_reg_done; + bool mac_phy_chainmask_combo_done; + bool mac_phy_chainmask_cap_done; + bool oem_dma_ring_cap_done; + bool dma_ring_cap_done; +}; + +struct wmi_tlv_svc_rdy_ext2_parse { + struct wmi_tlv_dma_ring_caps_parse dma_caps_parse; + bool dma_ring_cap_done; }; struct wmi_tlv_rdy_parse { u32 num_extra_mac_addr; }; +struct wmi_tlv_dma_buf_release_parse { + struct ath11k_wmi_dma_buf_release_fixed_param fixed; + struct wmi_dma_buf_release_entry *buf_entry; + struct wmi_dma_buf_release_meta_data *meta_data; + u32 num_buf_entry; + u32 num_meta; + bool buf_entry_done; + bool meta_data_done; +}; + static const struct wmi_tlv_policy wmi_tlv_policies[] = { [WMI_TAG_ARRAY_BYTE] = { .min_len = 0 }, @@ -368,6 +393,17 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, sizeof(struct ath11k_ppe_threshold)); + cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; + cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g; + cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g; + cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g; + cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext; + cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g; + memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g, + sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE); + memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, + sizeof(struct ath11k_ppe_threshold)); + return 0; } @@ -1692,10 +1728,10 @@ ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, */ if (param->auth_flag) cmd->peer_flags |= WMI_PEER_AUTH; - if (param->need_ptk_4_way) + if (param->need_ptk_4_way) { cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; - else - cmd->peer_flags &= ~WMI_PEER_NEED_PTK_4_WAY; + cmd->peer_flags &= ~WMI_PEER_AUTH; + } if (param->need_gtk_2_way) cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; /* safe mode bypass the 4-way handshake */ @@ -1778,6 +1814,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, cmd->peer_he_cap_info = param->peer_he_cap_macinfo[0]; cmd->peer_he_cap_info_ext = param->peer_he_cap_macinfo[1]; cmd->peer_he_cap_info_internal = param->peer_he_cap_macinfo_internal; + cmd->peer_he_caps_6ghz = param->peer_he_caps_6ghz; cmd->peer_he_ops = param->peer_he_ops; memcpy(&cmd->peer_he_cap_phy, ¶m->peer_he_cap_phyinfo, sizeof(param->peer_he_cap_phyinfo)); @@ -1831,6 +1868,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, /* HE Rates */ cmd->peer_he_mcs = param->peer_he_mcs_count; + cmd->min_data_rate = param->min_data_rate; ptr += sizeof(*mcs); @@ -1886,6 +1924,8 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, arg->dwell_time_active = 50; arg->dwell_time_active_2g = 0; arg->dwell_time_passive = 150; + arg->dwell_time_active_6g = 40; + arg->dwell_time_passive_6g = 30; arg->min_rest_time = 50; arg->max_rest_time = 500; arg->repeat_probe_time = 0; @@ -1990,6 +2030,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, int i, ret, len; u32 *tmp_ptr; u8 extraie_len_with_pad = 0; + struct hint_short_ssid *s_ssid = NULL; + struct hint_bssid *hint_bssid = NULL; len = sizeof(*cmd); @@ -2011,6 +2053,14 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, roundup(params->extraie.len, sizeof(u32)); len += extraie_len_with_pad; + if (params->num_hint_bssid) + len += TLV_HDR_SIZE + + params->num_hint_bssid * sizeof(struct hint_bssid); + + if (params->num_hint_s_ssid) + len += TLV_HDR_SIZE + + params->num_hint_s_ssid * sizeof(struct hint_short_ssid); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -2032,6 +2082,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, cmd->dwell_time_active = params->dwell_time_active; cmd->dwell_time_active_2g = params->dwell_time_active_2g; cmd->dwell_time_passive = params->dwell_time_passive; + cmd->dwell_time_active_6g = params->dwell_time_active_6g; + cmd->dwell_time_passive_6g = params->dwell_time_passive_6g; cmd->min_rest_time = params->min_rest_time; cmd->max_rest_time = params->max_rest_time; cmd->repeat_probe_time = params->repeat_probe_time; @@ -2109,6 +2161,68 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, ptr += extraie_len_with_pad; + if (params->num_hint_s_ssid) { + len = params->num_hint_s_ssid * sizeof(struct hint_short_ssid); + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + s_ssid = ptr; + for (i = 0; i < params->num_hint_s_ssid; ++i) { + s_ssid->freq_flags = params->hint_s_ssid[i].freq_flags; + s_ssid->short_ssid = params->hint_s_ssid[i].short_ssid; + s_ssid++; + } + ptr += len; + } + + if (params->num_hint_bssid) { + len = params->num_hint_bssid * sizeof(struct hint_bssid); + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + hint_bssid = ptr; + for (i = 0; i < params->num_hint_bssid; ++i) { + hint_bssid->freq_flags = + params->hint_bssid[i].freq_flags; + ether_addr_copy(¶ms->hint_bssid[i].bssid.addr[0], + &hint_bssid->bssid.addr[0]); + hint_bssid++; + } + } + + len = params->num_hint_s_ssid * sizeof(struct hint_short_ssid); + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + if (params->num_hint_s_ssid) { + s_ssid = ptr; + for (i = 0; i < params->num_hint_s_ssid; ++i) { + s_ssid->freq_flags = params->hint_s_ssid[i].freq_flags; + s_ssid->short_ssid = params->hint_s_ssid[i].short_ssid; + s_ssid++; + } + } + ptr += len; + + len = params->num_hint_bssid * sizeof(struct hint_bssid); + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, len); + ptr += TLV_HDR_SIZE; + if (params->num_hint_bssid) { + hint_bssid = ptr; + for (i = 0; i < params->num_hint_bssid; ++i) { + hint_bssid->freq_flags = + params->hint_bssid[i].freq_flags; + ether_addr_copy(¶ms->hint_bssid[i].bssid.addr[0], + &hint_bssid->bssid.addr[0]); + hint_bssid++; + } + } + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID); if (ret) { @@ -2178,91 +2292,110 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, struct wmi_tlv *tlv; void *ptr; int i, ret, len; + u16 num_send_chans, num_sends = 0, max_chan_limit = 0; u32 *reg1, *reg2; - len = sizeof(*cmd) + TLV_HDR_SIZE + - sizeof(*chan_info) * chan_list->nallchans; + tchan_info = &chan_list->ch_param[0]; + while (chan_list->nallchans) { + len = sizeof(*cmd) + TLV_HDR_SIZE; + max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / + sizeof(*chan_info); - skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); - if (!skb) - return -ENOMEM; + if (chan_list->nallchans > max_chan_limit) + num_send_chans = max_chan_limit; + else + num_send_chans = chan_list->nallchans; - cmd = (struct wmi_scan_chan_list_cmd *)skb->data; - cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) | - FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + chan_list->nallchans -= num_send_chans; + len += sizeof(*chan_info) * num_send_chans; - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI no.of chan = %d len = %d\n", chan_list->nallchans, len); - cmd->pdev_id = chan_list->pdev_id; - cmd->num_scan_chans = chan_list->nallchans; - - ptr = skb->data + sizeof(*cmd); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; - len = sizeof(*chan_info) * chan_list->nallchans; - tlv = ptr; - tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | - FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); - ptr += TLV_HDR_SIZE; + cmd = (struct wmi_scan_chan_list_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->pdev_id = chan_list->pdev_id; + cmd->num_scan_chans = num_send_chans; + if (num_sends) + cmd->flags |= WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG; - tchan_info = &chan_list->ch_param[0]; + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI no.of chan = %d len = %d pdev_id = %d num_sends = %d\n", + num_send_chans, len, cmd->pdev_id, num_sends); - for (i = 0; i < chan_list->nallchans; ++i) { - chan_info = ptr; - memset(chan_info, 0, sizeof(*chan_info)); - len = sizeof(*chan_info); - chan_info->tlv_header = FIELD_PREP(WMI_TLV_TAG, - WMI_TAG_CHANNEL) | - FIELD_PREP(WMI_TLV_LEN, - len - TLV_HDR_SIZE); - - reg1 = &chan_info->reg_info_1; - reg2 = &chan_info->reg_info_2; - chan_info->mhz = tchan_info->mhz; - chan_info->band_center_freq1 = tchan_info->cfreq1; - chan_info->band_center_freq2 = tchan_info->cfreq2; - - if (tchan_info->is_chan_passive) - chan_info->info |= WMI_CHAN_INFO_PASSIVE; - if (tchan_info->allow_he) - chan_info->info |= WMI_CHAN_INFO_ALLOW_HE; - else if (tchan_info->allow_vht) - chan_info->info |= WMI_CHAN_INFO_ALLOW_VHT; - else if (tchan_info->allow_ht) - chan_info->info |= WMI_CHAN_INFO_ALLOW_HT; - if (tchan_info->half_rate) - chan_info->info |= WMI_CHAN_INFO_HALF_RATE; - if (tchan_info->quarter_rate) - chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE; - - chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, - tchan_info->phy_mode); - *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MIN_PWR, - tchan_info->minpower); - *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR, - tchan_info->maxpower); - *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR, - tchan_info->maxregpower); - *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_REG_CLS, - tchan_info->reg_class_id); - *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX, - tchan_info->antennamax); + ptr = skb->data + sizeof(*cmd); - ath11k_dbg(ar->ab, ATH11K_DBG_WMI, - "WMI chan scan list chan[%d] = %u\n", - i, chan_info->mhz); + len = sizeof(*chan_info) * num_send_chans; + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + ptr += TLV_HDR_SIZE; - ptr += sizeof(*chan_info); + for (i = 0; i < num_send_chans; ++i) { + chan_info = ptr; + memset(chan_info, 0, sizeof(*chan_info)); + len = sizeof(*chan_info); + chan_info->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_CHANNEL) | + FIELD_PREP(WMI_TLV_LEN, + len - TLV_HDR_SIZE); + + reg1 = &chan_info->reg_info_1; + reg2 = &chan_info->reg_info_2; + chan_info->mhz = tchan_info->mhz; + chan_info->band_center_freq1 = tchan_info->cfreq1; + chan_info->band_center_freq2 = tchan_info->cfreq2; + + if (tchan_info->is_chan_passive) + chan_info->info |= WMI_CHAN_INFO_PASSIVE; + if (tchan_info->allow_he) + chan_info->info |= WMI_CHAN_INFO_ALLOW_HE; + else if (tchan_info->allow_vht) + chan_info->info |= WMI_CHAN_INFO_ALLOW_VHT; + else if (tchan_info->allow_ht) + chan_info->info |= WMI_CHAN_INFO_ALLOW_HT; + if (tchan_info->half_rate) + chan_info->info |= WMI_CHAN_INFO_HALF_RATE; + if (tchan_info->quarter_rate) + chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE; + if (tchan_info->psc_channel) + chan_info->info |= WMI_CHAN_INFO_PSC; + + chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, + tchan_info->phy_mode); + *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MIN_PWR, + tchan_info->minpower); + *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_PWR, + tchan_info->maxpower); + *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_MAX_REG_PWR, + tchan_info->maxregpower); + *reg1 |= FIELD_PREP(WMI_CHAN_REG_INFO1_REG_CLS, + tchan_info->reg_class_id); + *reg2 |= FIELD_PREP(WMI_CHAN_REG_INFO2_ANT_MAX, + tchan_info->antennamax); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n", + i, chan_info->mhz, chan_info->info); + + ptr += sizeof(*chan_info); + + tchan_info++; + } - tchan_info++; - } + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SCAN_CHAN_LIST_CMDID); + if (ret) { + ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n"); + dev_kfree_skb(skb); + return ret; + } - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_SCAN_CHAN_LIST_CMDID); - if (ret) { - ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n"); - dev_kfree_skb(skb); + num_sends++; } - return ret; + return 0; } int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id, @@ -3265,6 +3398,236 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param); } +int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar, + struct ath11k_wmi_vdev_spectral_conf_param *param) +{ + struct ath11k_wmi_vdev_spectral_conf_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct ath11k_wmi_vdev_spectral_conf_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_VDEV_SPECTRAL_CONFIGURE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + memcpy(&cmd->param, param, sizeof(*param)); + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, + WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "failed to send spectral scan config wmi cmd\n"); + goto err; + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI spectral scan config cmd vdev_id 0x%x\n", + param->vdev_id); + + return 0; +err: + dev_kfree_skb(skb); + return ret; +} + +int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id, + u32 trigger, u32 enable) +{ + struct ath11k_wmi_vdev_spectral_enable_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct ath11k_wmi_vdev_spectral_enable_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_VDEV_SPECTRAL_ENABLE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->vdev_id = vdev_id; + cmd->trigger_cmd = trigger; + cmd->enable_cmd = enable; + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, + WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "failed to send spectral enable wmi cmd\n"); + goto err; + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI spectral enable cmd vdev id 0x%x\n", + vdev_id); + + return 0; +err: + dev_kfree_skb(skb); + return ret; +} + +int ath11k_wmi_pdev_dma_ring_cfg(struct ath11k *ar, + struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *param) +{ + struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_DMA_RING_CFG_REQ) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->pdev_id = param->pdev_id; + cmd->module_id = param->module_id; + cmd->base_paddr_lo = param->base_paddr_lo; + cmd->base_paddr_hi = param->base_paddr_hi; + cmd->head_idx_paddr_lo = param->head_idx_paddr_lo; + cmd->head_idx_paddr_hi = param->head_idx_paddr_hi; + cmd->tail_idx_paddr_lo = param->tail_idx_paddr_lo; + cmd->tail_idx_paddr_hi = param->tail_idx_paddr_hi; + cmd->num_elems = param->num_elems; + cmd->buf_size = param->buf_size; + cmd->num_resp_per_event = param->num_resp_per_event; + cmd->event_timeout_ms = param->event_timeout_ms; + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, + WMI_PDEV_DMA_RING_CFG_REQ_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "failed to send dma ring cfg req wmi cmd\n"); + goto err; + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI DMA ring cfg req cmd pdev_id 0x%x\n", + param->pdev_id); + + return 0; +err: + dev_kfree_skb(skb); + return ret; +} + +static int ath11k_wmi_tlv_dma_buf_entry_parse(struct ath11k_base *soc, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_dma_buf_release_parse *parse = data; + + if (tag != WMI_TAG_DMA_BUF_RELEASE_ENTRY) + return -EPROTO; + + if (parse->num_buf_entry >= parse->fixed.num_buf_release_entry) + return -ENOBUFS; + + parse->num_buf_entry++; + return 0; +} + +static int ath11k_wmi_tlv_dma_buf_meta_parse(struct ath11k_base *soc, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_dma_buf_release_parse *parse = data; + + if (tag != WMI_TAG_DMA_BUF_RELEASE_SPECTRAL_META_DATA) + return -EPROTO; + + if (parse->num_meta >= parse->fixed.num_meta_data_entry) + return -ENOBUFS; + + parse->num_meta++; + return 0; +} + +static int ath11k_wmi_tlv_dma_buf_parse(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_dma_buf_release_parse *parse = data; + int ret; + + switch (tag) { + case WMI_TAG_DMA_BUF_RELEASE: + memcpy(&parse->fixed, ptr, + sizeof(struct ath11k_wmi_dma_buf_release_fixed_param)); + parse->fixed.pdev_id = DP_HW2SW_MACID(parse->fixed.pdev_id); + break; + case WMI_TAG_ARRAY_STRUCT: + if (!parse->buf_entry_done) { + parse->num_buf_entry = 0; + parse->buf_entry = (struct wmi_dma_buf_release_entry *)ptr; + + ret = ath11k_wmi_tlv_iter(ab, ptr, len, + ath11k_wmi_tlv_dma_buf_entry_parse, + parse); + if (ret) { + ath11k_warn(ab, "failed to parse dma buf entry tlv %d\n", + ret); + return ret; + } + + parse->buf_entry_done = true; + } else if (!parse->meta_data_done) { + parse->num_meta = 0; + parse->meta_data = (struct wmi_dma_buf_release_meta_data *)ptr; + + ret = ath11k_wmi_tlv_iter(ab, ptr, len, + ath11k_wmi_tlv_dma_buf_meta_parse, + parse); + if (ret) { + ath11k_warn(ab, "failed to parse dma buf meta tlv %d\n", + ret); + return ret; + } + + parse->meta_data_done = true; + } + break; + default: + break; + } + return 0; +} + +static void ath11k_wmi_pdev_dma_ring_buf_release_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + struct wmi_tlv_dma_buf_release_parse parse = { }; + struct ath11k_dbring_buf_release_event param; + int ret; + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tlv_dma_buf_parse, + &parse); + if (ret) { + ath11k_warn(ab, "failed to parse dma buf release tlv %d\n", ret); + return; + } + + param.fixed = parse.fixed; + param.buf_entry = parse.buf_entry; + param.num_buf_entry = parse.num_buf_entry; + param.meta_data = parse.meta_data; + param.num_meta = parse.num_meta; + + ret = ath11k_dbring_buffer_release_event(ab, ¶m); + if (ret) { + ath11k_warn(ab, "failed to handle dma buf release event %d\n", ret); + return; + } +} + static int ath11k_wmi_tlv_hw_mode_caps_parse(struct ath11k_base *soc, u16 tag, u16 len, const void *ptr, void *data) @@ -3445,6 +3808,95 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, return 0; } +static int ath11k_wmi_tlv_dma_ring_caps_parse(struct ath11k_base *soc, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_dma_ring_caps_parse *parse = data; + + if (tag != WMI_TAG_DMA_RING_CAPABILITIES) + return -EPROTO; + + parse->n_dma_ring_caps++; + return 0; +} + +static int ath11k_wmi_alloc_dbring_caps(struct ath11k_base *ab, + u32 num_cap) +{ + size_t sz; + void *ptr; + + sz = num_cap * sizeof(struct ath11k_dbring_cap); + ptr = kzalloc(sz, GFP_ATOMIC); + if (!ptr) + return -ENOMEM; + + ab->db_caps = ptr; + ab->num_db_cap = num_cap; + + return 0; +} + +static void ath11k_wmi_free_dbring_caps(struct ath11k_base *ab) +{ + kfree(ab->db_caps); + ab->db_caps = NULL; +} + +static int ath11k_wmi_tlv_dma_ring_caps(struct ath11k_base *ab, + u16 len, const void *ptr, void *data) +{ + struct wmi_tlv_dma_ring_caps_parse *dma_caps_parse = data; + struct wmi_dma_ring_capabilities *dma_caps; + struct ath11k_dbring_cap *dir_buff_caps; + int ret; + u32 i; + + dma_caps_parse->n_dma_ring_caps = 0; + dma_caps = (struct wmi_dma_ring_capabilities *)ptr; + ret = ath11k_wmi_tlv_iter(ab, ptr, len, + ath11k_wmi_tlv_dma_ring_caps_parse, + dma_caps_parse); + if (ret) { + ath11k_warn(ab, "failed to parse dma ring caps tlv %d\n", ret); + return ret; + } + + if (!dma_caps_parse->n_dma_ring_caps) + return 0; + + if (ab->num_db_cap) { + ath11k_warn(ab, "Already processed, so ignoring dma ring caps\n"); + return 0; + } + + ret = ath11k_wmi_alloc_dbring_caps(ab, dma_caps_parse->n_dma_ring_caps); + if (ret) + return ret; + + dir_buff_caps = ab->db_caps; + for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) { + if (dma_caps[i].module_id >= WMI_DIRECT_BUF_MAX) { + ath11k_warn(ab, "Invalid module id %d\n", dma_caps[i].module_id); + ret = -EINVAL; + goto free_dir_buff; + } + + dir_buff_caps[i].id = dma_caps[i].module_id; + dir_buff_caps[i].pdev_id = DP_HW2SW_MACID(dma_caps[i].pdev_id); + dir_buff_caps[i].min_elem = dma_caps[i].min_elem; + dir_buff_caps[i].min_buf_sz = dma_caps[i].min_buf_sz; + dir_buff_caps[i].min_buf_align = dma_caps[i].min_buf_align; + } + + return 0; + +free_dir_buff: + ath11k_wmi_free_dbring_caps(ab); + return ret; +} + static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab, u16 tag, u16 len, const void *ptr, void *data) @@ -3501,7 +3953,19 @@ static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab, return ret; svc_rdy_ext->ext_hal_reg_done = true; - complete(&ab->wmi_ab.service_ready); + } else if (!svc_rdy_ext->mac_phy_chainmask_combo_done) { + svc_rdy_ext->mac_phy_chainmask_combo_done = true; + } else if (!svc_rdy_ext->mac_phy_chainmask_cap_done) { + svc_rdy_ext->mac_phy_chainmask_cap_done = true; + } else if (!svc_rdy_ext->oem_dma_ring_cap_done) { + svc_rdy_ext->oem_dma_ring_cap_done = true; + } else if (!svc_rdy_ext->dma_ring_cap_done) { + ret = ath11k_wmi_tlv_dma_ring_caps(ab, len, ptr, + &svc_rdy_ext->dma_caps_parse); + if (ret) + return ret; + + svc_rdy_ext->dma_ring_cap_done = true; } break; @@ -3522,11 +3986,66 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab, &svc_rdy_ext); if (ret) { ath11k_warn(ab, "failed to parse tlv %d\n", ret); - return ret; + goto err; } + if (!test_bit(WMI_TLV_SERVICE_EXT2_MSG, ab->wmi_ab.svc_map)) + complete(&ab->wmi_ab.service_ready); + kfree(svc_rdy_ext.mac_phy_caps); return 0; + +err: + ath11k_wmi_free_dbring_caps(ab); + return ret; +} + +static int ath11k_wmi_tlv_svc_rdy_ext2_parse(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_tlv_svc_rdy_ext2_parse *parse = data; + int ret; + + switch (tag) { + case WMI_TAG_ARRAY_STRUCT: + if (!parse->dma_ring_cap_done) { + ret = ath11k_wmi_tlv_dma_ring_caps(ab, len, ptr, + &parse->dma_caps_parse); + if (ret) + return ret; + + parse->dma_ring_cap_done = true; + } + break; + default: + break; + } + + return 0; +} + +static int ath11k_service_ready_ext2_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + struct wmi_tlv_svc_rdy_ext2_parse svc_rdy_ext2 = { }; + int ret; + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tlv_svc_rdy_ext2_parse, + &svc_rdy_ext2); + if (ret) { + ath11k_warn(ab, "failed to parse ext2 event tlv %d\n", ret); + goto err; + } + + complete(&ab->wmi_ab.service_ready); + + return 0; + +err: + ath11k_wmi_free_dbring_caps(ab); + return ret; } static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buff *skb, @@ -3822,6 +4341,7 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab, } hdr->pdev_id = ev->pdev_id; + hdr->chan_freq = ev->chan_freq; hdr->channel = ev->channel; hdr->snr = ev->snr; hdr->rate = ev->rate; @@ -5193,7 +5713,9 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) if (rx_ev.status & WMI_RX_STATUS_ERR_MIC) status->flag |= RX_FLAG_MMIC_ERROR; - if (rx_ev.channel >= 1 && rx_ev.channel <= 14) { + if (rx_ev.chan_freq >= ATH11K_MIN_6G_FREQ) { + status->band = NL80211_BAND_6GHZ; + } else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) { status->band = NL80211_BAND_2GHZ; } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH11K_MAX_5G_CHAN) { status->band = NL80211_BAND_5GHZ; @@ -5206,9 +5728,10 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) goto exit; } - if (rx_ev.phy_mode == MODE_11B && status->band == NL80211_BAND_5GHZ) + if (rx_ev.phy_mode == MODE_11B && + (status->band == NL80211_BAND_5GHZ || status->band == NL80211_BAND_6GHZ)) ath11k_dbg(ab, ATH11K_DBG_WMI, - "wmi mgmt rx 11b (CCK) on 5GHz\n"); + "wmi mgmt rx 11b (CCK) on 5/6GHz, band = %d\n", status->band); sband = &ar->mac.sbands[status->band]; @@ -5933,6 +6456,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_SERVICE_READY_EXT_EVENTID: ath11k_service_ready_ext_event(ab, skb); break; + case WMI_SERVICE_READY_EXT2_EVENTID: + ath11k_service_ready_ext2_event(ab, skb); + break; case WMI_REG_CHAN_LIST_CC_EVENTID: ath11k_reg_chan_list_event(ab, skb); break; @@ -5994,12 +6520,16 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_PDEV_TEMPERATURE_EVENTID: ath11k_wmi_pdev_temperature_event(ab, skb); break; + case WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID: + ath11k_wmi_pdev_dma_ring_buf_release_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_VDEV_DELETE_RESP_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID: + case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ath11k_dbg(ab, ATH11K_DBG_WMI, "ignoring unsupported event 0x%x\n", id); break; @@ -6213,4 +6743,6 @@ void ath11k_wmi_detach(struct ath11k_base *ab) for (i = 0; i < ab->htc.wmi_ep_count; i++) ath11k_wmi_pdev_detach(ab, i); + + ath11k_wmi_free_dbring_caps(ab); } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index b9f3e559ced7..5a32ba0eb4f5 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -24,6 +24,8 @@ struct ath11k_fw_stats; #define HE_PET_8_USEC 1 #define HE_PET_16_USEC 2 +#define WMI_MAX_CHAINS 8 + #define WMI_MAX_NUM_SS MAX_HE_NSS #define WMI_MAX_NUM_RU MAX_HE_RU @@ -50,10 +52,20 @@ struct wmi_tlv { #define WMI_MAX_MEM_REQS 32 #define ATH11K_MAX_HW_LISTEN_INTERVAL 5 +#define WLAN_SCAN_MAX_HINT_S_SSID 10 +#define WLAN_SCAN_MAX_HINT_BSSID 10 +#define MAX_RNR_BSS 5 + +#define WLAN_SCAN_MAX_HINT_S_SSID 10 +#define WLAN_SCAN_MAX_HINT_BSSID 10 +#define MAX_RNR_BSS 5 + #define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_BSSID 4 #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 + #define WMI_BA_MODE_BUFFER_SIZE_256 3 /* * HW mode config type replicated from FW header @@ -586,6 +598,11 @@ enum wmi_tlv_event_id { WMI_PDEV_DMA_RING_CFG_RSP_EVENTID, WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID, WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID, + WMI_PDEV_CSC_SWITCH_COUNT_STATUS_EVENTID, + WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID, + WMI_PDEV_RAP_INFO_EVENTID, + WMI_CHAN_RF_CHARACTERIZATION_INFO_EVENTID, + WMI_SERVICE_READY_EXT2_EVENTID, WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_STOPPED_EVENTID, WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, @@ -1011,6 +1028,7 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, WMI_VDEV_PARAM_BA_MODE = 0x7e, WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, + WMI_VDEV_PARAM_6GHZ_PARAMS = 0x99, WMI_VDEV_PARAM_PROTOTYPE = 0x8000, WMI_VDEV_PARAM_BSS_COLOR, WMI_VDEV_PARAM_SET_HEMU_MODE, @@ -2013,9 +2031,10 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_DSM_ROAM_FILTER = 211, WMI_TLV_SERVICE_PACKET_CAPTURE_SUPPORT = 212, WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213, + WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219, + WMI_TLV_SERVICE_EXT2_MSG = 220, WMI_MAX_EXT_SERVICE - }; enum { @@ -2076,6 +2095,14 @@ enum wmi_beacon_gen_mode { WMI_BEACON_BURST_MODE = 1 }; +enum wmi_direct_buffer_module { + WMI_DIRECT_BUF_SPECTRAL = 0, + WMI_DIRECT_BUF_CFR = 1, + + /* keep it last */ + WMI_DIRECT_BUF_MAX +}; + struct wmi_host_pdev_band_to_mac { u32 pdev_id; u32 start_freq; @@ -2382,6 +2409,15 @@ struct wmi_mac_addr { } __packed; } __packed; +struct wmi_dma_ring_capabilities { + u32 tlv_header; + u32 pdev_id; + u32 module_id; + u32 min_elem; + u32 min_buf_sz; + u32 min_buf_align; +} __packed; + struct wmi_ready_event_min { struct wmi_abi_version fw_abi_vers; struct wmi_mac_addr mac_addr; @@ -2519,7 +2555,8 @@ struct channel_param { allow_ht:1, allow_vht:1, allow_he:1, - set_agile:1; + set_agile:1, + psc_channel:1; u32 phy_mode; u32 cfreq1; u32 cfreq2; @@ -3059,6 +3096,9 @@ struct wmi_start_scan_cmd { u32 num_vendor_oui; u32 scan_ctrl_flags_ext; u32 dwell_time_active_2g; + u32 dwell_time_active_6g; + u32 dwell_time_passive_6g; + u32 scan_start_offset; } __packed; #define WMI_SCAN_FLAG_PASSIVE 0x1 @@ -3098,6 +3138,16 @@ enum { ((flag) |= (((mode) << WMI_SCAN_DWELL_MODE_SHIFT) & \ WMI_SCAN_DWELL_MODE_MASK)) +struct hint_short_ssid { + u32 freq_flags; + u32 short_ssid; +}; + +struct hint_bssid { + u32 freq_flags; + struct wmi_mac_addr bssid; +}; + struct scan_req_params { u32 scan_id; u32 scan_req_id; @@ -3125,6 +3175,8 @@ struct scan_req_params { u32 dwell_time_active; u32 dwell_time_active_2g; u32 dwell_time_passive; + u32 dwell_time_active_6g; + u32 dwell_time_passive_6g; u32 min_rest_time; u32 max_rest_time; u32 repeat_probe_time; @@ -3175,6 +3227,10 @@ struct scan_req_params { struct element_info extraie; struct element_info htcap; struct element_info vhtcap; + u32 num_hint_s_ssid; + u32 num_hint_bssid; + struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID]; + struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID]; }; struct wmi_ssid_arg { @@ -3264,6 +3320,7 @@ struct wmi_bcn_send_from_host_cmd { #define WMI_CHAN_INFO_QUARTER_RATE BIT(15) #define WMI_CHAN_INFO_DFS_FREQ2 BIT(16) #define WMI_CHAN_INFO_ALLOW_HE BIT(17) +#define WMI_CHAN_INFO_PSC BIT(18) #define WMI_CHAN_REG_INFO1_MIN_PWR GENMASK(7, 0) #define WMI_CHAN_REG_INFO1_MAX_PWR GENMASK(15, 8) @@ -3444,6 +3501,7 @@ struct peer_assoc_params { u32 tx_max_rate; u32 tx_mcs_set; u8 vht_capable; + u8 min_data_rate; u32 tx_max_mcs_nss; u32 peer_bw_rxnss_override; bool is_pmf_enabled; @@ -3472,6 +3530,7 @@ struct peer_assoc_params { bool he_flag; u32 peer_he_cap_macinfo[2]; u32 peer_he_cap_macinfo_internal; + u32 peer_he_caps_6ghz; u32 peer_he_ops; u32 peer_he_cap_phyinfo[WMI_HOST_MAX_HECAP_PHY_SIZE]; u32 peer_he_mcs_count; @@ -3509,6 +3568,8 @@ struct wmi_peer_assoc_complete_cmd { u32 peer_he_mcs; u32 peer_he_cap_info_ext; u32 peer_he_cap_info_internal; + u32 min_data_rate; + u32 peer_he_caps_6ghz; } __packed; struct wmi_stop_scan_cmd { @@ -4228,6 +4289,7 @@ struct wmi_pdev_temperature_event { #define WLAN_MGMT_TXRX_HOST_MAX_ANTENNA 4 struct mgmt_rx_event_params { + u32 chan_freq; u32 channel; u32 snr; u8 rssi_ctl[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA]; @@ -4257,6 +4319,7 @@ struct wmi_mgmt_rx_hdr { u32 rx_tsf_l32; u32 rx_tsf_u32; u32 pdev_id; + u32 chan_freq; } __packed; #define MAX_ANTENNA_EIGHT 8 @@ -4734,6 +4797,117 @@ struct ath11k_wmi_pdev_lro_config_cmd { u32 pdev_id; } __packed; +#define ATH11K_WMI_SPECTRAL_COUNT_DEFAULT 0 +#define ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT 224 +#define ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT 1 +#define ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT 7 +#define ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT 1 +#define ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT 0 +#define ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96 +#define ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT 80 +#define ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12 +#define ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8 +#define ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0 +#define ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0 +#define ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0 +#define ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0 +#define ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT 2 +#define ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT 1 +#define ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT 1 +#define ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT 1 + +struct ath11k_wmi_vdev_spectral_conf_param { + u32 vdev_id; + u32 scan_count; + u32 scan_period; + u32 scan_priority; + u32 scan_fft_size; + u32 scan_gc_ena; + u32 scan_restart_ena; + u32 scan_noise_floor_ref; + u32 scan_init_delay; + u32 scan_nb_tone_thr; + u32 scan_str_bin_thr; + u32 scan_wb_rpt_mode; + u32 scan_rssi_rpt_mode; + u32 scan_rssi_thr; + u32 scan_pwr_format; + u32 scan_rpt_mode; + u32 scan_bin_scale; + u32 scan_dbm_adj; + u32 scan_chn_mask; +} __packed; + +struct ath11k_wmi_vdev_spectral_conf_cmd { + u32 tlv_header; + struct ath11k_wmi_vdev_spectral_conf_param param; +} __packed; + +#define ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1 +#define ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2 +#define ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE 1 +#define ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE 2 + +struct ath11k_wmi_vdev_spectral_enable_cmd { + u32 tlv_header; + u32 vdev_id; + u32 trigger_cmd; + u32 enable_cmd; +} __packed; + +struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd { + u32 tlv_header; + u32 pdev_id; + u32 module_id; /* see enum wmi_direct_buffer_module */ + u32 base_paddr_lo; + u32 base_paddr_hi; + u32 head_idx_paddr_lo; + u32 head_idx_paddr_hi; + u32 tail_idx_paddr_lo; + u32 tail_idx_paddr_hi; + u32 num_elems; /* Number of elems in the ring */ + u32 buf_size; /* size of allocated buffer in bytes */ + + /* Number of wmi_dma_buf_release_entry packed together */ + u32 num_resp_per_event; + + /* Target should timeout and send whatever resp + * it has if this time expires, units in milliseconds + */ + u32 event_timeout_ms; +} __packed; + +struct ath11k_wmi_dma_buf_release_fixed_param { + u32 pdev_id; + u32 module_id; + u32 num_buf_release_entry; + u32 num_meta_data_entry; +} __packed; + +struct wmi_dma_buf_release_entry { + u32 tlv_header; + u32 paddr_lo; + + /* Bits 11:0: address of data + * Bits 31:12: host context data + */ + u32 paddr_hi; +} __packed; + +#define WMI_SPECTRAL_META_INFO1_FREQ1 GENMASK(15, 0) +#define WMI_SPECTRAL_META_INFO1_FREQ2 GENMASK(31, 16) + +#define WMI_SPECTRAL_META_INFO2_CHN_WIDTH GENMASK(7, 0) + +struct wmi_dma_buf_release_meta_data { + u32 tlv_header; + s32 noise_floor[WMI_MAX_CHAINS]; + u32 reset_delay; + u32 freq1; + u32 freq2; + u32 ch_width; +} __packed; + struct target_resource_config { u32 num_vdevs; u32 num_peers; @@ -4941,4 +5115,10 @@ int ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id, int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, bool enable); int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, int pdev_id); +int ath11k_wmi_pdev_dma_ring_cfg(struct ath11k *ar, + struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *param); +int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id, + u32 trigger, u32 enable); +int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar, + struct ath11k_wmi_vdev_spectral_conf_param *param); #endif diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index aa1c71a76ef7..811fad6d60c0 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1575,7 +1575,7 @@ static int ath6kl_init_upload(struct ath6kl *ar) int ath6kl_init_hw_params(struct ath6kl *ar) { - const struct ath6kl_hw *uninitialized_var(hw); + const struct ath6kl_hw *hw; int i; for (i = 0; i < ARRAY_SIZE(hw_list); i++) { diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 53b66e9434c9..5372e948e761 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -311,7 +311,7 @@ static int ath6kl_usb_setup_pipe_resources(struct ath6kl_usb *ar_usb) ath6kl_dbg(ATH6KL_DBG_USB, "setting up USB Pipes using interface\n"); - /* walk decriptors and setup pipes */ + /* walk descriptors and setup pipes */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 42bfdb4a6214..d5e9af2dddd8 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -34,7 +34,7 @@ config ATH9K APs that come with these cards refer to ath9k wiki products page: - http://wireless.kernel.org/en/users/Drivers/ath9k/products + https://wireless.wiki.kernel.org/en/users/Drivers/ath9k/products If you choose to build a module, it'll be called ath9k. @@ -185,7 +185,8 @@ config ATH9K_HTC Support for Atheros HTC based cards. Chipsets supported: AR9271 - For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc + For more information: + https://wireless.wiki.kernel.org/en/users/Drivers/ath9k_htc The built module will be ath9k_htc. diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 052deffb4c9d..8c97db73e34c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2410,7 +2410,7 @@ static u8 fixup_chainmask(u8 chip_chainmask, u8 eeprom_chainmask) * of tests. The testing requirements are going to be documented. Desired * test requirements are documented at: * - * http://wireless.kernel.org/en/users/Drivers/ath9k/dfs + * https://wireless.wiki.kernel.org/en/users/Drivers/ath9k/dfs * * Once a new chipset gets properly tested an individual commit can be used * to document the testing for DFS for that chipset. diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 289a2444d534..4d72cd7daaa2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -230,7 +230,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl struct ath_hw *ah = hw_priv; struct ath_common *common = ath9k_hw_common(ah); struct ath_softc *sc = (struct ath_softc *) common->priv; - unsigned long uninitialized_var(flags); + unsigned long flags; u32 val; if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) { diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index b1bce7aad399..b2d760873992 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -10,7 +10,7 @@ config CARL9170 It needs a special firmware (carl9170-1.fw), which can be downloaded from our wiki here: - <http://wireless.kernel.org/en/users/Drivers/carl9170> + <https://wireless.wiki.kernel.org/en/users/Drivers/carl9170> If you choose to build a module, it'll be called carl9170. diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 486957a04bd1..ead79335823a 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -61,7 +61,7 @@ MODULE_ALIAS("arusb_lnx"); * Note: * * Always update our wiki's device list (located at: - * http://wireless.kernel.org/en/users/Drivers/ar9170/devices ), + * https://wireless.wiki.kernel.org/en/users/Drivers/ar9170/devices ), * whenever you add a new device. */ static const struct usb_device_id carl9170_usb_ids[] = { diff --git a/drivers/net/wireless/ath/spectral_common.h b/drivers/net/wireless/ath/spectral_common.h index 0d742acb1599..9c2e5458e425 100644 --- a/drivers/net/wireless/ath/spectral_common.h +++ b/drivers/net/wireless/ath/spectral_common.h @@ -24,6 +24,7 @@ * could be acquired so far. */ #define SPECTRAL_ATH10K_MAX_NUM_BINS 256 +#define SPECTRAL_ATH11K_MAX_NUM_BINS 512 /* FFT sample format given to userspace via debugfs. * @@ -37,6 +38,7 @@ enum ath_fft_sample_type { ATH_FFT_SAMPLE_HT20 = 1, ATH_FFT_SAMPLE_HT20_40, ATH_FFT_SAMPLE_ATH10K, + ATH_FFT_SAMPLE_ATH11K }; struct fft_sample_tlv { @@ -110,4 +112,19 @@ struct fft_sample_ath10k { u8 data[0]; } __packed; +struct fft_sample_ath11k { + struct fft_sample_tlv tlv; + u8 chan_width_mhz; + s8 max_index; + u8 max_exp; + __be16 freq1; + __be16 freq2; + __be16 max_magnitude; + __be16 rssi; + __be32 tsf; + __be32 noise; + + u8 data[0]; +} __packed; + #endif /* SPECTRAL_COMMON_H */ diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index dadba2d41bbb..6a95b199bf62 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -10,7 +10,7 @@ config WIL6210 wil6210 chip by Wilocity. It supports operation on the 60 GHz band, covered by the IEEE802.11ad standard. - http://wireless.kernel.org/en/users/Drivers/wil6210 + https://wireless.wiki.kernel.org/en/users/Drivers/wil6210 If you choose to build it as a module, it will be called wil6210 diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 3b2680772f03..a63b5c2f1e17 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -17,7 +17,7 @@ * * TODO list is at the wiki: * - * http://wireless.kernel.org/en/users/Drivers/at76c50x-usb#TODO + * https://wireless.wiki.kernel.org/en/users/Drivers/at76c50x-usb#TODO */ #include <linux/init.h> diff --git a/drivers/net/wireless/broadcom/b43/debugfs.c b/drivers/net/wireless/broadcom/b43/debugfs.c index dc1819ca52ac..89a25aefb327 100644 --- a/drivers/net/wireless/broadcom/b43/debugfs.c +++ b/drivers/net/wireless/broadcom/b43/debugfs.c @@ -493,7 +493,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, struct b43_wldev *dev; struct b43_debugfs_fops *dfops; struct b43_dfs_file *dfile; - ssize_t uninitialized_var(ret); + ssize_t ret; char *buf; const size_t bufsize = 1024 * 16; /* 16 kiB buffer */ const size_t buforder = get_order(bufsize); diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 9733c64bf978..ca671fc13116 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -37,7 +37,7 @@ static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr, enum b43_addrtype addrtype) { - u32 uninitialized_var(addr); + u32 addr; switch (addrtype) { case B43_DMA_ADDR_LOW: diff --git a/drivers/net/wireless/broadcom/b43/lo.c b/drivers/net/wireless/broadcom/b43/lo.c index 5d97cf06eceb..338b6545a1e7 100644 --- a/drivers/net/wireless/broadcom/b43/lo.c +++ b/drivers/net/wireless/broadcom/b43/lo.c @@ -729,7 +729,7 @@ struct b43_lo_calib *b43_calibrate_lo_setting(struct b43_wldev *dev, }; int max_rx_gain; struct b43_lo_calib *cal; - struct lo_g_saved_values uninitialized_var(saved_regs); + struct lo_g_saved_values saved_regs; /* Values from the "TXCTL Register and Value Table" */ u16 txctl_reg; u16 txctl_value; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 3ad94dad2d89..a54dd4f7fa54 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -734,7 +734,7 @@ static void b43_short_slot_timing_disable(struct b43_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-v4.sipsolutions.net/802.11/DummyTransmission + * https://bcm-v4.sipsolutions.net/802.11/DummyTransmission */ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) { @@ -1198,7 +1198,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/BmacCorePllReset */ void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev) { struct bcma_drv_cc *bcma_cc __maybe_unused; @@ -2164,7 +2164,7 @@ static void b43_print_fw_helptext(struct b43_wl *wl, bool error) { const char text[] = "You must go to " \ - "http://wireless.kernel.org/en/users/Drivers/b43#devicefirmware " \ + "https://wireless.wiki.kernel.org/en/users/Drivers/b43#devicefirmware " \ "and download the correct firmware for this driver version. " \ "Please carefully read all instructions on this website.\n"; @@ -2290,7 +2290,7 @@ err_format: return -EPROTO; } -/* http://bcm-v4.sipsolutions.net/802.11/Init/Firmware */ +/* https://bcm-v4.sipsolutions.net/802.11/Init/Firmware */ static int b43_try_request_fw(struct b43_request_fw_context *ctx) { struct b43_wldev *dev = ctx->dev; @@ -2843,7 +2843,7 @@ static int b43_upload_initvals_band(struct b43_wldev *dev) } /* Initialize the GPIOs - * http://bcm-specs.sipsolutions.net/GPIO + * https://bcm-specs.sipsolutions.net/GPIO */ #ifdef CONFIG_B43_SSB @@ -2971,7 +2971,7 @@ void b43_mac_enable(struct b43_wldev *dev) } } -/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +/* https://bcm-specs.sipsolutions.net/SuspendMAC */ void b43_mac_suspend(struct b43_wldev *dev) { int i; @@ -3004,7 +3004,7 @@ out: dev->mac_suspended++; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */ void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on) { u32 tmp; @@ -3231,7 +3231,7 @@ static void b43_chip_exit(struct b43_wldev *dev) } /* Initialize the chip - * http://bcm-specs.sipsolutions.net/ChipInit + * https://bcm-specs.sipsolutions.net/ChipInit */ static int b43_chip_init(struct b43_wldev *dev) { diff --git a/drivers/net/wireless/broadcom/b43/phy_common.c b/drivers/net/wireless/broadcom/b43/phy_common.c index 923d4cb9fc30..1de4de094d61 100644 --- a/drivers/net/wireless/broadcom/b43/phy_common.c +++ b/drivers/net/wireless/broadcom/b43/phy_common.c @@ -559,7 +559,7 @@ bool b43_is_40mhz(struct b43_wldev *dev) return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ void b43_phy_force_clock(struct b43_wldev *dev, bool force) { u32 tmp; diff --git a/drivers/net/wireless/broadcom/b43/phy_g.c b/drivers/net/wireless/broadcom/b43/phy_g.c index 1e022ec733a3..d5a1a5c58236 100644 --- a/drivers/net/wireless/broadcom/b43/phy_g.c +++ b/drivers/net/wireless/broadcom/b43/phy_g.c @@ -357,14 +357,14 @@ static void b43_set_original_gains(struct b43_wldev *dev) b43_dummy_transmission(dev, false, true); } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) { u16 val; @@ -375,7 +375,7 @@ static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) return (s16) val; } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) { u16 i; @@ -389,7 +389,7 @@ static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) } } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ static void b43_nrssi_mem_update(struct b43_wldev *dev) { struct b43_phy_g *gphy = dev->phy.g; @@ -1575,7 +1575,7 @@ static void b43_phy_initb5(struct b43_wldev *dev) b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Init/B6 */ static void b43_phy_initb6(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -2746,7 +2746,7 @@ static int b43_gphy_op_interf_mitigation(struct b43_wldev *dev, return 0; } -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut +/* https://bcm-specs.sipsolutions.net/EstimatePowerOut * This function converts a TSSI value to dBm in Q5.2 */ static s8 b43_gphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) diff --git a/drivers/net/wireless/broadcom/b43/phy_ht.c b/drivers/net/wireless/broadcom/b43/phy_ht.c index 6033df1c3053..c685b4bb5ed6 100644 --- a/drivers/net/wireless/broadcom/b43/phy_ht.c +++ b/drivers/net/wireless/broadcom/b43/phy_ht.c @@ -1018,7 +1018,7 @@ static void b43_phy_ht_op_free(struct b43_wldev *dev) phy->ht = NULL; } -/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ static void b43_phy_ht_op_software_rfkill(struct b43_wldev *dev, bool blocked) { diff --git a/drivers/net/wireless/broadcom/b43/phy_lp.c b/drivers/net/wireless/broadcom/b43/phy_lp.c index cfb953d61dc5..0e5c076e7544 100644 --- a/drivers/net/wireless/broadcom/b43/phy_lp.c +++ b/drivers/net/wireless/broadcom/b43/phy_lp.c @@ -70,7 +70,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev) dev->phy.lp = NULL; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */ static void lpphy_read_band_sprom(struct b43_wldev *dev) { struct ssb_sprom *sprom = dev->dev->bus_sprom; diff --git a/drivers/net/wireless/broadcom/b43/phy_n.c b/drivers/net/wireless/broadcom/b43/phy_n.c index c33b4235839d..ca2018da9753 100644 --- a/drivers/net/wireless/broadcom/b43/phy_n.c +++ b/drivers/net/wireless/broadcom/b43/phy_n.c @@ -98,7 +98,7 @@ static inline bool b43_nphy_ipa(struct b43_wldev *dev) (dev->phy.n->ipa5g_on && band == NL80211_BAND_5GHZ)); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreGetState */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreGetState */ static u8 b43_nphy_get_rx_core_state(struct b43_wldev *dev) { return (b43_phy_read(dev, B43_NPHY_RFSEQCA) & B43_NPHY_RFSEQCA_RXEN) >> @@ -109,7 +109,7 @@ static u8 b43_nphy_get_rx_core_state(struct b43_wldev *dev) * RF (just without b43_nphy_rf_ctl_intc_override) **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, enum b43_nphy_rf_sequence seq) { @@ -146,7 +146,7 @@ static void b43_nphy_rf_ctl_override_rev19(struct b43_wldev *dev, u16 field, /* TODO */ } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off, u8 override) @@ -193,7 +193,7 @@ static void b43_nphy_rf_ctl_override_rev7(struct b43_wldev *dev, u16 field, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverideOneToMany */ static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev, enum n_rf_ctl_over_cmd cmd, u16 value, u8 core, bool off) @@ -237,7 +237,7 @@ static void b43_nphy_rf_ctl_override_one_to_many(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */ static void b43_nphy_rf_ctl_override(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off) { @@ -382,7 +382,7 @@ static void b43_nphy_rf_ctl_intc_override_rev7(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev, enum n_intc_override intc_override, u16 value, u8 core) @@ -490,7 +490,7 @@ static void b43_nphy_rf_ctl_intc_override(struct b43_wldev *dev, * Various PHY ops **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ static void b43_nphy_write_clip_detection(struct b43_wldev *dev, const u16 *clip_st) { @@ -498,14 +498,14 @@ static void b43_nphy_write_clip_detection(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */ static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) { clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES); clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) { u16 tmp; @@ -526,7 +526,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val) return tmp; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ static void b43_nphy_reset_cca(struct b43_wldev *dev) { u16 bbcfg; @@ -540,7 +540,7 @@ static void b43_nphy_reset_cca(struct b43_wldev *dev) b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) { struct b43_phy *phy = &dev->phy; @@ -564,7 +564,7 @@ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable) } } -/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */ +/* https://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */ static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) { if (!offset) @@ -572,7 +572,7 @@ static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset) return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -628,7 +628,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, u8 *events, u8 *delays, u8 length) { @@ -805,7 +805,7 @@ static void b43_radio_2057_setup(struct b43_wldev *dev, } /* Calibrate resistors in LPF of PLL? - * http://bcm-v4.sipsolutions.net/PHY/radio205x_rcal + * https://bcm-v4.sipsolutions.net/PHY/radio205x_rcal */ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) { @@ -919,7 +919,7 @@ static u8 b43_radio_2057_rcal(struct b43_wldev *dev) } /* Calibrate the internal RC oscillator? - * http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal + * https://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */ static u16 b43_radio_2057_rccal(struct b43_wldev *dev) { @@ -1030,7 +1030,7 @@ static void b43_radio_2057_init_post(struct b43_wldev *dev) b43_radio_mask(dev, R2057_RFPLL_MASTER, ~0x8); } -/* http://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */ static void b43_radio_2057_init(struct b43_wldev *dev) { b43_radio_2057_init_pre(dev); @@ -1117,7 +1117,7 @@ static void b43_chantab_radio_2056_upload(struct b43_wldev *dev, e->radio_tx1_mixg_boost_tune); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */ static void b43_radio_2056_setup(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev3 *e) { @@ -1356,7 +1356,7 @@ static void b43_radio_init2056_post(struct b43_wldev *dev) /* * Initialize a Broadcom 2056 N-radio - * http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init + * https://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init */ static void b43_radio_init2056(struct b43_wldev *dev) { @@ -1406,7 +1406,7 @@ static void b43_chantab_radio_upload(struct b43_wldev *dev, b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */ static void b43_radio_2055_setup(struct b43_wldev *dev, const struct b43_nphy_channeltab_entry_rev2 *e) { @@ -1480,7 +1480,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) /* * Initialize a Broadcom 2055 N-radio - * http://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init + * https://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init */ static void b43_radio_init2055(struct b43_wldev *dev) { @@ -1499,7 +1499,7 @@ static void b43_radio_init2055(struct b43_wldev *dev) * Samples **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */ static int b43_nphy_load_samples(struct b43_wldev *dev, struct cordic_iq *samples, u16 len) { struct b43_phy_n *nphy = dev->phy.n; @@ -1526,7 +1526,7 @@ static int b43_nphy_load_samples(struct b43_wldev *dev, return 0; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, bool test) { @@ -1569,7 +1569,7 @@ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max, return (i < 0) ? 0 : len; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, u16 wait, bool iqmode, bool dac_test, bool modify_bbmult) @@ -1650,7 +1650,7 @@ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops, * RSSI **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale, s8 offset, u8 core, enum n_rail_type rail, @@ -1895,7 +1895,7 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, enum n_rssi_type type) { @@ -1907,7 +1907,7 @@ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, b43_nphy_rev2_rssi_select(dev, code, type); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, enum n_rssi_type rssi_type, u8 *buf) { @@ -1936,7 +1936,7 @@ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type, s32 *buf, u8 nsamp) { @@ -2025,7 +2025,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, enum n_rssi_type rssi_type, return out; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -2287,7 +2287,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) b43_nphy_write_clip_detection(dev, clip_state); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type) { int i, j, vcm; @@ -2453,7 +2453,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, enum n_rssi_type type) /* * RSSI Calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */ static void b43_nphy_rssi_cal(struct b43_wldev *dev) { @@ -2680,7 +2680,7 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev) b43_phy_maskset(dev, B43_PHY_N(0xC5D), 0xFF80, 4); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev) { if (dev->phy.rev >= 19) @@ -3433,7 +3433,7 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev) B43_NPHY_FINERX2_CGC_DECGC); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ static void b43_nphy_workarounds(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3468,7 +3468,7 @@ static void b43_nphy_workarounds(struct b43_wldev *dev) /* * Transmits a known value for LO calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone */ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, bool iqmode, bool dac_test, bool modify_bbmult) @@ -3481,7 +3481,7 @@ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val, return 0; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -3509,7 +3509,7 @@ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev) ~B43_NPHY_RFSEQMODE_CAOVER); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */ static void b43_nphy_stop_playback(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3546,7 +3546,7 @@ static void b43_nphy_stop_playback(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/IqCalGainParams */ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, struct nphy_txgains target, struct nphy_iqcal_params *params) @@ -3595,7 +3595,7 @@ static void b43_nphy_iq_cal_gain_params(struct b43_wldev *dev, u16 core, * Tx and Rx **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) { struct b43_phy *phy = &dev->phy; @@ -3732,7 +3732,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -3926,7 +3926,7 @@ static void b43_nphy_ipa_internal_tssi_setup(struct b43_wldev *dev) /* * Stop radio and transmit known signal. Then check received signal strength to * get TSSI (Transmit Signal Strength Indicator). - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlIdleTssi */ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) { @@ -3978,7 +3978,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev) nphy->pwr_ctl_info[1].idle_tssi_2g = (tmp >> 8) & 0xFF; } -/* http://bcm-v4.sipsolutions.net/PHY/N/TxPwrLimitToTbl */ +/* https://bcm-v4.sipsolutions.net/PHY/N/TxPwrLimitToTbl */ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -4039,7 +4039,7 @@ static void b43_nphy_tx_prepare_adjusted_power_table(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlSetup */ static void b43_nphy_tx_power_ctl_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -4222,7 +4222,7 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) u32 rfpwr_offset; u8 pga_gain, pad_gain; int i; - const s16 *uninitialized_var(rf_pwr_offset_table); + const s16 *rf_pwr_offset_table = NULL; table = b43_nphy_get_tx_gain_table(dev); if (!table) @@ -4272,7 +4272,7 @@ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) { struct b43_phy_n *nphy = dev->phy.n; @@ -4310,7 +4310,7 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) /* * TX low-pass filter bandwidth setup - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ static void b43_nphy_tx_lpf_bw(struct b43_wldev *dev) { @@ -4333,7 +4333,7 @@ static void b43_nphy_tx_lpf_bw(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, u16 samps, u8 time, bool wait) { @@ -4372,7 +4372,7 @@ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est, memset(est, 0, sizeof(*est)); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, struct b43_phy_n_iq_comp *pcomp) { @@ -4391,7 +4391,7 @@ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write, #if 0 /* Ready but not used anywhere */ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */ static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core) { u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; @@ -4414,7 +4414,7 @@ static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core) b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) { u8 rxval, txval; @@ -4476,7 +4476,7 @@ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core) } #endif -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) { int i; @@ -4574,7 +4574,7 @@ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) b43_nphy_rx_iq_coeffs(dev, true, &new); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) { u16 array[4]; @@ -4586,7 +4586,7 @@ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */ static void b43_nphy_spur_workaround(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -4645,7 +4645,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -4713,7 +4713,7 @@ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev) /* * Restore RSSI Calibration - * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal + * https://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreRssiCal */ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev) { @@ -4822,7 +4822,7 @@ static void b43_nphy_tx_cal_radio_setup_rev7(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -4921,7 +4921,7 @@ static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/UpdateTxCalLadder */ static void b43_nphy_update_tx_cal_ladder(struct b43_wldev *dev, u16 core) { struct b43_phy_n *nphy = dev->phy.n; @@ -4955,14 +4955,14 @@ static void b43_nphy_pa_set_tx_dig_filter(struct b43_wldev *dev, u16 offset, b43_phy_write(dev, offset, filter[i]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ExtPaSetTxDigiFilts */ static void b43_nphy_ext_pa_set_tx_dig_filters(struct b43_wldev *dev) { b43_nphy_pa_set_tx_dig_filter(dev, 0x2C5, tbl_tx_filter_coef_rev4[2]); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/IpaSetTxDigiFilts */ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) { /* B43_NPHY_TXF_20CO_S0A1, B43_NPHY_TXF_40CO_S0A1, unknown */ @@ -5002,7 +5002,7 @@ static void b43_nphy_int_pa_set_tx_dig_filters(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/GetTxGain */ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -5077,7 +5077,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) return target; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhyCleanup */ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) { u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs; @@ -5106,7 +5106,7 @@ static void b43_nphy_tx_cal_phy_cleanup(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalPhySetup */ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -5207,7 +5207,7 @@ static void b43_nphy_tx_cal_phy_setup(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SaveCal */ static void b43_nphy_save_cal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -5278,7 +5278,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RestoreCal */ static void b43_nphy_restore_cal(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; @@ -5366,7 +5366,7 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev) b43_nphy_rx_iq_coeffs(dev, true, rxcal_coeffs); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalTxIqlo */ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, struct nphy_txgains target, bool full, bool mphase) @@ -5599,7 +5599,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev, return error; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ReapplyTxCalCoeffs */ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) { struct b43_phy_n *nphy = dev->phy.n; @@ -5634,7 +5634,7 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIqRev2 */ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, struct nphy_txgains target, u8 type, bool debug) { @@ -5643,7 +5643,7 @@ static int b43_nphy_rev2_cal_rx_iq(struct b43_wldev *dev, u8 rfctl[2]; u8 afectl_core; u16 tmp[6]; - u16 uninitialized_var(cur_hpf1), uninitialized_var(cur_hpf2), cur_lna; + u16 cur_hpf1, cur_hpf2, cur_lna; u32 real, imag; enum nl80211_band band; @@ -5821,7 +5821,7 @@ static int b43_nphy_rev3_cal_rx_iq(struct b43_wldev *dev, return -1; } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/CalRxIq */ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, struct nphy_txgains target, u8 type, bool debug) { @@ -5834,7 +5834,7 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev, return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask) { struct b43_phy *phy = &dev->phy; @@ -5939,7 +5939,7 @@ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev, * N-PHY init **************************************************/ -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */ static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) { u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG); @@ -5953,7 +5953,7 @@ static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble) b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */ static void b43_nphy_bphy_init(struct b43_wldev *dev) { unsigned int i; @@ -5972,7 +5972,7 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init) { if (dev->phy.rev >= 7) @@ -6246,7 +6246,7 @@ static void b43_chantab_phy_upload(struct b43_wldev *dev, b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6); } -/* http://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */ +/* https://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid) { switch (dev->dev->bus_type) { @@ -6265,7 +6265,7 @@ static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */ static void b43_nphy_channel_setup(struct b43_wldev *dev, const struct b43_phy_n_sfo_cfg *e, struct ieee80211_channel *new_channel) @@ -6372,7 +6372,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev, b43_nphy_spur_workaround(dev); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */ static int b43_nphy_set_channel(struct b43_wldev *dev, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type) @@ -6589,7 +6589,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value) b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value); } -/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, bool blocked) { @@ -6643,7 +6643,7 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev, } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/Anacore */ static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/broadcom/b43/radio_2056.c b/drivers/net/wireless/broadcom/b43/radio_2056.c index 575c696b7cdf..94f5e626acba 100644 --- a/drivers/net/wireless/broadcom/b43/radio_2056.c +++ b/drivers/net/wireless/broadcom/b43/radio_2056.c @@ -3072,7 +3072,7 @@ INITTABSPTS(b2056_inittab_radio_rev11); .phy_regs.phy_bw5 = r4, \ .phy_regs.phy_bw6 = r5 -/* http://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */ +/* https://bcm-v4.sipsolutions.net/802.11/Radio/2056/ChannelTable */ static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_phy_rev3[] = { { .freq = 4920, RADIOREGS3(0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, diff --git a/drivers/net/wireless/broadcom/b43/tables_nphy.c b/drivers/net/wireless/broadcom/b43/tables_nphy.c index dad405abf9b1..7957db94e84c 100644 --- a/drivers/net/wireless/broadcom/b43/tables_nphy.c +++ b/drivers/net/wireless/broadcom/b43/tables_nphy.c @@ -3620,7 +3620,7 @@ static void b43_nphy_tables_init_rev0(struct b43_wldev *dev) ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables */ void b43_nphy_tables_init(struct b43_wldev *dev) { if (dev->phy.rev >= 16) @@ -3633,7 +3633,7 @@ void b43_nphy_tables_init(struct b43_wldev *dev) b43_nphy_tables_init_rev0(dev); } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ +/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/broadcom/b43/xmit.c b/drivers/net/wireless/broadcom/b43/xmit.c index 55babc6d1091..7651b1bdb592 100644 --- a/drivers/net/wireless/broadcom/b43/xmit.c +++ b/drivers/net/wireless/broadcom/b43/xmit.c @@ -422,10 +422,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; - struct ieee80211_hdr *uninitialized_var(hdr); + struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; - struct b43_plcp_hdr6 *uninitialized_var(plcp); + struct b43_plcp_hdr6 *plcp; struct ieee80211_rate *rts_cts_rate; rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); @@ -436,7 +436,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - struct ieee80211_cts *uninitialized_var(cts); + struct ieee80211_cts *cts; switch (dev->fw.hdr_format) { case B43_FW_HDR_598: @@ -458,7 +458,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { - struct ieee80211_rts *uninitialized_var(rts); + struct ieee80211_rts *rts; switch (dev->fw.hdr_format) { case B43_FW_HDR_598: @@ -637,8 +637,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; __le16 fctl; u16 phystat0, phystat3; - u16 uninitialized_var(chanstat), uninitialized_var(mactime); - u32 uninitialized_var(macstat); + u16 chanstat, mactime; + u32 macstat; u16 chanid; int padding, rate_idx; diff --git a/drivers/net/wireless/broadcom/b43legacy/debugfs.c b/drivers/net/wireless/broadcom/b43legacy/debugfs.c index fa133dfb2ecb..e7e4293c01f2 100644 --- a/drivers/net/wireless/broadcom/b43legacy/debugfs.c +++ b/drivers/net/wireless/broadcom/b43legacy/debugfs.c @@ -190,7 +190,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, struct b43legacy_wldev *dev; struct b43legacy_debugfs_fops *dfops; struct b43legacy_dfs_file *dfile; - ssize_t uninitialized_var(ret); + ssize_t ret; char *buf; const size_t bufsize = 1024 * 16; /* 16 KiB buffer */ const size_t buforder = get_order(bufsize); diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 5208a39fd6f7..2eaf481f03f1 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -591,7 +591,7 @@ static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev) } /* DummyTransmission function, as documented on - * http://bcm-specs.sipsolutions.net/DummyTransmission + * https://bcm-specs.sipsolutions.net/DummyTransmission */ void b43legacy_dummy_transmission(struct b43legacy_wldev *dev) { @@ -1477,8 +1477,8 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev) static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl) { - b43legacyerr(wl, "You must go to http://wireless.kernel.org/en/users/" - "Drivers/b43#devicefirmware " + b43legacyerr(wl, "You must go to https://wireless.wiki.kernel.org/en/" + "users/Drivers/b43#devicefirmware " "and download the correct firmware (version 3).\n"); } @@ -1870,7 +1870,7 @@ out: } /* Initialize the GPIOs - * http://bcm-specs.sipsolutions.net/GPIO + * https://bcm-specs.sipsolutions.net/GPIO */ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) { @@ -1960,7 +1960,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) } } -/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +/* https://bcm-specs.sipsolutions.net/SuspendMAC */ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) { int i; @@ -2141,7 +2141,7 @@ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) } /* Initialize the chip - * http://bcm-specs.sipsolutions.net/ChipInit + * https://bcm-specs.sipsolutions.net/ChipInit */ static int b43legacy_chip_init(struct b43legacy_wldev *dev) { @@ -2580,7 +2580,7 @@ static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev) static int b43legacy_switch_phymode(struct b43legacy_wl *wl, unsigned int new_mode) { - struct b43legacy_wldev *uninitialized_var(up_dev); + struct b43legacy_wldev *up_dev; struct b43legacy_wldev *down_dev; int err; bool gmode = false; diff --git a/drivers/net/wireless/broadcom/b43legacy/phy.c b/drivers/net/wireless/broadcom/b43legacy/phy.c index a659259bc51a..05404fbd1e70 100644 --- a/drivers/net/wireless/broadcom/b43legacy/phy.c +++ b/drivers/net/wireless/broadcom/b43legacy/phy.c @@ -129,7 +129,7 @@ void b43legacy_phy_calibrate(struct b43legacy_wldev *dev) } /* initialize B PHY power control - * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + * as described in https://bcm-specs.sipsolutions.net/InitPowerControl */ static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev) { @@ -1461,7 +1461,7 @@ void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev, b43legacy_phy_write(dev, 0x0060, value); } -/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +/* https://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev) { static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; @@ -1721,7 +1721,7 @@ void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev) } } -/* http://bcm-specs.sipsolutions.net/EstimatePowerOut +/* https://bcm-specs.sipsolutions.net/EstimatePowerOut * This function converts a TSSI value to dBm in Q5.2 */ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) @@ -1747,7 +1747,7 @@ static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi) return dbm; } -/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +/* https://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) { struct b43legacy_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/broadcom/b43legacy/radio.c b/drivers/net/wireless/broadcom/b43legacy/radio.c index da40d1ca8723..06891b4f837b 100644 --- a/drivers/net/wireless/broadcom/b43legacy/radio.c +++ b/drivers/net/wireless/broadcom/b43legacy/radio.c @@ -313,14 +313,14 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) return ret[channel - 1]; } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val) { b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val); } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) { u16 val; @@ -331,7 +331,7 @@ s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) return (s16)val; } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) { u16 i; @@ -345,7 +345,7 @@ void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) } } -/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +/* https://bcm-specs.sipsolutions.net/NRSSILookupTable */ void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) { struct b43legacy_phy *phy = &dev->phy; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 46346cb3bc84..1a7ab49295aa 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -863,7 +863,7 @@ static void brcmf_sdiod_freezer_detach(struct brcmf_sdio_dev *sdiodev) } #endif /* CONFIG_PM_SLEEP */ -static int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) +int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev) { sdiodev->state = BRCMF_SDIOD_DOWN; if (sdiodev->bus) { @@ -898,7 +898,7 @@ static void brcmf_sdiod_host_fixup(struct mmc_host *host) host->caps |= MMC_CAP_NONREMOVABLE; } -static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) +int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) { int ret = 0; unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index a757abd7a599..ab0da2ff982e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -84,6 +84,8 @@ #define BRCMF_ND_INFO_TIMEOUT msecs_to_jiffies(2000) +#define BRCMF_PS_MAX_TIMEOUT_MS 2000 + #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) @@ -1387,7 +1389,8 @@ static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, return err; } -static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) +static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason, + bool locally_generated) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); struct brcmf_pub *drvr = cfg->pub; @@ -1409,7 +1412,7 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) if ((vif->wdev.iftype == NL80211_IFTYPE_STATION) || (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0, - true, GFP_KERNEL); + locally_generated, GFP_KERNEL); } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); @@ -1588,7 +1591,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) return 0; } - brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING); + brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING, true); brcmf_net_setcarrier(ifp, false); brcmf_dbg(TRACE, "Exit\n"); @@ -2941,6 +2944,12 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, else bphy_err(drvr, "error (%d)\n", err); } + + err = brcmf_fil_iovar_int_set(ifp, "pm2_sleep_ret", + min_t(u32, timeout, BRCMF_PS_MAX_TIMEOUT_MS)); + if (err) + bphy_err(drvr, "Unable to set pm timeout, (%d)\n", err); + done: brcmf_dbg(TRACE, "Exit\n"); return err; @@ -3907,7 +3916,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, * disassociate from AP to save power while system is * in suspended state */ - brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED); + brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED, true); /* Make sure WPA_Supplicant receives all the event * generated due to DISASSOC call to the fw to keep * the state fw and WPA_Supplicant state consistent @@ -4835,12 +4844,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, goto exit; } - if (settings->hidden_ssid) { - err = brcmf_fil_iovar_int_set(ifp, "closednet", 1); - if (err) { - bphy_err(drvr, "closednet error (%d)\n", err); - goto exit; - } + err = brcmf_fil_iovar_int_set(ifp, "closednet", + settings->hidden_ssid); + if (err) { + bphy_err(drvr, "%s closednet error (%d)\n", + settings->hidden_ssid ? + "enabled" : "disabled", + err); + goto exit; } brcmf_dbg(TRACE, "AP mode configuration complete\n"); @@ -5129,7 +5140,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, &freq); chan_nr = ieee80211_frequency_to_channel(freq); af_params->channel = cpu_to_le32(chan_nr); - + af_params->dwell_time = cpu_to_le32(params->wait); memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], le16_to_cpu(action_frame->len)); @@ -6024,10 +6035,19 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, brcmf_net_setcarrier(ifp, true); } else if (brcmf_is_linkdown(e)) { brcmf_dbg(CONN, "Linkdown\n"); - if (!brcmf_is_ibssmode(ifp->vif)) { + if (!brcmf_is_ibssmode(ifp->vif) && + test_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state)) { + if (memcmp(profile->bssid, e->addr, ETH_ALEN)) + return err; + brcmf_bss_connect_done(cfg, ndev, e, false); brcmf_link_down(ifp->vif, - brcmf_map_fw_linkdown_reason(e)); + brcmf_map_fw_linkdown_reason(e), + e->event_code & + (BRCMF_E_DEAUTH_IND | + BRCMF_E_DISASSOC_IND) + ? false : true); brcmf_init_prof(ndev_to_prof(ndev)); if (ndev != cfg_to_ndev(cfg)) complete(&cfg->vif_disabled); @@ -6801,7 +6821,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { * #AP <= 4, matching BI, channels = 1, 4 total * * no p2p and rsdb: - * #STA <= 2, #AP <= 2, channels = 2, 4 total + * #STA <= 1, #AP <= 2, channels = 2, 4 total * * p2p, no mchan, and mbss: * @@ -6816,7 +6836,7 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { * #AP <= 4, matching BI, channels = 1, 4 total * * p2p, rsdb, and no mbss: - * #STA <= 2, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2, + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2, * channels = 2, 4 total */ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) @@ -6857,7 +6877,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) goto err; combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan)); - c0_limits[i].max = 1 + rsdb; + c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); if (mon_flag) { c0_limits[i].max = 1; @@ -6873,7 +6893,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (p2p && rsdb) { c0_limits[i].max = 2; c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); - combo[c].max_interfaces = 5; + combo[c].max_interfaces = 4; } else if (p2p) { combo[c].max_interfaces = i; } else if (rsdb) { @@ -7180,7 +7200,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp) * from AP to save power */ if (check_vif_up(ifp->vif)) { - brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED); + brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED, true); /* Make sure WPA_Supplicant receives all the event generated due to DISASSOC call to the fw to keep diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index dec25e415619..e3758bd86acf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -209,8 +209,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err); goto done; } - memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN); memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); + memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN); bus = ifp->drvr->bus_if; ri = &ifp->drvr->revinfo; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index c88655acc78c..f89010a81ffb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -352,6 +352,9 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, if ((skb->priority == 0) || (skb->priority > 7)) skb->priority = cfg80211_classify8021d(skb, NULL); + /* set pacing shift for packet aggregation */ + sk_pacing_shift_update(skb->sk, 8); + ret = brcmf_proto_tx_queue_data(drvr, ifp->ifidx, skb); if (ret < 0) brcmf_txfinalize(ifp, skb, false); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index de0ef1b545c4..2e31cc10c195 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -19,7 +19,7 @@ #define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x00000008 #define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */ -#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0002 +#define BRCMF_BSS_RSSI_ON_CHANNEL 0x0004 #define BRCMF_STA_BRCM 0x00000001 /* Running a Broadcom driver */ #define BRCMF_STA_WME 0x00000002 /* WMM association */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 09701262330d..2df6811c066e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -323,6 +323,10 @@ struct brcmf_skbuff_cb { * firmware suppress the packet as device is already in PS mode. * @BRCMF_FWS_TXSTATUS_FW_TOSSED: * firmware tossed the packet. + * @BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK: + * firmware tossed the packet after retries. + * @BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED: + * firmware wrongly reported suppressed previously, now fixing to acked. * @BRCMF_FWS_TXSTATUS_HOST_TOSSED: * host tossed the packet. */ @@ -331,6 +335,8 @@ enum brcmf_fws_txstatus { BRCMF_FWS_TXSTATUS_CORE_SUPPRESS, BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS, BRCMF_FWS_TXSTATUS_FW_TOSSED, + BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK, + BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED, BRCMF_FWS_TXSTATUS_HOST_TOSSED }; @@ -383,6 +389,7 @@ struct brcmf_fws_mac_descriptor { }; #define BRCMF_FWS_HANGER_MAXITEMS 3072 +#define BRCMF_BORROW_RATIO 3 /** * enum brcmf_fws_hanger_item_state - state of hanger item. @@ -479,7 +486,8 @@ struct brcmf_fws_info { u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT]; int fifo_credit[BRCMF_FWS_FIFO_COUNT]; int init_fifo_credit[BRCMF_FWS_FIFO_COUNT]; - int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1]; + int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1] + [BRCMF_FWS_FIFO_AC_VO + 1]; int deq_node_pos[BRCMF_FWS_FIFO_COUNT]; u32 fifo_credit_map; u32 fifo_delay_map; @@ -621,6 +629,7 @@ static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h, static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q, int ifidx) { + struct brcmf_fws_hanger_item *hi; bool (*matchfn)(struct sk_buff *, void *) = NULL; struct sk_buff *skb; int prec; @@ -632,6 +641,9 @@ static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q, skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); while (skb) { hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT); + hi = &fws->hanger.items[hslot]; + WARN_ON(skb != hi->pkt); + hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE; brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true); brcmu_pkt_buf_free_skb(skb); @@ -1187,11 +1199,11 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws, fws->fifo_credit_map |= 1 << fifo; - if ((fifo == BRCMF_FWS_FIFO_AC_BE) && - (fws->credits_borrowed[0])) { + if (fifo > BRCMF_FWS_FIFO_AC_BK && + fifo <= BRCMF_FWS_FIFO_AC_VO) { for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0; lender_ac--) { - borrowed = &fws->credits_borrowed[lender_ac]; + borrowed = &fws->credits_borrowed[fifo][lender_ac]; if (*borrowed) { fws->fifo_credit_map |= (1 << lender_ac); fifo_credit = &fws->fifo_credit[lender_ac]; @@ -1208,7 +1220,10 @@ static void brcmf_fws_return_credits(struct brcmf_fws_info *fws, } } - fws->fifo_credit[fifo] += credits; + if (credits) { + fws->fifo_credit[fifo] += credits; + } + if (fws->fifo_credit[fifo] > fws->init_fifo_credit[fifo]) fws->fifo_credit[fifo] = fws->init_fifo_credit[fifo]; @@ -1451,6 +1466,10 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot, remove_from_hanger = false; } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED) fws->stats.txs_tossed += compcnt; + else if (flags == BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK) + fws->stats.txs_discard += compcnt; + else if (flags == BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED) + fws->stats.txs_discard += compcnt; else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) fws->stats.txs_host_tossed += compcnt; else @@ -1843,6 +1862,9 @@ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb) WARN_ON(siglen > skb->len); + if (siglen > skb->len) + siglen = skb->len; + if (!siglen) return; /* if flow control disabled, skip to packet data and leave */ @@ -2005,27 +2027,31 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, } } -static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws) +static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws, + int highest_lender_ac, int borrower_ac, + bool borrow_all) { - int lender_ac; + int lender_ac, borrow_limit = 0; - if (time_after(fws->borrow_defer_timestamp, jiffies)) { - fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE); - return -ENAVAIL; - } + for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) { - for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) { - if (fws->fifo_credit[lender_ac] > 0) { - fws->credits_borrowed[lender_ac]++; + if (!borrow_all) + borrow_limit = + fws->init_fifo_credit[lender_ac] / BRCMF_BORROW_RATIO; + else + borrow_limit = 0; + + if (fws->fifo_credit[lender_ac] > borrow_limit) { + fws->credits_borrowed[borrower_ac][lender_ac]++; fws->fifo_credit[lender_ac]--; if (fws->fifo_credit[lender_ac] == 0) fws->fifo_credit_map &= ~(1 << lender_ac); - fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE); + fws->fifo_credit_map |= (1 << borrower_ac); brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac); return 0; } } - fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE); + fws->fifo_credit_map &= ~(1 << borrower_ac); return -ENAVAIL; } @@ -2216,9 +2242,10 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) } continue; } - while ((fws->fifo_credit[fifo] > 0) || + + while ((fws->fifo_credit[fifo]) || ((!fws->bcmc_credit_check) && - (fifo == BRCMF_FWS_FIFO_BCMC))) { + (fifo == BRCMF_FWS_FIFO_BCMC))) { skb = brcmf_fws_deq(fws, fifo); if (!skb) break; @@ -2228,10 +2255,14 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) if (fws->bus_flow_blocked) break; } - if ((fifo == BRCMF_FWS_FIFO_AC_BE) && - (fws->fifo_credit[fifo] <= 0) && - (!fws->bus_flow_blocked)) { - while (brcmf_fws_borrow_credit(fws) == 0) { + + if (fifo >= BRCMF_FWS_FIFO_AC_BE && + fifo <= BRCMF_FWS_FIFO_AC_VO && + fws->fifo_credit[fifo] == 0 && + !fws->bus_flow_blocked) { + while (brcmf_fws_borrow_credit(fws, + fifo - 1, fifo, + true) == 0) { skb = brcmf_fws_deq(fws, fifo); if (!skb) { brcmf_fws_return_credits(fws, fifo, 1); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index 8bb4f1fa790e..f1a20db8daab 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -54,6 +54,7 @@ #define BRCMF_IOCTL_REQ_PKTID 0xFFFE #define BRCMF_MSGBUF_MAX_PKT_SIZE 2048 +#define BRCMF_MSGBUF_MAX_CTL_PKT_SIZE 8192 #define BRCMF_MSGBUF_RXBUFPOST_THRESHOLD 32 #define BRCMF_MSGBUF_MAX_IOCTLRESPBUF_POST 8 #define BRCMF_MSGBUF_MAX_EVENTBUF_POST 8 @@ -1028,7 +1029,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf, rx_bufpost = (struct msgbuf_rx_ioctl_resp_or_event *)ret_ptr; memset(rx_bufpost, 0, sizeof(*rx_bufpost)); - skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_PKT_SIZE); + skb = brcmu_pkt_buf_get_skb(BRCMF_MSGBUF_MAX_CTL_PKT_SIZE); if (skb == NULL) { bphy_err(drvr, "Failed to alloc SKB\n"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c index b886b56a5e5a..a7554265f95f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -17,7 +17,6 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, { struct brcmfmac_sdio_pd *sdio = &settings->bus.sdio; struct device_node *root, *np = dev->of_node; - struct property *prop; int irq; u32 irqf; u32 val; @@ -25,8 +24,22 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, /* Set board-type to the first string of the machine compatible prop */ root = of_find_node_by_path("/"); if (root) { - prop = of_find_property(root, "compatible", NULL); - settings->board_type = of_prop_next_string(prop, NULL); + int i, len; + char *board_type; + const char *tmp; + + of_property_read_string_index(root, "compatible", 0, &tmp); + + /* get rid of '/' in the compatible string to be able to find the FW */ + len = strlen(tmp) + 1; + board_type = devm_kzalloc(dev, len, GFP_KERNEL); + strscpy(board_type, tmp, len); + for (i = 0; i < board_type[i]; i++) { + if (board_type[i] == '/') + board_type[i] = '-'; + } + settings->board_type = board_type; + of_node_put(root); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index d2795dc17c46..debd887e159e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1700,7 +1700,7 @@ static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg, return err; } -static bool brcmf_p2p_check_dwell_overflow(s32 requested_dwell, +static bool brcmf_p2p_check_dwell_overflow(u32 requested_dwell, unsigned long dwell_jiffies) { if ((requested_dwell & CUSTOM_RETRY_MASK) && @@ -1738,8 +1738,7 @@ bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, unsigned long dwell_jiffies = 0; bool dwell_overflow = false; - s32 requested_dwell = af_params->dwell_time; - + u32 requested_dwell = le32_to_cpu(af_params->dwell_time); action_frame = &af_params->action_frame; action_frame_len = le16_to_cpu(action_frame->len); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 310d8075f5d7..e8712ad3ac45 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -16,6 +16,7 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio_func.h> #include <linux/mmc/card.h> +#include <linux/mmc/core.h> #include <linux/semaphore.h> #include <linux/firmware.h> #include <linux/module.h> @@ -648,6 +649,8 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) }; +#define TXCTL_CREDITS 2 + static void pkt_align(struct sk_buff *p, int len, int align) { uint datalign; @@ -661,8 +664,16 @@ static void pkt_align(struct sk_buff *p, int len, int align) /* To check if there's window offered */ static bool data_ok(struct brcmf_sdio *bus) { - return (u8)(bus->tx_max - bus->tx_seq) != 0 && - ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; + /* Reserve TXCTL_CREDITS credits for txctl */ + return (bus->tx_max - bus->tx_seq) > TXCTL_CREDITS && + ((bus->tx_max - bus->tx_seq) & 0x80) == 0; +} + +/* To check if there's window offered */ +static bool txctl_ok(struct brcmf_sdio *bus) +{ + return (bus->tx_max - bus->tx_seq) != 0 && + ((bus->tx_max - bus->tx_seq) & 0x80) == 0; } static int @@ -2668,7 +2679,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) brcmf_sdio_clrintr(bus); if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) && - data_ok(bus)) { + txctl_ok(bus)) { sdio_claim_host(bus->sdiodev->func1); if (bus->ctrl_frame_stat) { err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf, @@ -2676,6 +2687,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus) bus->ctrl_frame_err = err; wmb(); bus->ctrl_frame_stat = false; + if (err) + brcmf_err("sdio ctrlframe tx failed err=%d\n", + err); } sdio_release_host(bus->sdiodev->func1); brcmf_sdio_wait_event_wakeup(bus); @@ -3699,7 +3713,11 @@ static void brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus) if (bus->idlecount > bus->idletime) { brcmf_dbg(SDIO, "idle\n"); sdio_claim_host(bus->sdiodev->func1); - brcmf_sdio_wd_timer(bus, false); +#ifdef DEBUG + if (!BRCMF_FWCON_ON() || + bus->console_interval == 0) +#endif + brcmf_sdio_wd_timer(bus, false); bus->idlecount = 0; brcmf_sdio_bus_sleep(bus, true, false); sdio_release_host(bus->sdiodev->func1); @@ -4109,6 +4127,36 @@ int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name) return 0; } +static int brcmf_sdio_bus_reset(struct device *dev) +{ + int ret = 0; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; + + brcmf_dbg(SDIO, "Enter\n"); + + /* start by unregistering irqs */ + brcmf_sdiod_intr_unregister(sdiodev); + + brcmf_sdiod_remove(sdiodev); + + /* reset the adapter */ + sdio_claim_host(sdiodev->func1); + mmc_hw_reset(sdiodev->func1->card->host); + sdio_release_host(sdiodev->func1); + + brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN); + + ret = brcmf_sdiod_probe(sdiodev); + if (ret) { + brcmf_err("Failed to probe after sdio device reset: ret %d\n", + ret); + brcmf_sdiod_remove(sdiodev); + } + + return ret; +} + static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { .stop = brcmf_sdio_bus_stop, .preinit = brcmf_sdio_bus_preinit, @@ -4120,7 +4168,8 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { .get_ramsize = brcmf_sdio_bus_get_ramsize, .get_memdump = brcmf_sdio_bus_get_memdump, .get_fwname = brcmf_sdio_get_fwname, - .debugfs_create = brcmf_sdio_debugfs_create + .debugfs_create = brcmf_sdio_debugfs_create, + .reset = brcmf_sdio_bus_reset }; #define BRCMF_SDIO_FW_CODE 0 diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h index 163fd664780a..12108927fb50 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h @@ -367,6 +367,9 @@ static inline void brcmf_sdiod_freezer_uncount(struct brcmf_sdio_dev *sdiodev) } #endif /* CONFIG_PM_SLEEP */ +int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev); +int brcmf_sdiod_remove(struct brcmf_sdio_dev *sdiodev); + struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); void brcmf_sdio_remove(struct brcmf_sdio *bus); void brcmf_sdio_isr(struct brcmf_sdio *bus); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c index c0a5449ed72c..c1b9ac692d26 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <net/mac80211.h> #include <linux/bcma/bcma_driver_chipcommon.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> +#include <linux/gpio/consumer.h> #include "mac80211_if.h" #include "pub.h" @@ -19,16 +21,13 @@ static void brcms_radio_led_ctrl(struct brcms_info *wl, bool state) { - if (wl->radio_led.gpio == -1) + if (!wl->radio_led.gpiod) return; - if (wl->radio_led.active_low) - state = !state; - if (state) - gpio_set_value(wl->radio_led.gpio, 1); + gpiod_set_value(wl->radio_led.gpiod, 1); else - gpio_set_value(wl->radio_led.gpio, 0); + gpiod_set_value(wl->radio_led.gpiod, 0); } @@ -45,8 +44,8 @@ void brcms_led_unregister(struct brcms_info *wl) { if (wl->led_dev.dev) led_classdev_unregister(&wl->led_dev); - if (wl->radio_led.gpio != -1) - gpio_free(wl->radio_led.gpio); + if (wl->radio_led.gpiod) + gpiochip_free_own_desc(wl->radio_led.gpiod); } int brcms_led_register(struct brcms_info *wl) @@ -61,12 +60,8 @@ int brcms_led_register(struct brcms_info *wl) &sprom->gpio1, &sprom->gpio2, &sprom->gpio3 }; - unsigned gpio = -1; - bool active_low = false; - - /* none by default */ - radio_led->gpio = -1; - radio_led->active_low = false; + int hwnum = -1; + enum gpio_lookup_flags lflags = GPIO_ACTIVE_HIGH; if (!bcma_gpio || !gpio_is_valid(bcma_gpio->base)) return -ENODEV; @@ -75,30 +70,26 @@ int brcms_led_register(struct brcms_info *wl) for (i = 0; i < BRCMS_LED_NO; i++) { u8 led = *leds[i]; if ((led & BRCMS_LED_BEH_MASK) == BRCMS_LED_RADIO) { - gpio = bcma_gpio->base + i; + hwnum = i; if (led & BRCMS_LED_AL_MASK) - active_low = true; + lflags = GPIO_ACTIVE_LOW; break; } } - if (gpio == -1 || !gpio_is_valid(gpio)) + /* No LED, bail out */ + if (hwnum == -1) return -ENODEV; - /* request and configure LED gpio */ - err = gpio_request_one(gpio, - active_low ? GPIOF_OUT_INIT_HIGH - : GPIOF_OUT_INIT_LOW, - "radio on"); - if (err) { - wiphy_err(wl->wiphy, "requesting led gpio %d failed (err: %d)\n", - gpio, err); - return err; - } - err = gpio_direction_output(gpio, 1); - if (err) { - wiphy_err(wl->wiphy, "cannot set led gpio %d to output (err: %d)\n", - gpio, err); + /* Try to obtain this LED GPIO line */ + radio_led->gpiod = gpiochip_request_own_desc(bcma_gpio, hwnum, + "radio on", lflags, + GPIOD_OUT_LOW); + + if (IS_ERR(radio_led->gpiod)) { + err = PTR_ERR(radio_led->gpiod); + wiphy_err(wl->wiphy, "requesting led GPIO failed (err: %d)\n", + err); return err; } @@ -117,11 +108,8 @@ int brcms_led_register(struct brcms_info *wl) return err; } - wiphy_info(wl->wiphy, "registered radio enabled led device: %s gpio: %d\n", - wl->radio_led.name, - gpio); - radio_led->gpio = gpio; - radio_led->active_low = active_low; + wiphy_info(wl->wiphy, "registered radio enabled led device: %s\n", + wl->radio_led.name); return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h index 17a0b1f5dbcf..d65f5c268fd7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h @@ -16,10 +16,12 @@ #ifndef _BRCM_LED_H_ #define _BRCM_LED_H_ + +struct gpio_desc; + struct brcms_led { char name[32]; - unsigned gpio; - bool active_low; + struct gpio_desc *gpiod; }; #ifdef CONFIG_BCMA_DRIVER_GPIO diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index 827bb6d74815..316672486d82 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -74,16 +74,19 @@ MODULE_DEVICE_TABLE(pci, card_ids); static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); static void airo_pci_remove(struct pci_dev *); -static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state); -static int airo_pci_resume(struct pci_dev *pdev); +static int __maybe_unused airo_pci_suspend(struct device *dev); +static int __maybe_unused airo_pci_resume(struct device *dev); + +static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops, + airo_pci_suspend, + airo_pci_resume); static struct pci_driver airo_driver = { - .name = DRV_NAME, - .id_table = card_ids, - .probe = airo_pci_probe, - .remove = airo_pci_remove, - .suspend = airo_pci_suspend, - .resume = airo_pci_resume, + .name = DRV_NAME, + .id_table = card_ids, + .probe = airo_pci_probe, + .remove = airo_pci_remove, + .driver.pm = &airo_pci_pm_ops, }; #endif /* CONFIG_PCI */ @@ -2450,7 +2453,7 @@ static void mpi_unmap_card(struct pci_dev *pci) /************************************************************* * This routine assumes that descriptors have been setup . - * Run at insmod time or after reset when the decriptors + * Run at insmod time or after reset when the descriptors * have been initialized . Returns 0 if all is well nz * otherwise . Does not allocate memory but sets up card * using previously allocated descriptors. @@ -3113,7 +3116,7 @@ static int airo_thread(void *data) { } break; } - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); remove_wait_queue(&ai->thr_wait, &wait); locked = 1; } @@ -5573,9 +5576,9 @@ static void airo_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused airo_pci_suspend(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; @@ -5591,25 +5594,21 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) return -EAGAIN; disable_MAC(ai, 0); netif_device_detach(dev); - ai->power = state; + ai->power = PMSG_SUSPEND; cmd.cmd = HOSTSLEEP; issuecommand(ai, &cmd, &rsp); - pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + device_wakeup_enable(dev_d); return 0; } -static int airo_pci_resume(struct pci_dev *pdev) +static int __maybe_unused airo_pci_resume(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); struct airo_info *ai = dev->ml_priv; - pci_power_t prev_state = pdev->current_state; + pci_power_t prev_state = to_pci_dev(dev_d)->current_state; - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D0, 0); + device_wakeup_disable(dev_d); if (prev_state != PCI_D1) { reset_card(dev, 0); diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig index d00386915a9d..b1e7b4470842 100644 --- a/drivers/net/wireless/intel/ipw2x00/Kconfig +++ b/drivers/net/wireless/intel/ipw2x00/Kconfig @@ -16,7 +16,7 @@ config IPW2100 A driver for the Intel PRO/Wireless 2100 Network Connection 802.11b wireless network adapter. - See <file:Documentation/networking/device_drivers/intel/ipw2100.rst> + See <file:Documentation/networking/device_drivers/wifi/intel/ipw2100.rst> for information on the capabilities currently enabled in this driver and for tips for debugging issues and problems. @@ -28,7 +28,7 @@ config IPW2100 You will also very likely need the Wireless Tools in order to configure your card: - <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. It is recommended that you compile this driver as a module (M) rather than built-in (Y). This driver requires firmware at device @@ -78,7 +78,7 @@ config IPW2200 A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network Connection adapters. - See <file:Documentation/networking/device_drivers/intel/ipw2200.rst> + See <file:Documentation/networking/device_drivers/wifi/intel/ipw2200.rst> for information on the capabilities currently enabled in this driver and for tips for debugging issues and problems. @@ -90,7 +90,7 @@ config IPW2200 You will also very likely need the Wireless Tools in order to configure your card: - <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. It is recommended that you compile this driver as a module (M) rather than built-in (Y). This driver requires firmware at device diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 624fe721e2b5..461e955aa259 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -2295,10 +2295,11 @@ static int ipw2100_alloc_skb(struct ipw2100_priv *priv, return -ENOMEM; packet->rxp = (struct ipw2100_rx *)packet->skb->data; - packet->dma_addr = pci_map_single(priv->pci_dev, packet->skb->data, + packet->dma_addr = dma_map_single(&priv->pci_dev->dev, + packet->skb->data, sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pci_dev, packet->dma_addr)) { + DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pci_dev->dev, packet->dma_addr)) { dev_kfree_skb(packet->skb); return -ENOMEM; } @@ -2479,9 +2480,8 @@ static void isr_rx(struct ipw2100_priv *priv, int i, return; } - pci_unmap_single(priv->pci_dev, - packet->dma_addr, - sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr, + sizeof(struct ipw2100_rx), DMA_FROM_DEVICE); skb_put(packet->skb, status->frame_size); @@ -2563,8 +2563,8 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, return; } - pci_unmap_single(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr, + sizeof(struct ipw2100_rx), DMA_FROM_DEVICE); memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), packet->skb->data, status->frame_size); @@ -2689,9 +2689,9 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) /* Sync the DMA for the RX buffer so CPU is sure to get * the correct values */ - pci_dma_sync_single_for_cpu(priv->pci_dev, packet->dma_addr, - sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pci_dev->dev, packet->dma_addr, + sizeof(struct ipw2100_rx), + DMA_FROM_DEVICE); if (unlikely(ipw2100_corruption_check(priv, i))) { ipw2100_corruption_detected(priv, i); @@ -2923,9 +2923,8 @@ static int __ipw2100_tx_process(struct ipw2100_priv *priv) (packet->index + 1 + i) % txq->entries, tbd->host_addr, tbd->buf_length); - pci_unmap_single(priv->pci_dev, - tbd->host_addr, - tbd->buf_length, PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pci_dev->dev, tbd->host_addr, + tbd->buf_length, DMA_TO_DEVICE); } libipw_txb_free(packet->info.d_struct.txb); @@ -3165,15 +3164,13 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) tbd->buf_length = packet->info.d_struct.txb-> fragments[i]->len - LIBIPW_3ADDR_LEN; - tbd->host_addr = pci_map_single(priv->pci_dev, + tbd->host_addr = dma_map_single(&priv->pci_dev->dev, packet->info.d_struct. - txb->fragments[i]-> - data + + txb->fragments[i]->data + LIBIPW_3ADDR_LEN, tbd->buf_length, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pci_dev, - tbd->host_addr)) { + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pci_dev->dev, tbd->host_addr)) { IPW_DEBUG_TX("dma mapping error\n"); break; } @@ -3182,10 +3179,10 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv) txq->next, tbd->host_addr, tbd->buf_length); - pci_dma_sync_single_for_device(priv->pci_dev, - tbd->host_addr, - tbd->buf_length, - PCI_DMA_TODEVICE); + dma_sync_single_for_device(&priv->pci_dev->dev, + tbd->host_addr, + tbd->buf_length, + DMA_TO_DEVICE); txq->next++; txq->next %= txq->entries; @@ -3440,9 +3437,9 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) return -ENOMEM; for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - v = pci_zalloc_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - &p); + v = dma_alloc_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_cmd_header), &p, + GFP_KERNEL); if (!v) { printk(KERN_ERR DRV_NAME ": " "%s: PCI alloc failed for msg " @@ -3461,11 +3458,10 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[j].info.c_struct.cmd, - priv->msg_buffers[j].info.c_struct. - cmd_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[j].info.c_struct.cmd, + priv->msg_buffers[j].info.c_struct.cmd_phys); } kfree(priv->msg_buffers); @@ -3496,11 +3492,10 @@ static void ipw2100_msg_free(struct ipw2100_priv *priv) return; for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_cmd_header), - priv->msg_buffers[i].info.c_struct.cmd, - priv->msg_buffers[i].info.c_struct. - cmd_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_cmd_header), + priv->msg_buffers[i].info.c_struct.cmd, + priv->msg_buffers[i].info.c_struct.cmd_phys); } kfree(priv->msg_buffers); @@ -4323,7 +4318,8 @@ static int status_queue_allocate(struct ipw2100_priv *priv, int entries) IPW_DEBUG_INFO("enter\n"); q->size = entries * sizeof(struct ipw2100_status); - q->drv = pci_zalloc_consistent(priv->pci_dev, q->size, &q->nic); + q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic, + GFP_KERNEL); if (!q->drv) { IPW_DEBUG_WARNING("Can not allocate status queue.\n"); return -ENOMEM; @@ -4339,9 +4335,10 @@ static void status_queue_free(struct ipw2100_priv *priv) IPW_DEBUG_INFO("enter\n"); if (priv->status_queue.drv) { - pci_free_consistent(priv->pci_dev, priv->status_queue.size, - priv->status_queue.drv, - priv->status_queue.nic); + dma_free_coherent(&priv->pci_dev->dev, + priv->status_queue.size, + priv->status_queue.drv, + priv->status_queue.nic); priv->status_queue.drv = NULL; } @@ -4357,7 +4354,8 @@ static int bd_queue_allocate(struct ipw2100_priv *priv, q->entries = entries; q->size = entries * sizeof(struct ipw2100_bd); - q->drv = pci_zalloc_consistent(priv->pci_dev, q->size, &q->nic); + q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic, + GFP_KERNEL); if (!q->drv) { IPW_DEBUG_INFO ("can't allocate shared memory for buffer descriptors\n"); @@ -4377,7 +4375,8 @@ static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q) return; if (q->drv) { - pci_free_consistent(priv->pci_dev, q->size, q->drv, q->nic); + dma_free_coherent(&priv->pci_dev->dev, q->size, q->drv, + q->nic); q->drv = NULL; } @@ -4430,16 +4429,16 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH, sizeof(struct ipw2100_tx_packet), - GFP_ATOMIC); + GFP_KERNEL); if (!priv->tx_buffers) { bd_queue_free(priv, &priv->tx_queue); return -ENOMEM; } for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) { - v = pci_alloc_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - &p); + v = dma_alloc_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_data_header), &p, + GFP_KERNEL); if (!v) { printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for tx " "buffers.\n", @@ -4459,11 +4458,10 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[j].info.d_struct.data, - priv->tx_buffers[j].info.d_struct. - data_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[j].info.d_struct.data, + priv->tx_buffers[j].info.d_struct.data_phys); } kfree(priv->tx_buffers); @@ -4540,12 +4538,10 @@ static void ipw2100_tx_free(struct ipw2100_priv *priv) priv->tx_buffers[i].info.d_struct.txb = NULL; } if (priv->tx_buffers[i].info.d_struct.data) - pci_free_consistent(priv->pci_dev, - sizeof(struct ipw2100_data_header), - priv->tx_buffers[i].info.d_struct. - data, - priv->tx_buffers[i].info.d_struct. - data_phys); + dma_free_coherent(&priv->pci_dev->dev, + sizeof(struct ipw2100_data_header), + priv->tx_buffers[i].info.d_struct.data, + priv->tx_buffers[i].info.d_struct.data_phys); } kfree(priv->tx_buffers); @@ -4608,9 +4604,10 @@ static int ipw2100_rx_allocate(struct ipw2100_priv *priv) return 0; for (j = 0; j < i; j++) { - pci_unmap_single(priv->pci_dev, priv->rx_buffers[j].dma_addr, + dma_unmap_single(&priv->pci_dev->dev, + priv->rx_buffers[j].dma_addr, sizeof(struct ipw2100_rx_packet), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); dev_kfree_skb(priv->rx_buffers[j].skb); } @@ -4662,10 +4659,10 @@ static void ipw2100_rx_free(struct ipw2100_priv *priv) for (i = 0; i < RX_QUEUE_LENGTH; i++) { if (priv->rx_buffers[i].rxp) { - pci_unmap_single(priv->pci_dev, + dma_unmap_single(&priv->pci_dev->dev, priv->rx_buffers[i].dma_addr, sizeof(struct ipw2100_rx), - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); dev_kfree_skb(priv->rx_buffers[i].skb); } } @@ -6196,7 +6193,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, pci_set_master(pci_dev); pci_set_drvdata(pci_dev, priv); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { printk(KERN_WARNING DRV_NAME "Error calling pci_set_dma_mask.\n"); @@ -6397,10 +6394,9 @@ static void ipw2100_pci_remove_one(struct pci_dev *pci_dev) IPW_DEBUG_INFO("exit\n"); } -#ifdef CONFIG_PM -static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) +static int __maybe_unused ipw2100_suspend(struct device *dev_d) { - struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); + struct ipw2100_priv *priv = dev_get_drvdata(dev_d); struct net_device *dev = priv->net_dev; IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name); @@ -6414,10 +6410,6 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) /* Remove the PRESENT state of the device */ netif_device_detach(dev); - pci_save_state(pci_dev); - pci_disable_device(pci_dev); - pci_set_power_state(pci_dev, PCI_D3hot); - priv->suspend_at = ktime_get_boottime_seconds(); mutex_unlock(&priv->action_mutex); @@ -6425,11 +6417,11 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) return 0; } -static int ipw2100_resume(struct pci_dev *pci_dev) +static int __maybe_unused ipw2100_resume(struct device *dev_d) { + struct pci_dev *pci_dev = to_pci_dev(dev_d); struct ipw2100_priv *priv = pci_get_drvdata(pci_dev); struct net_device *dev = priv->net_dev; - int err; u32 val; if (IPW2100_PM_DISABLED) @@ -6439,16 +6431,6 @@ static int ipw2100_resume(struct pci_dev *pci_dev) IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name); - pci_set_power_state(pci_dev, PCI_D0); - err = pci_enable_device(pci_dev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - mutex_unlock(&priv->action_mutex); - return err; - } - pci_restore_state(pci_dev); - /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries @@ -6473,7 +6455,6 @@ static int ipw2100_resume(struct pci_dev *pci_dev) return 0; } -#endif static void ipw2100_shutdown(struct pci_dev *pci_dev) { @@ -6539,15 +6520,14 @@ static const struct pci_device_id ipw2100_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table); +static SIMPLE_DEV_PM_OPS(ipw2100_pm_ops, ipw2100_suspend, ipw2100_resume); + static struct pci_driver ipw2100_pci_driver = { .name = DRV_NAME, .id_table = ipw2100_pci_id_table, .probe = ipw2100_pci_init_one, .remove = ipw2100_pci_remove_one, -#ifdef CONFIG_PM - .suspend = ipw2100_suspend, - .resume = ipw2100_resume, -#endif + .driver.pm = &ipw2100_pm_ops, .shutdown = ipw2100_shutdown, }; @@ -8352,7 +8332,7 @@ static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw) if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) { printk(KERN_WARNING DRV_NAME ": Firmware image not compatible " "(detected version id of %u). " - "See Documentation/networking/device_drivers/intel/ipw2100.rst\n", + "See Documentation/networking/device_drivers/wifi/intel/ipw2100.rst\n", h->version); return 1; } diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 661e63bfc892..129ef2f6248a 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -3442,8 +3442,9 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, /* In the reset function, these buffers may have been allocated * to an SKB, so we need to unmap and free potential storage */ if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, + rxq->pool[i].dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(rxq->pool[i].skb); rxq->pool[i].skb = NULL; } @@ -3774,7 +3775,8 @@ static int ipw_queue_tx_init(struct ipw_priv *priv, return -ENOMEM; q->bd = - pci_alloc_consistent(dev, sizeof(q->bd[0]) * count, &q->q.dma_addr); + dma_alloc_coherent(&dev->dev, sizeof(q->bd[0]) * count, + &q->q.dma_addr, GFP_KERNEL); if (!q->bd) { IPW_ERROR("pci_alloc_consistent(%zd) failed\n", sizeof(q->bd[0]) * count); @@ -3816,9 +3818,10 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, /* unmap chunks if any */ for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) { - pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]), + dma_unmap_single(&dev->dev, + le32_to_cpu(bd->u.data.chunk_ptr[i]), le16_to_cpu(bd->u.data.chunk_len[i]), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); if (txq->txb[txq->q.last_used]) { libipw_txb_free(txq->txb[txq->q.last_used]); txq->txb[txq->q.last_used] = NULL; @@ -3850,8 +3853,8 @@ static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq) } /* free buffers belonging to queue itself */ - pci_free_consistent(dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd, - q->dma_addr); + dma_free_coherent(&dev->dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd, + q->dma_addr); kfree(txq->txb); /* 0 fill whole structure */ @@ -5196,8 +5199,8 @@ static void ipw_rx_queue_replenish(void *data) list_del(element); rxb->dma_addr = - pci_map_single(priv->pci_dev, rxb->skb->data, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_map_single(&priv->pci_dev->dev, rxb->skb->data, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; @@ -5230,8 +5233,9 @@ static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq) for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].skb != NULL) { - pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, + rxq->pool[i].dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb(rxq->pool[i].skb); } } @@ -8263,9 +8267,8 @@ static void ipw_rx(struct ipw_priv *priv) } priv->rxq->queue[i] = NULL; - pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, - IPW_RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pci_dev->dev, rxb->dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); pkt = (struct ipw_rx_packet *)rxb->skb->data; IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n", @@ -8417,8 +8420,8 @@ static void ipw_rx(struct ipw_priv *priv) rxb->skb = NULL; } - pci_unmap_single(priv->pci_dev, rxb->dma_addr, - IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pci_dev->dev, rxb->dma_addr, + IPW_RX_BUF_SIZE, DMA_FROM_DEVICE); list_add_tail(&rxb->list, &priv->rxq->rx_used); i = (i + 1) % RX_QUEUE_SIZE; @@ -10217,11 +10220,10 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, txb->fragments[i]->len - hdr_len); tfd->u.data.chunk_ptr[i] = - cpu_to_le32(pci_map_single - (priv->pci_dev, - txb->fragments[i]->data + hdr_len, - txb->fragments[i]->len - hdr_len, - PCI_DMA_TODEVICE)); + cpu_to_le32(dma_map_single(&priv->pci_dev->dev, + txb->fragments[i]->data + hdr_len, + txb->fragments[i]->len - hdr_len, + DMA_TO_DEVICE)); tfd->u.data.chunk_len[i] = cpu_to_le16(txb->fragments[i]->len - hdr_len); } @@ -10251,10 +10253,10 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb, dev_kfree_skb_any(txb->fragments[i]); txb->fragments[i] = skb; tfd->u.data.chunk_ptr[i] = - cpu_to_le32(pci_map_single - (priv->pci_dev, skb->data, - remaining_bytes, - PCI_DMA_TODEVICE)); + cpu_to_le32(dma_map_single(&priv->pci_dev->dev, + skb->data, + remaining_bytes, + DMA_TO_DEVICE)); le32_add_cpu(&tfd->u.data.num_chunks, 1); } @@ -11620,9 +11622,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) { printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n"); goto out_pci_disable_device; @@ -11838,10 +11840,9 @@ static void ipw_pci_remove(struct pci_dev *pdev) free_firmware(); } -#ifdef CONFIG_PM -static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused ipw_pci_suspend(struct device *dev_d) { - struct ipw_priv *priv = pci_get_drvdata(pdev); + struct ipw_priv *priv = dev_get_drvdata(dev_d); struct net_device *dev = priv->net_dev; printk(KERN_INFO "%s: Going into suspend...\n", dev->name); @@ -11852,33 +11853,20 @@ static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state) /* Remove the PRESENT state of the device */ netif_device_detach(dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - priv->suspend_at = ktime_get_boottime_seconds(); return 0; } -static int ipw_pci_resume(struct pci_dev *pdev) +static int __maybe_unused ipw_pci_resume(struct device *dev_d) { + struct pci_dev *pdev = to_pci_dev(dev_d); struct ipw_priv *priv = pci_get_drvdata(pdev); struct net_device *dev = priv->net_dev; - int err; u32 val; printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); - pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - return err; - } - pci_restore_state(pdev); - /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries @@ -11900,7 +11888,6 @@ static int ipw_pci_resume(struct pci_dev *pdev) return 0; } -#endif static void ipw_pci_shutdown(struct pci_dev *pdev) { @@ -11912,16 +11899,15 @@ static void ipw_pci_shutdown(struct pci_dev *pdev) pci_disable_device(pdev); } +static SIMPLE_DEV_PM_OPS(ipw_pci_pm_ops, ipw_pci_suspend, ipw_pci_resume); + /* driver initialization stuff */ static struct pci_driver ipw_driver = { .name = DRV_NAME, .id_table = card_ids, .probe = ipw_pci_probe, .remove = ipw_pci_remove, -#ifdef CONFIG_PM - .suspend = ipw_pci_suspend, - .resume = ipw_pci_resume, -#endif + .driver.pm = &ipw_pci_pm_ops, .shutdown = ipw_pci_shutdown, }; diff --git a/drivers/net/wireless/intel/iwlegacy/3945.c b/drivers/net/wireless/intel/iwlegacy/3945.c index 2ac494f5ae22..fd63eba47ba2 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945.c +++ b/drivers/net/wireless/intel/iwlegacy/3945.c @@ -2100,7 +2100,7 @@ il3945_txpower_set_from_eeprom(struct il_priv *il) /* set tx power value for all OFDM rates */ for (rate_idx = 0; rate_idx < IL_OFDM_RATES; rate_idx++) { - s32 uninitialized_var(power_idx); + s32 power_idx; int rc; /* use channel group's clip-power table, diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index da6d4202611c..e73c223a7d28 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -1415,7 +1415,7 @@ il4965_hdl_c_stats(struct il_priv *il, struct il_rx_buf *rxb) /* * mac80211 queues, ACs, hardware queues, FIFOs. * - * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues + * Cf. https://wireless.wiki.kernel.org/en/developers/Documentation/mac80211/queues * * Mac80211 uses the following numbers, which we get as from it * by way of skb_get_queue_mapping(skb): @@ -2769,7 +2769,7 @@ il4965_hdl_tx(struct il_priv *il, struct il_rx_buf *rxb) struct ieee80211_tx_info *info; struct il4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->u.status); - int uninitialized_var(tid); + int tid; int sta_id; int freed; u8 *qc = NULL; diff --git a/drivers/net/wireless/intel/iwlegacy/4965-rs.c b/drivers/net/wireless/intel/iwlegacy/4965-rs.c index 0a02d8aca320..1f196665d21f 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c @@ -1749,7 +1749,7 @@ il4965_rs_rate_scale_perform(struct il_priv *il, struct sk_buff *skb, u8 done_search = 0; u16 high_low; s32 sr; - u8 tid = MAX_TID_COUNT; + u8 tid; struct il_tid_data *tid_data; D_RATE("rate scale calculate new rate for skb\n"); diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 348c17ce72f5..f78e062df572 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -4286,8 +4286,8 @@ il_apm_init(struct il_priv *il) * power savings, even without L1. */ if (il->cfg->set_l0s) { - pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &lctl); - if (lctl & PCI_EXP_LNKCTL_ASPM_L1) { + ret = pcie_capability_read_word(il->pci_dev, PCI_EXP_LNKCTL, &lctl); + if (!ret && (lctl & PCI_EXP_LNKCTL_ASPM_L1)) { /* L1-ASPM enabled; disable(!) L0S */ il_set_bit(il, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 36153fa5f96a..1085afbefba8 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -31,7 +31,7 @@ config IWLWIFI In order to use this driver, you will need a firmware image for it. You can obtain the microcode from: - <http://wireless.kernel.org/en/users/Drivers/iwlwifi>. + <https://wireless.wiki.kernel.org/en/users/Drivers/iwlwifi>. The firmware is typically installed in /lib/firmware. You can look in the hotplug script /etc/hotplug/firmware.agent to diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h index 0f4be4be181c..fdcc1292a92b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h @@ -1023,7 +1023,7 @@ struct iwl_wep_cmd { u8 global_key_type; u8 flags; u8 reserved; - struct iwl_wep_key key[0]; + struct iwl_wep_key key[]; } __packed; #define WEP_KEY_WEP_TYPE 1 @@ -1305,7 +1305,7 @@ struct iwl_tx_cmd { * length is 26 or 30 bytes, followed by payload data */ u8 payload[0]; - struct ieee80211_hdr hdr[0]; + struct ieee80211_hdr hdr[]; } __packed; /* @@ -2380,7 +2380,7 @@ struct iwl_scan_cmd { * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) * before requesting another scan. */ - u8 data[0]; + u8 data[]; } __packed; /* Can abort will notify by complete notification with abort status. */ @@ -2475,7 +2475,7 @@ struct iwl_tx_beacon_cmd { __le16 tim_idx; u8 tim_size; u8 reserved1; - struct ieee80211_hdr frame[0]; /* beacon frame */ + struct ieee80211_hdr frame[]; /* beacon frame */ } __packed; /****************************************************************************** @@ -3188,7 +3188,7 @@ struct iwl_calib_hdr { struct iwl_calib_cmd { struct iwl_calib_hdr hdr; - u8 data[0]; + u8 data[]; } __packed; struct iwl_calib_xtal_freq_cmd { @@ -3216,7 +3216,7 @@ struct iwl_calib_temperature_offset_v2_cmd { /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ struct iwl_calib_chain_noise_reset_cmd { struct iwl_calib_hdr hdr; - u8 data[0]; + u8 data[]; }; /* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 6512d25e3563..423d3c396b2d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -200,6 +200,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, iwl_leds_init(priv); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_EXT_KEY_ID); ret = ieee80211_register_hw(priv->hw); if (ret) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index fd719c37428c..b6c31f01ea9e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -361,7 +361,7 @@ struct iwl_mcc_update_resp_v3 { __le16 time; __le16 geo_info; __le32 n_channels; - __le32 channels[0]; + __le32 channels[]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** @@ -390,7 +390,7 @@ struct iwl_mcc_update_resp { u8 source_id; u8 reserved[3]; __le32 n_channels; - __le32 channels[0]; + __le32 channels[]; } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_4 */ /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index f1d1fe96fecc..82d59b5a5f8c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -293,7 +293,7 @@ struct iwl_tx_cmd { __le16 pm_frame_timeout; __le16 reserved4; u8 payload[0]; - struct ieee80211_hdr hdr[0]; + struct ieee80211_hdr hdr[]; } __packed; /* TX_CMD_API_S_VER_6 */ struct iwl_dram_sec_info { @@ -319,7 +319,7 @@ struct iwl_tx_cmd_gen2 { __le32 flags; struct iwl_dram_sec_info dram_info; __le32 rate_n_flags; - struct ieee80211_hdr hdr[0]; + struct ieee80211_hdr hdr[]; } __packed; /* TX_CMD_API_S_VER_7 */ /** @@ -342,7 +342,7 @@ struct iwl_tx_cmd_gen3 { struct iwl_dram_sec_info dram_info; __le32 rate_n_flags; __le64 ttl; - struct ieee80211_hdr hdr[0]; + struct ieee80211_hdr hdr[]; } __packed; /* TX_CMD_API_S_VER_8 */ /* @@ -766,8 +766,8 @@ struct iwl_mvm_compressed_ba_notif { __le32 tx_rate; __le16 tfd_cnt; __le16 ra_tid_cnt; - struct iwl_mvm_compressed_ba_tfd tfd[0]; struct iwl_mvm_compressed_ba_ratid ra_tid[0]; + struct iwl_mvm_compressed_ba_tfd tfd[]; } __packed; /* COMPRESSED_BA_RES_API_S_VER_4 */ /** @@ -784,7 +784,7 @@ struct iwl_mac_beacon_cmd_v6 { __le32 template_id; __le32 tim_idx; __le32 tim_size; - struct ieee80211_hdr frame[0]; + struct ieee80211_hdr frame[]; } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_6 */ /** @@ -805,7 +805,7 @@ struct iwl_mac_beacon_cmd_v7 { __le32 tim_size; __le32 ecsa_offset; __le32 csa_offset; - struct ieee80211_hdr frame[0]; + struct ieee80211_hdr frame[]; } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_7 */ enum iwl_mac_beacon_flags { @@ -840,7 +840,7 @@ struct iwl_mac_beacon_cmd { __le32 tim_size; __le32 ecsa_offset; __le32 csa_offset; - struct ieee80211_hdr frame[0]; + struct ieee80211_hdr frame[]; } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_10 */ struct iwl_beacon_notif { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 4d3687cc83a4..7ea55cfdd8a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2554,7 +2554,7 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) return -EINVAL; if (fwrt->dump.conf != FW_DBG_INVALID) - IWL_WARN(fwrt, "FW already configured (%d) - re-configuring\n", + IWL_INFO(fwrt, "FW already configured (%d) - re-configuring\n", fwrt->dump.conf); /* Send all HCMDs for configuring the FW debug */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index 6e72c27f527b..267ad4eddb5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -260,7 +260,7 @@ struct hcmd_write_data { __be32 cmd_id; __be32 flags; __be16 length; - u8 data[0]; + u8 data[]; } __packed; static ssize_t iwl_dbgfs_send_hcmd_write(struct iwl_fw_runtime *fwrt, char *buf, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 244899f3f3bf..e27c13263a23 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -641,6 +641,6 @@ extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0; extern const struct iwl_cfg iwlax411_2ax_cfg_so_gf4_a0_long; extern const struct iwl_cfg iwlax411_2ax_cfg_sosnj_gf4_a0; extern const struct iwl_cfg iwlax211_cfg_snj_gf_a0; -#endif /* CPTCFG_IWLMVM || CPTCFG_IWLFMAC */ +#endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 27116c7d3f4f..9ce7207d9ec5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -480,7 +480,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) if (!iwlwifi_mod_params.enable_ini) return; - res = request_firmware(&fw, "iwl-debug-yoyo.bin", dev); + res = firmware_request_nowarn(&fw, "iwl-debug-yoyo.bin", dev); if (res) return; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index 3008a5246be8..b35b8920941b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -175,7 +175,7 @@ void iwl_opmode_deregister(const char *name); struct iwl_op_mode { const struct iwl_op_mode_ops *ops; - char op_mode_specific[0] __aligned(sizeof(void *)); + char op_mode_specific[] __aligned(sizeof(void *)); }; static inline void iwl_op_mode_stop(struct iwl_op_mode *op_mode) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a301e2484cdb..34788e7afc7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1006,7 +1006,7 @@ struct iwl_trans { /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ - char trans_specific[0] __aligned(sizeof(void *)); + char trans_specific[] __aligned(sizeof(void *)); }; const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 77916231ff7d..9374c85c5caf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -543,6 +543,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + + /* The new Tx API does not allow to pass the key or keyid of a MPDU to + * the hw, preventing us to control which key(id) to use per MPDU. + * Till that's fixed we can't use Extended Key ID for the newer cards. + */ + if (!iwl_mvm_has_new_tx_api(mvm)) + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_EXT_KEY_ID); hw->wiphy->features |= NL80211_FEATURE_HT_IBSS; hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR; @@ -4903,7 +4911,7 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if (mvmsta->avg_energy) { - sinfo->signal_avg = mvmsta->avg_energy; + sinfo->signal_avg = -(s8)mvmsta->avg_energy; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index a7264b282d79..86b2ebb5d5fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -603,7 +603,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { - int ret = -EAGAIN; + int ret; IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 27977992fd7f..9e124755a3ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1367,14 +1367,6 @@ out_err: return ret; } -static inline u8 iwl_mvm_tid_to_ac_queue(int tid) -{ - if (tid == IWL_MAX_TID_COUNT) - return IEEE80211_AC_VO; /* MGMT */ - - return tid_to_mac80211_ac[tid]; -} - void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk) { struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig index 6a6ce9d4aeee..c52d9b535623 100644 --- a/drivers/net/wireless/intersil/Kconfig +++ b/drivers/net/wireless/intersil/Kconfig @@ -30,7 +30,7 @@ config PRISM54 For more information refer to the p54 wiki: - http://wireless.kernel.org/en/users/Drivers/p54 + http://wireless.wiki.kernel.org/en/users/Drivers/p54 Note: You need a motherboard with DMA support to use any of these cards diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index 2ab34cf74ecc..b6c497ce12e1 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -3366,8 +3366,8 @@ static void prism2_free_local_data(struct net_device *dev) } -#if (defined(PRISM2_PCI) && defined(CONFIG_PM)) || defined(PRISM2_PCCARD) -static void prism2_suspend(struct net_device *dev) +#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD) +static void __maybe_unused prism2_suspend(struct net_device *dev) { struct hostap_interface *iface; struct local_info *local; @@ -3385,7 +3385,7 @@ static void prism2_suspend(struct net_device *dev) /* Disable hardware and firmware */ prism2_hw_shutdown(dev, 0); } -#endif /* (PRISM2_PCI && CONFIG_PM) || PRISM2_PCCARD */ +#endif /* PRISM2_PCI || PRISM2_PCCARD */ /* These might at some point be compiled separately and used as separate diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c index 0c2aa880e32a..101887e6bd0f 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_pci.c +++ b/drivers/net/wireless/intersil/hostap/hostap_pci.c @@ -403,36 +403,23 @@ static void prism2_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); } - -#ifdef CONFIG_PM -static int prism2_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused prism2_pci_suspend(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); if (netif_running(dev)) { netif_stop_queue(dev); netif_device_detach(dev); } prism2_suspend(dev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); return 0; } -static int prism2_pci_resume(struct pci_dev *pdev) +static int __maybe_unused prism2_pci_resume(struct device *dev_d) { - struct net_device *dev = pci_get_drvdata(pdev); - int err; - - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - return err; - } - pci_restore_state(pdev); + struct net_device *dev = dev_get_drvdata(dev_d); + prism2_hw_config(dev, 0); if (netif_running(dev)) { netif_device_attach(dev); @@ -441,20 +428,19 @@ static int prism2_pci_resume(struct pci_dev *pdev) return 0; } -#endif /* CONFIG_PM */ - MODULE_DEVICE_TABLE(pci, prism2_pci_id_table); +static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops, + prism2_pci_suspend, + prism2_pci_resume); + static struct pci_driver prism2_pci_driver = { .name = "hostap_pci", .id_table = prism2_pci_id_table, .probe = prism2_pci_probe, .remove = prism2_pci_remove, -#ifdef CONFIG_PM - .suspend = prism2_pci_suspend, - .resume = prism2_pci_resume, -#endif /* CONFIG_PM */ + .driver.pm = &prism2_pci_pm_ops, }; module_pci_driver(prism2_pci_driver); diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig index c470ee23673f..f62730aa7be3 100644 --- a/drivers/net/wireless/intersil/orinoco/Kconfig +++ b/drivers/net/wireless/intersil/orinoco/Kconfig @@ -27,7 +27,7 @@ config HERMES You will also very likely also need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works : - <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> + <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html> config HERMES_PRISM bool "Support Prism 2/2.5 chipset" @@ -120,7 +120,7 @@ config PCMCIA_HERMES You will very likely need the Wireless Tools in order to configure your card and that /etc/pcmcia/wireless.opts works: - <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. + <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c index 048693b6c6c2..96a03d10a080 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c @@ -290,8 +290,7 @@ static struct pci_driver orinoco_nortel_driver = { .id_table = orinoco_nortel_id_table, .probe = orinoco_nortel_init_one, .remove = orinoco_nortel_remove_one, - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, + .driver.pm = &orinoco_pci_pm_ops, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c index 4938a2208a37..f3c86b07b1b9 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c @@ -230,8 +230,7 @@ static struct pci_driver orinoco_pci_driver = { .id_table = orinoco_pci_id_table, .probe = orinoco_pci_init_one, .remove = orinoco_pci_remove_one, - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, + .driver.pm = &orinoco_pci_pm_ops, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h index 43f5b9f5a0b0..d49d940864b4 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h +++ b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h @@ -18,51 +18,37 @@ struct orinoco_pci_card { void __iomem *attr_io; }; -#ifdef CONFIG_PM -static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused orinoco_pci_suspend(struct device *dev_d) { + struct pci_dev *pdev = to_pci_dev(dev_d); struct orinoco_private *priv = pci_get_drvdata(pdev); orinoco_down(priv); free_irq(pdev->irq, priv); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); return 0; } -static int orinoco_pci_resume(struct pci_dev *pdev) +static int __maybe_unused orinoco_pci_resume(struct device *dev_d) { + struct pci_dev *pdev = to_pci_dev(dev_d); struct orinoco_private *priv = pci_get_drvdata(pdev); struct net_device *dev = priv->ndev; int err; - pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - dev->name); - return err; - } - pci_restore_state(pdev); - err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, dev->name, priv); if (err) { printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n", dev->name); - pci_disable_device(pdev); return -EBUSY; } - err = orinoco_up(priv); - - return err; + return orinoco_up(priv); } -#else -#define orinoco_pci_suspend NULL -#define orinoco_pci_resume NULL -#endif + +static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops, + orinoco_pci_suspend, + orinoco_pci_resume); #endif /* _ORINOCO_PCI_H */ diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c index 221352027779..16dada94c774 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c @@ -336,8 +336,7 @@ static struct pci_driver orinoco_plx_driver = { .id_table = orinoco_plx_id_table, .probe = orinoco_plx_init_one, .remove = orinoco_plx_remove_one, - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, + .driver.pm = &orinoco_pci_pm_ops, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c index 20ce569b8a43..9a9d335611ac 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c @@ -213,8 +213,7 @@ static struct pci_driver orinoco_tmd_driver = { .id_table = orinoco_tmd_id_table, .probe = orinoco_tmd_init_one, .remove = orinoco_tmd_remove_one, - .suspend = orinoco_pci_suspend, - .resume = orinoco_pci_resume, + .driver.pm = &orinoco_pci_pm_ops, }; static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 651c676b5506..11fa38fedd87 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -158,7 +158,7 @@ MODULE_FIRMWARE("orinoco_ezusb_fw"); #define EZUSB_REQUEST_FW_TRANS 0xA0 -#define EZUSB_REQUEST_TRIGER 0xAA +#define EZUSB_REQUEST_TRIGGER 0xAA #define EZUSB_REQUEST_TRIG_AC 0xAC #define EZUSB_CPUCS_REG 0x7F92 @@ -1318,12 +1318,12 @@ static int ezusb_hard_reset(struct orinoco_private *priv) netdev_dbg(upriv->dev, "sending control message\n"); retval = usb_control_msg(upriv->udev, usb_sndctrlpipe(upriv->udev, 0), - EZUSB_REQUEST_TRIGER, + EZUSB_REQUEST_TRIGGER, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x0, 0x0, NULL, 0, DEF_TIMEOUT); if (retval < 0) { - err("EZUSB_REQUEST_TRIGER failed retval %d", retval); + err("EZUSB_REQUEST_TRIGGER failed retval %d", retval); return retval; } #if 0 diff --git a/drivers/net/wireless/intersil/p54/Kconfig b/drivers/net/wireless/intersil/p54/Kconfig index 024be5507daf..003c378ed131 100644 --- a/drivers/net/wireless/intersil/p54/Kconfig +++ b/drivers/net/wireless/intersil/p54/Kconfig @@ -10,7 +10,7 @@ config P54_COMMON also need to be enabled in order to support any devices. These devices require softmac firmware which can be found at - <http://wireless.kernel.org/en/users/Drivers/p54> + <http://wireless.wiki.kernel.org/en/users/Drivers/p54> If you choose to build a module, it'll be called p54common. @@ -22,7 +22,7 @@ config P54_USB This driver is for USB isl38xx based wireless cards. These devices require softmac firmware which can be found at - <http://wireless.kernel.org/en/users/Drivers/p54> + <http://wireless.wiki.kernel.org/en/users/Drivers/p54> If you choose to build a module, it'll be called p54usb. @@ -36,7 +36,7 @@ config P54_PCI supported by the fullmac driver/firmware. This driver requires softmac firmware which can be found at - <http://wireless.kernel.org/en/users/Drivers/p54> + <http://wireless.wiki.kernel.org/en/users/Drivers/p54> If you choose to build a module, it'll be called p54pci. diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c index a5afcc865196..bece14e4ff0d 100644 --- a/drivers/net/wireless/intersil/p54/fwio.c +++ b/drivers/net/wireless/intersil/p54/fwio.c @@ -132,7 +132,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) if (priv->fw_var < 0x500) wiphy_info(priv->hw->wiphy, "you are using an obsolete firmware. " - "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "visit http://wireless.wiki.kernel.org/en/users/Drivers/p54 " "and grab one for \"kernel >= 2.6.28\"!\n"); if (priv->fw_var >= 0x300) { diff --git a/drivers/net/wireless/intersil/p54/p54pci.c b/drivers/net/wireless/intersil/p54/p54pci.c index 80ad0b7eaef4..9d96c8b8409d 100644 --- a/drivers/net/wireless/intersil/p54/p54pci.c +++ b/drivers/net/wireless/intersil/p54/p54pci.c @@ -153,12 +153,12 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev, if (!skb) break; - mapping = pci_map_single(priv->pdev, + mapping = dma_map_single(&priv->pdev->dev, skb_tail_pointer(skb), priv->common.rx_mtu + 32, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); - if (pci_dma_mapping_error(priv->pdev, mapping)) { + if (dma_mapping_error(&priv->pdev->dev, mapping)) { dev_kfree_skb_any(skb); dev_err(&priv->pdev->dev, "RX DMA Mapping error\n"); @@ -215,19 +215,22 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, len = priv->common.rx_mtu; } dma_addr = le32_to_cpu(desc->host_addr); - pci_dma_sync_single_for_cpu(priv->pdev, dma_addr, - priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pdev->dev, dma_addr, + priv->common.rx_mtu + 32, + DMA_FROM_DEVICE); skb_put(skb, len); if (p54_rx(dev, skb)) { - pci_unmap_single(priv->pdev, dma_addr, - priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, dma_addr, + priv->common.rx_mtu + 32, + DMA_FROM_DEVICE); rx_buf[i] = NULL; desc->host_addr = cpu_to_le32(0); } else { skb_trim(skb, 0); - pci_dma_sync_single_for_device(priv->pdev, dma_addr, - priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE); + dma_sync_single_for_device(&priv->pdev->dev, dma_addr, + priv->common.rx_mtu + 32, + DMA_FROM_DEVICE); desc->len = cpu_to_le16(priv->common.rx_mtu + 32); } @@ -258,8 +261,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, skb = tx_buf[i]; tx_buf[i] = NULL; - pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), - le16_to_cpu(desc->len), PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, + le32_to_cpu(desc->host_addr), + le16_to_cpu(desc->len), DMA_TO_DEVICE); desc->host_addr = 0; desc->device_addr = 0; @@ -334,9 +338,9 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - mapping = pci_map_single(priv->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, mapping)) { + mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, mapping)) { spin_unlock_irqrestore(&priv->lock, flags); p54_free_skb(dev, skb); dev_err(&priv->pdev->dev, "TX DMA mapping error\n"); @@ -378,10 +382,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) { desc = &ring_control->rx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), priv->common.rx_mtu + 32, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); kfree_skb(priv->rx_buf_data[i]); priv->rx_buf_data[i] = NULL; } @@ -389,10 +393,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) { desc = &ring_control->rx_mgmt[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), priv->common.rx_mtu + 32, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); kfree_skb(priv->rx_buf_mgmt[i]); priv->rx_buf_mgmt[i] = NULL; } @@ -400,10 +404,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) { desc = &ring_control->tx_data[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), le16_to_cpu(desc->len), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); p54_free_skb(dev, priv->tx_buf_data[i]); priv->tx_buf_data[i] = NULL; @@ -412,10 +416,10 @@ static void p54p_stop(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) { desc = &ring_control->tx_mgmt[i]; if (desc->host_addr) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, le32_to_cpu(desc->host_addr), le16_to_cpu(desc->len), - PCI_DMA_TODEVICE); + DMA_TO_DEVICE); p54_free_skb(dev, priv->tx_buf_mgmt[i]); priv->tx_buf_mgmt[i] = NULL; @@ -568,9 +572,9 @@ static int p54p_probe(struct pci_dev *pdev, goto err_disable_dev; } - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); if (!err) - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&pdev->dev, "No suitable DMA available\n"); goto err_free_reg; @@ -603,8 +607,9 @@ static int p54p_probe(struct pci_dev *pdev, goto err_free_dev; } - priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control), - &priv->ring_control_dma); + priv->ring_control = dma_alloc_coherent(&pdev->dev, + sizeof(*priv->ring_control), + &priv->ring_control_dma, GFP_KERNEL); if (!priv->ring_control) { dev_err(&pdev->dev, "Cannot allocate rings\n"); err = -ENOMEM; @@ -623,8 +628,8 @@ static int p54p_probe(struct pci_dev *pdev, if (!err) return 0; - pci_free_consistent(pdev, sizeof(*priv->ring_control), - priv->ring_control, priv->ring_control_dma); + dma_free_coherent(&pdev->dev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); err_iounmap: iounmap(priv->map); @@ -653,8 +658,8 @@ static void p54p_remove(struct pci_dev *pdev) wait_for_completion(&priv->fw_loaded); p54_unregister_common(dev); release_firmware(priv->firmware); - pci_free_consistent(pdev, sizeof(*priv->ring_control), - priv->ring_control, priv->ring_control_dma); + dma_free_coherent(&pdev->dev, sizeof(*priv->ring_control), + priv->ring_control, priv->ring_control_dma); iounmap(priv->map); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c index ff0e30c0c14c..cae47663b17b 100644 --- a/drivers/net/wireless/intersil/p54/p54usb.c +++ b/drivers/net/wireless/intersil/p54/p54usb.c @@ -36,7 +36,7 @@ static struct usb_driver p54u_driver; * Note: * * Always update our wiki's device list (located at: - * http://wireless.kernel.org/en/users/Drivers/p54/devices ), + * http://wireless.wiki.kernel.org/en/users/Drivers/p54/devices ), * whenever you add a new device. */ diff --git a/drivers/net/wireless/intersil/prism54/isl_oid.h b/drivers/net/wireless/intersil/prism54/isl_oid.h index 1afc2ccf94ca..b889bb73a485 100644 --- a/drivers/net/wireless/intersil/prism54/isl_oid.h +++ b/drivers/net/wireless/intersil/prism54/isl_oid.h @@ -143,7 +143,7 @@ enum dot11_priv_t { * together with a CSMA contention. Without this all frames are * sent with a CSMA contention. * Bibliography: - * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html + * https://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html */ enum dot11_maxframeburst_t { /* Values for DOT11_OID_MAXFRAMEBURST */ diff --git a/drivers/net/wireless/intersil/prism54/islpci_dev.c b/drivers/net/wireless/intersil/prism54/islpci_dev.c index a9bae69222dc..efd64e555bb5 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_dev.c +++ b/drivers/net/wireless/intersil/prism54/islpci_dev.c @@ -636,10 +636,10 @@ islpci_alloc_memory(islpci_private *priv) */ /* perform the allocation */ - priv->driver_mem_address = pci_alloc_consistent(priv->pdev, - HOST_MEM_BLOCK, - &priv-> - device_host_address); + priv->driver_mem_address = dma_alloc_coherent(&priv->pdev->dev, + HOST_MEM_BLOCK, + &priv->device_host_address, + GFP_KERNEL); if (!priv->driver_mem_address) { /* error allocating the block of PCI memory */ @@ -692,11 +692,9 @@ islpci_alloc_memory(islpci_private *priv) /* map the allocated skb data area to pci */ priv->pci_map_rx_address[counter] = - pci_map_single(priv->pdev, (void *) skb->data, - MAX_FRAGMENT_SIZE_RX + 2, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, - priv->pci_map_rx_address[counter])) { + dma_map_single(&priv->pdev->dev, (void *)skb->data, + MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, priv->pci_map_rx_address[counter])) { priv->pci_map_rx_address[counter] = 0; /* error mapping the buffer to device accessible memory address */ @@ -727,9 +725,9 @@ islpci_free_memory(islpci_private *priv) /* free consistent DMA area... */ if (priv->driver_mem_address) - pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, - priv->driver_mem_address, - priv->device_host_address); + dma_free_coherent(&priv->pdev->dev, HOST_MEM_BLOCK, + priv->driver_mem_address, + priv->device_host_address); /* clear some dangling pointers */ priv->driver_mem_address = NULL; @@ -741,8 +739,8 @@ islpci_free_memory(islpci_private *priv) for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { struct islpci_membuf *buf = &priv->mgmt_rx[counter]; if (buf->pci_addr) - pci_unmap_single(priv->pdev, buf->pci_addr, - buf->size, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, buf->pci_addr, + buf->size, DMA_FROM_DEVICE); buf->pci_addr = 0; kfree(buf->mem); buf->size = 0; @@ -752,10 +750,10 @@ islpci_free_memory(islpci_private *priv) /* clean up data rx buffers */ for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { if (priv->pci_map_rx_address[counter]) - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, priv->pci_map_rx_address[counter], MAX_FRAGMENT_SIZE_RX + 2, - PCI_DMA_FROMDEVICE); + DMA_FROM_DEVICE); priv->pci_map_rx_address[counter] = 0; if (priv->data_low_rx[counter]) diff --git a/drivers/net/wireless/intersil/prism54/islpci_eth.c b/drivers/net/wireless/intersil/prism54/islpci_eth.c index 8d680250a281..74dd65716afd 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_eth.c +++ b/drivers/net/wireless/intersil/prism54/islpci_eth.c @@ -50,9 +50,9 @@ islpci_eth_cleanup_transmit(islpci_private *priv, skb, skb->data, skb->len, skb->truesize); #endif - pci_unmap_single(priv->pdev, + dma_unmap_single(&priv->pdev->dev, priv->pci_map_tx_address[index], - skb->len, PCI_DMA_TODEVICE); + skb->len, DMA_TO_DEVICE); dev_kfree_skb_irq(skb); skb = NULL; } @@ -176,10 +176,9 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) #endif /* map the skb buffer to pci memory for DMA operation */ - pci_map_address = pci_map_single(priv->pdev, - (void *) skb->data, skb->len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, pci_map_address)) { + pci_map_address = dma_map_single(&priv->pdev->dev, (void *)skb->data, + skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, pci_map_address)) { printk(KERN_WARNING "%s: cannot map buffer to PCI\n", ndev->name); goto drop_free; @@ -323,9 +322,8 @@ islpci_eth_receive(islpci_private *priv) #endif /* delete the streaming DMA mapping before processing the skb */ - pci_unmap_single(priv->pdev, - priv->pci_map_rx_address[index], - MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); + dma_unmap_single(&priv->pdev->dev, priv->pci_map_rx_address[index], + MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); /* update the skb structure and align the buffer */ skb_put(skb, size); @@ -431,11 +429,9 @@ islpci_eth_receive(islpci_private *priv) /* set the streaming DMA mapping for proper PCI bus operation */ priv->pci_map_rx_address[index] = - pci_map_single(priv->pdev, (void *) skb->data, - MAX_FRAGMENT_SIZE_RX + 2, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, - priv->pci_map_rx_address[index])) { + dma_map_single(&priv->pdev->dev, (void *)skb->data, + MAX_FRAGMENT_SIZE_RX + 2, DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, priv->pci_map_rx_address[index])) { /* error mapping the buffer to device accessible memory address */ DEBUG(SHOW_ERROR_MESSAGES, "Error mapping DMA address\n"); diff --git a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c index 20291c0d962d..31a1e61326ff 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/intersil/prism54/islpci_hotplug.c @@ -26,7 +26,8 @@ module_param(init_pcitm, int, 0); /* In this order: vendor, device, subvendor, subdevice, class, class_mask, * driver_data * If you have an update for this please contact prism54-devel@prism54.org - * The latest list can be found at http://wireless.kernel.org/en/users/Drivers/p54 */ + * The latest list can be found at http://wireless.wiki.kernel.org/en/users/Drivers/p54 + */ static const struct pci_device_id prism54_id_tbl[] = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ { @@ -63,16 +64,17 @@ MODULE_DEVICE_TABLE(pci, prism54_id_tbl); static int prism54_probe(struct pci_dev *, const struct pci_device_id *); static void prism54_remove(struct pci_dev *); -static int prism54_suspend(struct pci_dev *, pm_message_t state); -static int prism54_resume(struct pci_dev *); +static int __maybe_unused prism54_suspend(struct device *); +static int __maybe_unused prism54_resume(struct device *); + +static SIMPLE_DEV_PM_OPS(prism54_pm_ops, prism54_suspend, prism54_resume); static struct pci_driver prism54_driver = { .name = DRV_NAME, .id_table = prism54_id_tbl, .probe = prism54_probe, .remove = prism54_remove, - .suspend = prism54_suspend, - .resume = prism54_resume, + .driver.pm = &prism54_pm_ops, }; /****************************************************************************** @@ -106,7 +108,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* enable PCI DMA */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); goto do_pci_disable_device; } @@ -243,16 +245,13 @@ prism54_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static int -prism54_suspend(struct pci_dev *pdev, pm_message_t state) +static int __maybe_unused +prism54_suspend(struct device *dev) { - struct net_device *ndev = pci_get_drvdata(pdev); + struct net_device *ndev = dev_get_drvdata(dev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; BUG_ON(!priv); - - pci_save_state(pdev); - /* tell the device not to trigger interrupts for now... */ isl38xx_disable_interrupts(priv->device_base); @@ -266,26 +265,16 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int -prism54_resume(struct pci_dev *pdev) +static int __maybe_unused +prism54_resume(struct device *dev) { - struct net_device *ndev = pci_get_drvdata(pdev); + struct net_device *ndev = dev_get_drvdata(dev); islpci_private *priv = ndev ? netdev_priv(ndev) : NULL; - int err; BUG_ON(!priv); printk(KERN_NOTICE "%s: got resume request\n", ndev->name); - err = pci_enable_device(pdev); - if (err) { - printk(KERN_ERR "%s: pci_enable_device failed on resume\n", - ndev->name); - return err; - } - - pci_restore_state(pdev); - /* alright let's go into the PREBOOT state */ islpci_reset(priv, 1); diff --git a/drivers/net/wireless/intersil/prism54/islpci_mgt.c b/drivers/net/wireless/intersil/prism54/islpci_mgt.c index e336eb106429..0c7fb76c7d1c 100644 --- a/drivers/net/wireless/intersil/prism54/islpci_mgt.c +++ b/drivers/net/wireless/intersil/prism54/islpci_mgt.c @@ -115,10 +115,11 @@ islpci_mgmt_rx_fill(struct net_device *ndev) buf->size = MGMT_FRAME_SIZE; } if (buf->pci_addr == 0) { - buf->pci_addr = pci_map_single(priv->pdev, buf->mem, + buf->pci_addr = dma_map_single(&priv->pdev->dev, + buf->mem, MGMT_FRAME_SIZE, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(priv->pdev, buf->pci_addr)) { + DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, buf->pci_addr)) { printk(KERN_WARNING "Failed to make memory DMA'able.\n"); return -ENOMEM; @@ -203,9 +204,9 @@ islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, #endif err = -ENOMEM; - buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(priv->pdev, buf.pci_addr)) { + buf.pci_addr = dma_map_single(&priv->pdev->dev, buf.mem, frag_len, + DMA_TO_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, buf.pci_addr)) { printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", ndev->name); goto error_free; @@ -302,8 +303,8 @@ islpci_mgt_receive(struct net_device *ndev) } /* Ensure the results of device DMA are visible to the CPU. */ - pci_dma_sync_single_for_cpu(priv->pdev, buf->pci_addr, - buf->size, PCI_DMA_FROMDEVICE); + dma_sync_single_for_cpu(&priv->pdev->dev, buf->pci_addr, + buf->size, DMA_FROM_DEVICE); /* Perform endianess conversion for PIMFOR header in-place. */ header = pimfor_decode_header(buf->mem, frag_len); @@ -414,8 +415,8 @@ islpci_mgt_cleanup_transmit(struct net_device *ndev) for (; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; struct islpci_membuf *buf = &priv->mgmt_tx[index]; - pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, - PCI_DMA_TODEVICE); + dma_unmap_single(&priv->pdev->dev, buf->pci_addr, buf->size, + DMA_TO_DEVICE); buf->pci_addr = 0; kfree(buf->mem); buf->mem = NULL; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1356e8cbe617..9dd9d73f4484 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -4334,7 +4334,7 @@ static int __init init_mac80211_hwsim(void) break; case HWSIM_REGTEST_STRICT_ALL: param.reg_strict = true; - /* fall through */ + fallthrough; case HWSIM_REGTEST_DRIVER_REG_ALL: param.reg_alpha2 = hwsim_alpha2s[0]; break; diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 0bdafe9f66db..1046b59647f5 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -398,7 +398,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *), GFP_KERNEL); if (!new_node->rx_reorder_ptr) { - kfree((u8 *) new_node); + kfree(new_node); mwifiex_dbg(priv->adapter, ERROR, "%s: failed to alloc reorder_ptr\n", __func__); return; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 4e4f59c17ded..96848fa0e417 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -27,7 +27,8 @@ module_param(reg_alpha2, charp, 0); static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { { - .max = 3, .types = BIT(NL80211_IFTYPE_STATION) | + .max = MWIFIEX_MAX_BSS_NUM, + .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_AP), @@ -3726,11 +3727,11 @@ mwifiex_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, int ret; if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) - return -ENOTSUPP; + return -EOPNOTSUPP; /* make sure we are in station mode and connected */ if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) - return -ENOTSUPP; + return -EOPNOTSUPP; switch (action_code) { case WLAN_TDLS_SETUP_REQUEST: @@ -3798,11 +3799,11 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) || !(wiphy->flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP)) - return -ENOTSUPP; + return -EOPNOTSUPP; /* make sure we are in station mode and connected */ if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) - return -ENOTSUPP; + return -EOPNOTSUPP; mwifiex_dbg(priv->adapter, MSG, "TDLS peer=%pM, oper=%d\n", peer, action); @@ -3832,7 +3833,7 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, default: mwifiex_dbg(priv->adapter, ERROR, "tdls_oper: operation not supported\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } return mwifiex_tdls_oper(priv, peer, action); @@ -3913,11 +3914,11 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) - return -ENOTSUPP; + return -EOPNOTSUPP; /* make sure we are in station mode and connected */ if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected) - return -ENOTSUPP; + return -EOPNOTSUPP; return mwifiex_tdls_oper(priv, mac, MWIFIEX_TDLS_CREATE_LINK); } @@ -4150,11 +4151,11 @@ mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev, /* we support change_station handler only for TDLS peers*/ if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) - return -ENOTSUPP; + return -EOPNOTSUPP; /* make sure we are in station mode and connected */ if ((priv->bss_type != MWIFIEX_BSS_TYPE_STA) || !priv->media_connected) - return -ENOTSUPP; + return -EOPNOTSUPP; priv->sta_params = params; diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 529099137644..9ee5600351a7 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -953,7 +953,7 @@ int mwifiex_set_mac_address(struct mwifiex_private *priv, } else { /* Internal mac address change */ if (priv->bss_type == MWIFIEX_BSS_TYPE_ANY) - return -ENOTSUPP; + return -EOPNOTSUPP; mac_addr = old_mac_addr; diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.h b/drivers/net/wireless/marvell/mwifiex/sdio.h index 71cd8629b28e..8b476b007c5e 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.h +++ b/drivers/net/wireless/marvell/mwifiex/sdio.h @@ -36,9 +36,9 @@ #define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin" #define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin" #define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin" -#define SD8977_DEFAULT_FW_NAME "mrvl/sd8977_uapsta.bin" +#define SD8977_DEFAULT_FW_NAME "mrvl/sdsd8977_combo_v2.bin" #define SD8987_DEFAULT_FW_NAME "mrvl/sd8987_uapsta.bin" -#define SD8997_DEFAULT_FW_NAME "mrvl/sd8997_uapsta.bin" +#define SD8997_DEFAULT_FW_NAME "mrvl/sdsd8997_combo_v4.bin" #define BLOCK_MODE 1 #define BYTE_MODE 0 diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 8bd355d7974e..d3a968ef21ef 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1723,7 +1723,7 @@ mwifiex_cmd_tdls_config(struct mwifiex_private *priv, default: mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS configuration\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } le16_unaligned_add_cpu(&cmd->size, len); @@ -1849,7 +1849,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, break; default: mwifiex_dbg(priv->adapter, ERROR, "Unknown TDLS operation\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } le16_unaligned_add_cpu(&cmd->size, config_len); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index f21660149f58..962d8bfe6f10 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -580,6 +580,11 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, { struct host_cmd_ds_802_11_key_material *key = &resp->params.key_material; + int len; + + len = le16_to_cpu(key->key_param_set.key_len); + if (len > sizeof(key->key_param_set.key)) + return -EINVAL; if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) { if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) { @@ -593,9 +598,8 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, memset(priv->aes_key.key_param_set.key, 0, sizeof(key->key_param_set.key)); - priv->aes_key.key_param_set.key_len = key->key_param_set.key_len; - memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, - le16_to_cpu(priv->aes_key.key_param_set.key_len)); + priv->aes_key.key_param_set.key_len = cpu_to_le16(len); + memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key, len); return 0; } @@ -610,9 +614,14 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, struct host_cmd_ds_command *resp) { struct host_cmd_ds_802_11_key_material_v2 *key_v2; - __le16 len; + int len; key_v2 = &resp->params.key_material_v2; + + len = le16_to_cpu(key_v2->key_param_set.key_params.aes.key_len); + if (len > WLAN_KEY_LEN_CCMP) + return -EINVAL; + if (le16_to_cpu(key_v2->action) == HostCmd_ACT_GEN_SET) { if ((le16_to_cpu(key_v2->key_param_set.key_info) & KEY_MCAST)) { mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n"); @@ -628,10 +637,9 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, memset(priv->aes_key_v2.key_param_set.key_params.aes.key, 0, WLAN_KEY_LEN_CCMP); priv->aes_key_v2.key_param_set.key_params.aes.key_len = - key_v2->key_param_set.key_params.aes.key_len; - len = priv->aes_key_v2.key_param_set.key_params.aes.key_len; + cpu_to_le16(len); memcpy(priv->aes_key_v2.key_param_set.key_params.aes.key, - key_v2->key_param_set.key_params.aes.key, le16_to_cpu(len)); + key_v2->key_param_set.key_params.aes.key, len); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 41533a0e1720..31015d2a8e7d 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -12,6 +12,10 @@ config MT76_USB tristate depends on MT76_CORE +config MT76_SDIO + tristate + depends on MT76_CORE + config MT76x02_LIB tristate select MT76_CORE diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index ef663b873b0b..e53584db0756 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MT76_CORE) += mt76.o obj-$(CONFIG_MT76_USB) += mt76-usb.o +obj-$(CONFIG_MT76_SDIO) += mt76-sdio.o obj-$(CONFIG_MT76x02_LIB) += mt76x02-lib.o obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o @@ -9,8 +10,10 @@ mt76-y := \ tx.o agg-rx.o mcu.o mt76-$(CONFIG_PCI) += pci.o +mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o mt76-usb-y := usb.o usb_trace.o +mt76-sdio-y := sdio.o CFLAGS_trace.o := -I$(src) CFLAGS_usb_trace.o := -I$(src) diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index 3a5de1d1b121..5d58b16bfe9f 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -9,7 +9,7 @@ mt76_reg_set(void *data, u64 val) { struct mt76_dev *dev = data; - dev->bus->wr(dev, dev->debugfs_reg, val); + __mt76_wr(dev, dev->debugfs_reg, val); return 0; } @@ -18,7 +18,7 @@ mt76_reg_get(void *data, u64 *val) { struct mt76_dev *dev = data; - *val = dev->bus->rr(dev, dev->debugfs_reg); + *val = __mt76_rr(dev, dev->debugfs_reg); return 0; } @@ -54,9 +54,6 @@ static int mt76_rx_queues_read(struct seq_file *s, void *data) mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - queued = mt76_is_usb(dev) ? q->ndesc - q->queued : q->queued; seq_printf(s, "%d: queued=%d head=%d tail=%d\n", i, queued, q->head, q->tail); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f4d6074fe32a..6c25859dd386 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -370,6 +370,12 @@ unmap: tx_info.buf[n].len, DMA_TO_DEVICE); free: +#ifdef CONFIG_NL80211_TESTMODE + /* fix tx_done accounting on queue overflow */ + if (tx_info.skb == dev->test.tx_skb) + dev->test.tx_done--; +#endif + e.skb = tx_info.skb; e.txwi = t; dev->drv->tx_complete_skb(dev, qid, &e); diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index c236e303ccfd..3044e0069991 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -74,6 +74,11 @@ mt76_get_of_eeprom(struct mt76_dev *dev, int len) &data[i]); } +#ifdef CONFIG_NL80211_TESTMODE + dev->test.mtd_name = devm_kstrdup(dev->dev, part, GFP_KERNEL); + dev->test.mtd_offset = offset; +#endif + out_put_node: of_node_put(np); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 907098101898..3d4bf72700a5 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -58,12 +58,15 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { CHAN5G(132, 5660), CHAN5G(136, 5680), CHAN5G(140, 5700), + CHAN5G(144, 5720), CHAN5G(149, 5745), CHAN5G(153, 5765), CHAN5G(157, 5785), CHAN5G(161, 5805), CHAN5G(165, 5825), + CHAN5G(169, 5845), + CHAN5G(173, 5865), }; static const struct ieee80211_tpt_blink mt76_tpt_blink[] = { @@ -279,7 +282,8 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | - WIPHY_FLAG_SUPPORTS_TDLS; + WIPHY_FLAG_SUPPORTS_TDLS | + WIPHY_FLAG_AP_UAPSD; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); @@ -289,6 +293,7 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) wiphy->available_antennas_rx = dev->phy.antenna_mask; hw->txq_data_size = sizeof(struct mt76_txq); + hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; if (!hw->max_tx_fragments) hw->max_tx_fragments = 16; @@ -300,7 +305,11 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, TX_AMSDU); - ieee80211_hw_set(hw, TX_FRAG_LIST); + + /* TODO: avoid linearization for SDIO */ + if (!mt76_is_sdio(dev)) + ieee80211_hw_set(hw, TX_FRAG_LIST); + ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); @@ -432,6 +441,12 @@ mt76_alloc_device(struct device *pdev, unsigned int size, tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev); + dev->wq = alloc_ordered_workqueue("mt76", 0); + if (!dev->wq) { + ieee80211_free_hw(hw); + return NULL; + } + return dev; } EXPORT_SYMBOL_GPL(mt76_alloc_device); @@ -485,7 +500,12 @@ EXPORT_SYMBOL_GPL(mt76_unregister_device); void mt76_free_device(struct mt76_dev *dev) { - mt76_tx_free(dev); + if (dev->wq) { + destroy_workqueue(dev->wq); + dev->wq = NULL; + } + if (mt76_is_mmio(dev)) + mt76_tx_free(dev); ieee80211_free_hw(dev->hw); } EXPORT_SYMBOL_GPL(mt76_free_device); @@ -500,6 +520,13 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) return; } +#ifdef CONFIG_NL80211_TESTMODE + if (dev->test.state == MT76_TM_STATE_RX_FRAMES) { + dev->test.rx_stats.packets[q]++; + if (status->flag & RX_FLAG_FAILED_FCS_CRC) + dev->test.rx_stats.fcs_error[q]++; + } +#endif __skb_queue_tail(&dev->rx_skb[q], skb); } EXPORT_SYMBOL_GPL(mt76_rx); @@ -537,8 +564,7 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c) return &msband->chan[idx]; } -static void -mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) +void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) { struct mt76_channel_state *state = phy->chan_state; @@ -546,6 +572,7 @@ mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time) phy->survey_time)); phy->survey_time = time; } +EXPORT_SYMBOL_GPL(mt76_update_survey_active_time); void mt76_update_survey(struct mt76_dev *dev) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3d7db6ffb599..af35bc388ae2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -15,6 +15,7 @@ #include <linux/average.h> #include <net/mac80211.h> #include "util.h" +#include "testmode.h" #define MT_TX_RING_SIZE 256 #define MT_MCU_RING_SIZE 32 @@ -33,6 +34,7 @@ struct mt76_reg_pair { enum mt76_bus_type { MT76_BUS_MMIO, MT76_BUS_USB, + MT76_BUS_SDIO, }; struct mt76_bus_ops { @@ -52,6 +54,7 @@ struct mt76_bus_ops { #define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB) #define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO) +#define mt76_is_sdio(dev) ((dev)->bus->type == MT76_BUS_SDIO) enum mt76_txq_id { MT_TXQ_VO = IEEE80211_AC_VO, @@ -94,6 +97,7 @@ struct mt76_queue_entry { union { struct mt76_txwi_cache *txwi; struct urb *urb; + int buf_sz; }; enum mt76_txq_id qid; bool skip_buf0:1; @@ -146,6 +150,8 @@ struct mt76_mcu_ops { int len, bool wait_resp); int (*mcu_skb_send_msg)(struct mt76_dev *dev, struct sk_buff *skb, int cmd, bool wait_resp); + u32 (*mcu_rr)(struct mt76_dev *dev, u32 offset); + void (*mcu_wr)(struct mt76_dev *dev, u32 offset, u32 val); int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *rp, int len); int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base, @@ -290,6 +296,7 @@ enum { MT76_STATE_POWER_OFF, MT76_STATE_SUSPEND, MT76_STATE_ROC, + MT76_STATE_PM, }; struct mt76_hw_cap { @@ -422,7 +429,6 @@ struct mt76_usb { u16 data_len; struct tasklet_struct rx_tasklet; - struct workqueue_struct *wq; struct work_struct stat_work; u8 out_ep[__MT_EP_OUT_MAX]; @@ -439,6 +445,24 @@ struct mt76_usb { } mcu; }; +struct mt76_sdio { + struct task_struct *tx_kthread; + struct task_struct *kthread; + struct work_struct stat_work; + + unsigned long state; + + struct sdio_func *func; + + struct { + struct mutex lock; + int pse_data_quota; + int ple_data_quota; + int pse_mcu_quota; + int deficit; + } sched; +}; + struct mt76_mmio { void __iomem *regs; spinlock_t irq_lock; @@ -475,6 +499,47 @@ struct mt76_rx_status { s8 chain_signal[IEEE80211_MAX_CHAINS]; }; +struct mt76_testmode_ops { + int (*set_state)(struct mt76_dev *dev, enum mt76_testmode_state state); + int (*set_params)(struct mt76_dev *dev, struct nlattr **tb, + enum mt76_testmode_state new_state); + int (*dump_stats)(struct mt76_dev *dev, struct sk_buff *msg); +}; + +struct mt76_testmode_data { + enum mt76_testmode_state state; + + u32 param_set[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)]; + struct sk_buff *tx_skb; + + u32 tx_count; + u16 tx_msdu_len; + + u8 tx_rate_mode; + u8 tx_rate_idx; + u8 tx_rate_nss; + u8 tx_rate_sgi; + u8 tx_rate_ldpc; + + u8 tx_antenna_mask; + + u32 freq_offset; + + u8 tx_power[4]; + u8 tx_power_control; + + const char *mtd_name; + u32 mtd_offset; + + u32 tx_pending; + u32 tx_queued; + u32 tx_done; + struct { + u64 packets[__MT_RXQ_MAX]; + u64 fcs_error[__MT_RXQ_MAX]; + } rx_stats; +}; + struct mt76_phy { struct ieee80211_hw *hw; struct mt76_dev *dev; @@ -491,6 +556,8 @@ struct mt76_phy { struct mt76_sband sband_2g; struct mt76_sband sband_5g; + u32 vif_mask; + int txpower_cur; u8 antenna_mask; }; @@ -572,9 +639,17 @@ struct mt76_dev { u32 rxfilter; +#ifdef CONFIG_NL80211_TESTMODE + const struct mt76_testmode_ops *test_ops; + struct mt76_testmode_data test; +#endif + + struct workqueue_struct *wq; + union { struct mt76_mmio mmio; struct mt76_usb usb; + struct mt76_sdio sdio; }; }; @@ -805,6 +880,15 @@ static inline u8 mt76_tx_power_nss_delta(u8 nss) return nss_delta[nss - 1]; } +static inline bool mt76_testmode_enabled(struct mt76_dev *dev) +{ +#ifdef CONFIG_NL80211_TESTMODE + return dev->test.state != MT76_TM_STATE_OFF; +#else + return false; +#endif +} + void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb); void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb); @@ -824,6 +908,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, bool mt76_has_tx_pending(struct mt76_phy *phy); void mt76_set_channel(struct mt76_phy *phy); void mt76_update_survey(struct mt76_dev *dev); +void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void mt76_set_stream_caps(struct mt76_phy *phy, bool vht); @@ -877,6 +962,24 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac); void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len); +int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, + struct netlink_callback *cb, void *data, int len); +int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state); + +static inline void mt76_testmode_reset(struct mt76_dev *dev, bool disable) +{ +#ifdef CONFIG_NL80211_TESTMODE + enum mt76_testmode_state state = MT76_TM_STATE_IDLE; + + if (disable || dev->test.state == MT76_TM_STATE_OFF) + state = MT76_TM_STATE_OFF; + + mt76_testmode_set_state(dev, state); +#endif +} + /* internal */ static inline struct ieee80211_hw * @@ -901,6 +1004,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, struct napi_struct *napi); void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames); +void mt76_testmode_tx_pending(struct mt76_dev *dev); /* usb */ static inline bool mt76u_urb_error(struct urb *urb) @@ -935,13 +1039,12 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout); } -int mt76u_skb_dma_info(struct sk_buff *skb, u32 info); +int mt76_skb_adjust_pad(struct sk_buff *skb); int mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len); void mt76u_single_wr(struct mt76_dev *dev, const u8 req, const u16 offset, const u32 val); -void mt76u_deinit(struct mt76_dev *dev); int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, bool ext); int mt76u_alloc_mcu_queue(struct mt76_dev *dev); @@ -951,6 +1054,12 @@ void mt76u_stop_rx(struct mt76_dev *dev); int mt76u_resume_rx(struct mt76_dev *dev); void mt76u_queues_deinit(struct mt76_dev *dev); +int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, + const struct mt76_bus_ops *bus_ops); +int mt76s_alloc_queues(struct mt76_dev *dev); +void mt76s_stop_txrx(struct mt76_dev *dev); +void mt76s_deinit(struct mt76_dev *dev); + struct sk_buff * mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data, int data_len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 83dfa6da4761..447f2c63ef38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -44,7 +44,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) mutex_lock(&dev->mt76.mutex); - mvif->idx = ffs(~dev->vif_mask) - 1; + mvif->idx = ffs(~dev->mphy.vif_mask) - 1; if (mvif->idx >= MT7603_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -65,7 +65,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; - dev->vif_mask |= BIT(mvif->idx); + dev->mphy.vif_mask |= BIT(mvif->idx); INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -107,7 +107,7 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) spin_unlock_bh(&dev->sta_poll_lock); mutex_lock(&dev->mt76.mutex); - dev->vif_mask &= ~BIT(mvif->idx); + dev->mphy.vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 7fadf094e9be..c86305241e66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -108,8 +108,6 @@ struct mt7603_dev { u32 rxfilter; - u8 vif_mask; - struct list_head sta_poll_list; spinlock_t sta_poll_lock; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index e25db1135eda..f372fb629caf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -28,13 +28,28 @@ config MT7622_WMAC which has the same feature set as a MT7615, but limited to 2.4 GHz only. +config MT7663_USB_SDIO_COMMON + tristate + select MT7615_COMMON + config MT7663U tristate "MediaTek MT7663U (USB) support" select MT76_USB - select MT7615_COMMON + select MT7663_USB_SDIO_COMMON depends on MAC80211 depends on USB help - This adds support for MT7663U 802.11ax 2x2:2 wireless devices. + This adds support for MT7663U 802.11ac 2x2:2 wireless devices. + + To compile this driver as a module, choose M here. + +config MT7663S + tristate "MediaTek MT7663S (SDIO) support" + select MT76_SDIO + select MT7663_USB_SDIO_COMMON + depends on MAC80211 + depends on MMC + help + This adds support for MT7663S 802.11ac 2x2:2 wireless devices. To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index 99f353b8b9aa..e8fc4a7ae9bc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -2,14 +2,19 @@ obj-$(CONFIG_MT7615_COMMON) += mt7615-common.o obj-$(CONFIG_MT7615E) += mt7615e.o +obj-$(CONFIG_MT7663_USB_SDIO_COMMON) += mt7663-usb-sdio-common.o obj-$(CONFIG_MT7663U) += mt7663u.o +obj-$(CONFIG_MT7663S) += mt7663s.o CFLAGS_trace.o := -I$(src) mt7615-common-y := main.o init.o mcu.o eeprom.o mac.o \ debugfs.o trace.o +mt7615-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7615e-y := pci.o pci_init.o dma.o pci_mac.o mmio.o mt7615e-$(CONFIG_MT7622_WMAC) += soc.o -mt7663u-y := usb.o usb_mcu.o usb_init.o +mt7663-usb-sdio-common-y := usb_sdio.o +mt7663u-y := usb.o usb_mcu.o +mt7663s-y := sdio.o sdio_mcu.o sdio_txrx.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index d06afcf46d67..88931658a9fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -6,11 +6,16 @@ static int mt7615_radar_pattern_set(void *data, u64 val) { struct mt7615_dev *dev = data; + int err; if (!mt7615_wait_for_mcu_init(dev)) return 0; - return mt7615_mcu_rdd_send_pattern(dev); + mt7615_mutex_acquire(dev); + err = mt7615_mcu_rdd_send_pattern(dev); + mt7615_mutex_release(dev); + + return err; } DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_pattern, NULL, @@ -47,6 +52,52 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get, mt7615_scs_set, "%lld\n"); static int +mt7615_pm_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + if (!mt7615_wait_for_mcu_init(dev)) + return 0; + + return mt7615_pm_set_enable(dev, val); +} + +static int +mt7615_pm_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = dev->pm.enable; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7615_pm_get, mt7615_pm_set, "%lld\n"); + +static int +mt7615_pm_idle_timeout_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + dev->pm.idle_timeout = msecs_to_jiffies(val); + + return 0; +} + +static int +mt7615_pm_idle_timeout_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = jiffies_to_msecs(dev->pm.idle_timeout); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7615_pm_idle_timeout_get, + mt7615_pm_idle_timeout_set, "%lld\n"); + +static int mt7615_dbdc_set(void *data, u64 val) { struct mt7615_dev *dev = data; @@ -84,7 +135,10 @@ mt7615_fw_debug_set(void *data, u64 val) return 0; dev->fw_debug = val; + + mt7615_mutex_acquire(dev); mt7615_mcu_fw_log_2_host(dev, dev->fw_debug ? 2 : 0); + mt7615_mutex_release(dev); return 0; } @@ -111,6 +165,8 @@ mt7615_reset_test_set(void *data, u64 val) if (!mt7615_wait_for_mcu_init(dev)) return 0; + mt7615_mutex_acquire(dev); + skb = alloc_skb(1, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -118,6 +174,8 @@ mt7615_reset_test_set(void *data, u64 val) skb_put(skb, 1); mt76_tx_queue_skb_raw(dev, 0, skb, 0); + mt7615_mutex_release(dev); + return 0; } @@ -167,9 +225,13 @@ mt7615_ampdu_stat_read(struct seq_file *file, void *data) { struct mt7615_dev *dev = file->private; + mt7615_mutex_acquire(dev); + mt7615_ampdu_stat_read_phy(&dev->phy, file); mt7615_ampdu_stat_read_phy(mt7615_ext_phy(dev), file); + mt7615_mutex_release(dev); + return 0; } @@ -221,7 +283,10 @@ static int mt7615_read_temperature(struct seq_file *s, void *data) return 0; /* cpu */ + mt7615_mutex_acquire(dev); temp = mt7615_mcu_get_temperature(dev, 0); + mt7615_mutex_release(dev); + seq_printf(s, "Temperature: %d\n", temp); return 0; @@ -233,6 +298,8 @@ mt7615_queues_acq(struct seq_file *s, void *data) struct mt7615_dev *dev = dev_get_drvdata(s->private); int i; + mt7615_mutex_acquire(dev); + for (i = 0; i < 16; i++) { int j, wmm_idx = i % MT7615_MAX_WMM_SETS; int acs = i / MT7615_MAX_WMM_SETS; @@ -253,6 +320,8 @@ mt7615_queues_acq(struct seq_file *s, void *data) seq_printf(s, "AC%d%d: queued=%d\n", wmm_idx, acs, qlen); } + mt7615_mutex_release(dev); + return 0; } @@ -285,6 +354,29 @@ mt7615_queues_read(struct seq_file *s, void *data) return 0; } +static int +mt7615_rf_reg_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + mt7615_rf_wr(dev, dev->debugfs_rf_wf, dev->debugfs_rf_reg, val); + + return 0; +} + +static int +mt7615_rf_reg_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = mt7615_rf_rr(dev, dev->debugfs_rf_wf, dev->debugfs_rf_reg); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_reg, mt7615_rf_reg_get, mt7615_rf_reg_set, + "0x%08llx\n"); + int mt7615_init_debugfs(struct mt7615_dev *dev) { struct dentry *dir; @@ -305,6 +397,9 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_file("scs", 0600, dir, dev, &fops_scs); debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc); debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug); + debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm); + debugfs_create_file("idle-timeout", 0600, dir, dev, + &fops_pm_idle_timeout); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); @@ -324,6 +419,11 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, mt7615_read_temperature); + debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf); + debugfs_create_u32("rf_regidx", 0600, dir, &dev->debugfs_rf_reg); + debugfs_create_file_unsafe("rf_regval", 0600, dir, dev, + &fops_rf_reg); + return 0; } EXPORT_SYMBOL_GPL(mt7615_init_debugfs); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index e5a965df899a..1231a5ddf9ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -122,10 +122,6 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) mt7615_tx_cleanup(dev); - rcu_read_lock(); - mt7615_mac_sta_poll(dev); - rcu_read_unlock(); - tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index e2d80518e5af..fc1ebabfebac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -285,7 +285,9 @@ mt7615_regd_notifier(struct wiphy *wiphy, if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) return; + mt7615_mutex_acquire(dev); mt7615_dfs_init_radar_detector(phy); + mt7615_mutex_release(dev); } static void @@ -321,6 +323,7 @@ mt7615_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); + ieee80211_hw_set(hw, WANT_MONITOR_VIF); if (is_mt7615(&phy->dev->mt76)) hw->max_tx_fragments = MT_TXP_MAX_BUF_NUM; @@ -405,9 +408,6 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) mphy->sband_2g.sband.n_channels = 0; mphy->hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL; - /* The second interface does not get any packets unless it has a vif */ - ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF); - ret = mt76_register_phy(mphy); if (ret) ieee80211_free_hw(mphy->hw); @@ -437,6 +437,12 @@ void mt7615_init_device(struct mt7615_dev *dev) dev->phy.dev = dev; dev->phy.mt76 = &dev->mt76.phy; dev->mt76.phy.priv = &dev->phy; + + INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work); + INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work); + init_completion(&dev->pm.wake_cmpl); + spin_lock_init(&dev->pm.txq_lock); + set_bit(MT76_STATE_PM, &dev->mphy.state); INIT_DELAYED_WORK(&dev->phy.mac_work, mt7615_mac_work); INIT_DELAYED_WORK(&dev->phy.scan_work, mt7615_scan_work); skb_queue_head_init(&dev->phy.scan_event_list); @@ -450,6 +456,7 @@ void mt7615_init_device(struct mt7615_dev *dev) timer_setup(&dev->phy.roc_timer, mt7615_roc_timer, 0); mt7615_init_wiphy(hw); + dev->pm.idle_timeout = MT7615_PM_TIMEOUT; dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; dev->mphy.sband_5g.sband.vht_cap.cap |= @@ -457,5 +464,9 @@ void mt7615_init_device(struct mt7615_dev *dev) IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; mt7615_cap_dbdc_disable(dev); dev->phy.dfs_state = -1; + +#ifdef CONFIG_NL80211_TESTMODE + dev->mt76.test_ops = &mt7615_testmode_ops; +#endif } EXPORT_SYMBOL_GPL(mt7615_init_device); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index d97315ec7265..3dd8dd28690e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -186,6 +186,40 @@ mt7615_get_status_freq_info(struct mt7615_dev *dev, struct mt76_phy *mphy, status->freq = ieee80211_channel_to_frequency(chfreq, status->band); } +static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv) +{ +#ifdef CONFIG_NL80211_TESTMODE + u32 rxv1 = le32_to_cpu(rxv[0]); + u32 rxv3 = le32_to_cpu(rxv[2]); + u32 rxv4 = le32_to_cpu(rxv[3]); + u32 rxv5 = le32_to_cpu(rxv[4]); + u8 cbw = FIELD_GET(MT_RXV1_FRAME_MODE, rxv1); + u8 mode = FIELD_GET(MT_RXV1_TX_MODE, rxv1); + s16 foe = FIELD_GET(MT_RXV5_FOE, rxv5); + u32 foe_const = (BIT(cbw + 1) & 0xf) * 10000; + + if (!mode) { + /* CCK */ + foe &= ~BIT(11); + foe *= 1000; + foe >>= 11; + } else { + if (foe > 2048) + foe -= 4096; + + foe = (foe * foe_const) >> 15; + } + + dev->test.last_freq_offset = foe; + dev->test.last_rcpi[0] = FIELD_GET(MT_RXV4_RCPI0, rxv4); + dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4); + dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4); + dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4); + dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3); + dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3); +#endif +} + static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -401,6 +435,8 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) status->chain_signal[i]); } + mt7615_mac_fill_tm_rx(dev, rxd); + rxd += 6; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; @@ -493,18 +529,18 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct ieee80211_sta *sta, int pid, struct ieee80211_key_conf *key, bool beacon) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; bool multicast = is_multicast_ether_addr(hdr->addr1); struct ieee80211_vif *vif = info->control.vif; + bool is_mmio = mt76_is_mmio(&dev->mt76); + u32 val, sz_txd = is_mmio ? MT_TXD_SIZE : MT_USB_TXD_SIZE; struct mt76_phy *mphy = &dev->mphy; - bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY; - bool is_usb = mt76_is_usb(&dev->mt76); - int tx_count = 8; - u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; __le16 fc = hdr->frame_control; - u32 val, sz_txd = is_usb ? MT_USB_TXD_SIZE : MT_TXD_SIZE; + int tx_count = 8; u16 seqno = 0; if (vif) { @@ -530,10 +566,10 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, p_fmt = MT_TX_TYPE_FW; q_idx = ext_phy ? MT_LMAC_BCN1 : MT_LMAC_BCN0; } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { - p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; + p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = ext_phy ? MT_LMAC_ALTX1 : MT_LMAC_ALTX0; } else { - p_fmt = is_usb ? MT_TX_TYPE_SF : MT_TX_TYPE_CT; + p_fmt = is_mmio ? MT_TX_TYPE_CT : MT_TX_TYPE_SF; q_idx = wmm_idx * MT7615_MAX_WMM_SETS + mt7615_lmac_mapping(dev, skb_get_queue_mapping(skb)); } @@ -617,16 +653,19 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, } val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count); - if (ieee80211_is_data_qos(hdr->frame_control)) { - seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); - val |= MT_TXD3_SN_VALID; - } else if (ieee80211_is_back_req(hdr->frame_control)) { - struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; + if (info->flags & IEEE80211_TX_CTL_INJECTED) { + seqno = le16_to_cpu(hdr->seq_ctrl); + + if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar; - seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num)); - val |= MT_TXD3_SN_VALID; + bar = (struct ieee80211_bar *)skb->data; + seqno = le16_to_cpu(bar->start_seq_num); + } + + val |= MT_TXD3_SN_VALID | + FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno)); } - val |= FIELD_PREP(MT_TXD3_SEQ, seqno); txwi[3] |= cpu_to_le32(val); @@ -636,7 +675,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype) | FIELD_PREP(MT_TXD7_SPE_IDX, 0x18); - if (is_usb) + if (!is_mmio) txwi[8] = FIELD_PREP(MT_TXD8_L_TYPE, fc_type) | FIELD_PREP(MT_TXD8_L_SUB_TYPE, fc_stype); @@ -878,6 +917,9 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, struct mt7615_dev *dev = phy->dev; struct mt7615_wtbl_desc *wd; + if (work_pending(&dev->wtbl_work)) + return -EBUSY; + wd = kzalloc(sizeof(*wd), GFP_ATOMIC); if (!wd) return -ENOMEM; @@ -888,11 +930,34 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta, mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates, &wd->rate); list_add_tail(&wd->node, &dev->wd_head); - queue_work(dev->mt76.usb.wq, &dev->wtbl_work); + queue_work(dev->mt76.wq, &dev->wtbl_work); return 0; } +u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid) +{ + u32 addr, val, val2; + u8 offset; + + addr = mt7615_mac_wtbl_addr(dev, wcid) + 11 * 4; + + offset = tid * 12; + addr += 4 * (offset / 32); + offset %= 32; + + val = mt76_rr(dev, addr); + val >>= (tid % 32); + + if (offset > 20) { + addr += 4; + val2 = mt76_rr(dev, addr); + val |= val2 << (32 - offset); + } + + return val & GENMASK(11, 0); +} + void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) @@ -902,7 +967,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct mt7615_rate_desc rd; u32 w5, w27, addr; - if (mt76_is_usb(&dev->mt76)) { + if (!mt76_is_mmio(&dev->mt76)) { mt7615_mac_queue_rate_update(phy, sta, probe_rate, rates); return; } @@ -961,6 +1026,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + sta->rate_probe = !!probe_rate; } EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); @@ -1169,7 +1235,6 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, phy = dev->mt76.phy2->priv; mt7615_mac_set_rates(phy, sta, NULL, sta->rates); - sta->rate_probe = false; } spin_unlock_bh(&dev->mt76.lock); } else { @@ -1373,6 +1438,12 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) } dev_kfree_skb(skb); + + rcu_read_lock(); + mt7615_mac_sta_poll(dev); + rcu_read_unlock(); + + tasklet_schedule(&dev->mt76.tx_tasklet); } void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, @@ -1462,7 +1533,7 @@ void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) bool ext_phy = phy != &dev->phy; u32 reg, mask; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); if (phy->scs_en == enable) goto out; @@ -1489,7 +1560,7 @@ void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable) phy->scs_en = enable; out: - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy) @@ -1679,9 +1750,9 @@ mt7615_phy_update_channel(struct mt76_phy *mphy, int idx) state->noise = -(phy->noise >> 4); } -void mt7615_update_channel(struct mt76_dev *mdev) +static void __mt7615_update_channel(struct mt7615_dev *dev) { - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_dev *mdev = &dev->mt76; mt7615_phy_update_channel(&mdev->phy, 0); if (mdev->phy2) @@ -1690,8 +1761,32 @@ void mt7615_update_channel(struct mt76_dev *mdev) /* reset obss airtime */ mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } + +void mt7615_update_channel(struct mt76_dev *mdev) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + + if (mt7615_pm_wake(dev)) + return; + + __mt7615_update_channel(dev); + mt7615_pm_power_save_sched(dev); +} EXPORT_SYMBOL_GPL(mt7615_update_channel); +static void mt7615_update_survey(struct mt7615_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + ktime_t cur_time; + + __mt7615_update_channel(dev); + cur_time = ktime_get_boottime(); + + mt76_update_survey_active_time(&mdev->phy, cur_time); + if (mdev->phy2) + mt76_update_survey_active_time(mdev->phy2, cur_time); +} + static void mt7615_mac_update_mib_stats(struct mt7615_phy *phy) { @@ -1740,6 +1835,163 @@ mt7615_mac_update_mib_stats(struct mt7615_phy *phy) } } +void mt7615_pm_wake_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + struct mt76_phy *mphy; + int i; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + pm.wake_work); + mphy = dev->phy.mt76; + + if (mt7615_driver_own(dev)) { + dev_err(mphy->dev->dev, "failed to wake device\n"); + goto out; + } + + spin_lock_bh(&dev->pm.txq_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + struct mt7615_sta *msta = dev->pm.tx_q[i].msta; + struct mt76_wcid *wcid = msta ? &msta->wcid : NULL; + struct ieee80211_sta *sta = NULL; + + if (!dev->pm.tx_q[i].skb) + continue; + + if (msta && wcid->sta) + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + + mt76_tx(mphy, sta, wcid, dev->pm.tx_q[i].skb); + dev->pm.tx_q[i].skb = NULL; + } + spin_unlock_bh(&dev->pm.txq_lock); + + tasklet_schedule(&dev->mt76.tx_tasklet); + +out: + ieee80211_wake_queues(mphy->hw); + complete_all(&dev->pm.wake_cmpl); +} + +int mt7615_pm_wake(struct mt7615_dev *dev) +{ + struct mt76_phy *mphy = dev->phy.mt76; + + if (!mt7615_firmware_offload(dev)) + return 0; + + if (!mt76_is_mmio(mphy->dev)) + return 0; + + if (!test_bit(MT76_STATE_PM, &mphy->state)) + return 0; + + if (test_bit(MT76_HW_SCANNING, &mphy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) + return 0; + + if (queue_work(dev->mt76.wq, &dev->pm.wake_work)) + reinit_completion(&dev->pm.wake_cmpl); + + if (!wait_for_completion_timeout(&dev->pm.wake_cmpl, 3 * HZ)) { + ieee80211_wake_queues(mphy->hw); + return -ETIMEDOUT; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mt7615_pm_wake); + +void mt7615_pm_power_save_sched(struct mt7615_dev *dev) +{ + struct mt76_phy *mphy = dev->phy.mt76; + + if (!mt7615_firmware_offload(dev)) + return; + + if (!mt76_is_mmio(mphy->dev)) + return; + + if (!dev->pm.enable || !test_bit(MT76_STATE_RUNNING, &mphy->state)) + return; + + dev->pm.last_activity = jiffies; + + if (test_bit(MT76_HW_SCANNING, &mphy->state) || + test_bit(MT76_HW_SCHED_SCANNING, &mphy->state)) + return; + + if (!test_bit(MT76_STATE_PM, &mphy->state)) + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, + dev->pm.idle_timeout); +} +EXPORT_SYMBOL_GPL(mt7615_pm_power_save_sched); + +void mt7615_pm_power_save_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + unsigned long delta; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + pm.ps_work.work); + + delta = dev->pm.idle_timeout; + if (time_is_after_jiffies(dev->pm.last_activity + delta)) { + delta = dev->pm.last_activity + delta - jiffies; + goto out; + } + + if (!mt7615_firmware_own(dev)) + return; +out: + queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta); +} + +static void +mt7615_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7615_phy *phy = priv; + struct mt7615_dev *dev = phy->dev; + bool ext_phy = phy != &dev->phy; + + if (mt7615_mcu_set_bss_pm(dev, vif, dev->pm.enable)) + return; + + if (dev->pm.enable) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } else { + vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER; + mt76_clear(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } +} + +int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable) +{ + struct mt76_phy *mphy = dev->phy.mt76; + + if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76)) + return -EOPNOTSUPP; + + mt7615_mutex_acquire(dev); + + if (dev->pm.enable == enable) + goto out; + + dev->pm.enable = enable; + ieee80211_iterate_active_interfaces(mphy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7615_pm_interface_iter, mphy->priv); +out: + mt7615_mutex_release(dev); + + return 0; +} + void mt7615_mac_work(struct work_struct *work) { struct mt7615_phy *phy; @@ -1749,9 +2001,9 @@ void mt7615_mac_work(struct work_struct *work) mac_work.work); mdev = &phy->dev->mt76; - mutex_lock(&mdev->mutex); + mt7615_mutex_acquire(phy->dev); - mt76_update_survey(mdev); + mt7615_update_survey(phy->dev); if (++phy->mac_work_count == 5) { phy->mac_work_count = 0; @@ -1759,7 +2011,7 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mac_scs_check(phy); } - mutex_unlock(&mdev->mutex); + mt7615_mutex_release(phy->dev); mt76_tx_status_check(mdev, NULL, false); ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, @@ -1863,7 +2115,7 @@ void mt7615_mac_reset_work(struct work_struct *work) napi_disable(&dev->mt76.napi[1]); napi_disable(&dev->mt76.tx_napi); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_PDMA_STOPPED); @@ -1896,10 +2148,10 @@ void mt7615_mac_reset_work(struct work_struct *work) mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE); mt7615_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); - mutex_unlock(&dev->mt76.mutex); - mt7615_update_beacons(dev); + mt7615_mutex_release(dev); + ieee80211_queue_delayed_work(mt76_hw(dev), &dev->phy.mac_work, MT7615_WATCHDOG_TIME); if (phy2) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index 81608ab656b8..169f4e17b5b4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -100,11 +100,16 @@ enum rx_pkt_type { #define MT_RXV2_GROUP_ID GENMASK(26, 21) #define MT_RXV2_LENGTH GENMASK(20, 0) +#define MT_RXV3_WB_RSSI GENMASK(31, 24) +#define MT_RXV3_IB_RSSI GENMASK(23, 16) + #define MT_RXV4_RCPI3 GENMASK(31, 24) #define MT_RXV4_RCPI2 GENMASK(23, 16) #define MT_RXV4_RCPI1 GENMASK(15, 8) #define MT_RXV4_RCPI0 GENMASK(7, 0) +#define MT_RXV5_FOE GENMASK(11, 0) + #define MT_RXV6_NF3 GENMASK(31, 24) #define MT_RXV6_NF2 GENMASK(23, 16) #define MT_RXV6_NF1 GENMASK(15, 8) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index beaca8127680..2d0b1f49fdbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -24,6 +24,22 @@ static bool mt7615_dev_running(struct mt7615_dev *dev) return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state); } +static void mt7615_free_pending_tx_skbs(struct mt7615_dev *dev, + struct mt7615_sta *msta) +{ + int i; + + spin_lock_bh(&dev->pm.txq_lock); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (msta && dev->pm.tx_q[i].msta != msta) + continue; + + dev_kfree_skb(dev->pm.tx_q[i].skb); + dev->pm.tx_q[i].skb = NULL; + } + spin_unlock_bh(&dev->pm.txq_lock); +} + static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = mt7615_hw_dev(hw); @@ -33,7 +49,7 @@ static int mt7615_start(struct ieee80211_hw *hw) if (!mt7615_wait_for_mcu_init(dev)) return -EIO; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); running = mt7615_dev_running(dev); @@ -60,7 +76,7 @@ static int mt7615_start(struct ieee80211_hw *hw) if (!running) mt7615_mac_reset_counters(dev); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -74,7 +90,14 @@ static void mt7615_stop(struct ieee80211_hw *hw) del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); - mutex_lock(&dev->mt76.mutex); + cancel_delayed_work_sync(&dev->pm.ps_work); + cancel_work_sync(&dev->pm.wake_work); + + mt7615_free_pending_tx_skbs(dev, NULL); + + mt7615_mutex_acquire(dev); + + mt76_testmode_reset(&dev->mt76, true); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); @@ -89,7 +112,7 @@ static void mt7615_stop(struct ieee80211_hw *hw) mt7615_mcu_set_mac_enable(dev, 0, false); } - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static int get_omac_idx(enum nl80211_iftype type, u32 mask) @@ -135,9 +158,15 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, bool ext_phy = phy != &dev->phy; int idx, ret = 0; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); + + mt76_testmode_reset(&dev->mt76, true); - mvif->idx = ffs(~dev->vif_mask) - 1; + if (vif->type == NL80211_IFTYPE_MONITOR && + is_zero_ether_addr(vif->addr)) + phy->monitor_vif = vif; + + mvif->idx = ffs(~dev->mphy.vif_mask) - 1; if (mvif->idx >= MT7615_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -157,7 +186,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, else mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS; - dev->vif_mask |= BIT(mvif->idx); + dev->mphy.vif_mask |= BIT(mvif->idx); dev->omac_mask |= BIT(mvif->omac_idx); phy->omac_mask |= BIT(mvif->omac_idx); @@ -180,8 +209,20 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, } ret = mt7615_mcu_add_dev_info(dev, vif, true); + if (ret) + goto out; + + if (dev->pm.enable) { + ret = mt7615_mcu_set_bss_pm(dev, vif, true); + if (ret) + goto out; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + mt76_set(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } out: - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return ret; } @@ -197,17 +238,32 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, /* TODO: disable beacon for the bss */ + mt7615_mutex_acquire(dev); + + mt76_testmode_reset(&dev->mt76, true); + if (vif == phy->monitor_vif) + phy->monitor_vif = NULL; + + mt7615_free_pending_tx_skbs(dev, msta); + + if (dev->pm.enable) { + bool ext_phy = phy != &dev->phy; + + mt7615_mcu_set_bss_pm(dev, vif, false); + mt76_clear(dev, MT_WF_RFCR(ext_phy), + MT_WF_RFCR_DROP_OTHER_BEACON); + } mt7615_mcu_add_dev_info(dev, vif, false); rcu_assign_pointer(dev->mt76.wcid[idx], NULL); if (vif->txq) mt76_txq_remove(&dev->mt76, vif->txq); - mutex_lock(&dev->mt76.mutex); - dev->vif_mask &= ~BIT(mvif->idx); + dev->mphy.vif_mask &= ~BIT(mvif->idx); dev->omac_mask &= ~BIT(mvif->omac_idx); phy->omac_mask &= ~BIT(mvif->omac_idx); - mutex_unlock(&dev->mt76.mutex); + + mt7615_mutex_release(dev); spin_lock_bh(&dev->sta_poll_lock); if (!list_empty(&msta->poll_list)) @@ -234,7 +290,7 @@ static void mt7615_init_dfs_state(struct mt7615_phy *phy) phy->dfs_state = -1; } -static int mt7615_set_channel(struct mt7615_phy *phy) +int mt7615_set_channel(struct mt7615_phy *phy) { struct mt7615_dev *dev = phy->dev; bool ext_phy = phy != &dev->phy; @@ -242,7 +298,8 @@ static int mt7615_set_channel(struct mt7615_phy *phy) cancel_delayed_work_sync(&phy->mac_work); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); + set_bit(MT76_RESET, &phy->mt76->state); mt7615_init_dfs_state(phy); @@ -260,7 +317,7 @@ static int mt7615_set_channel(struct mt7615_phy *phy) mt7615_mac_set_timing(phy); ret = mt7615_dfs_init_radar_detector(phy); mt7615_mac_cca_stats_reset(phy); - mt7615_mcu_set_sku_en(phy, true); + mt7615_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76)); mt7615_mac_reset_counters(dev); phy->noise = 0; @@ -268,11 +325,15 @@ static int mt7615_set_channel(struct mt7615_phy *phy) out: clear_bit(MT76_RESET, &phy->mt76->state); - mutex_unlock(&dev->mt76.mutex); + + mt7615_mutex_release(dev); mt76_txq_schedule_all(phy->mt76); - ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, - MT7615_WATCHDOG_TIME); + + if (!mt76_testmode_enabled(&dev->mt76)) + ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work, + MT7615_WATCHDOG_TIME); + return ret; } @@ -301,7 +362,7 @@ mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd, wd->key.cmd = cmd; list_add_tail(&wd->node, &dev->wd_head); - queue_work(dev->mt76.usb.wq, &dev->wtbl_work); + queue_work(dev->mt76.wq, &dev->wtbl_work); return 0; } @@ -315,7 +376,7 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt7615_sta *msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta; struct mt76_wcid *wcid = &msta->wcid; - int idx = key->keyidx; + int idx = key->keyidx, err; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. @@ -345,6 +406,8 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + mt7615_mutex_acquire(dev); + if (cmd == SET_KEY) { key->hw_key_idx = wcid->idx; wcid->hw_key_idx = idx; @@ -354,10 +417,14 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mt76_wcid_key_setup(&dev->mt76, wcid, cmd == SET_KEY ? key : NULL); - if (mt76_is_usb(&dev->mt76)) - return mt7615_queue_key_update(dev, cmd, msta, key); + if (mt76_is_mmio(&dev->mt76)) + err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + else + err = mt7615_queue_key_update(dev, cmd, msta, key); + + mt7615_mutex_release(dev); - return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); + return err; } static int mt7615_config(struct ieee80211_hw *hw, u32 changed) @@ -369,14 +436,23 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | IEEE80211_CONF_CHANGE_POWER)) { +#ifdef CONFIG_NL80211_TESTMODE + if (dev->mt76.test.state != MT76_TM_STATE_OFF) { + mt7615_mutex_acquire(dev); + mt76_testmode_reset(&dev->mt76, false); + mt7615_mutex_release(dev); + } +#endif ieee80211_stop_queues(hw); ret = mt7615_set_channel(phy); ieee80211_wake_queues(hw); } - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + mt76_testmode_reset(&dev->mt76, true); + if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; else @@ -385,7 +461,7 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter); } - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return ret; } @@ -396,11 +472,17 @@ mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = mt7615_hw_dev(hw); + int err; + + mt7615_mutex_acquire(dev); queue = mt7615_lmac_mapping(dev, queue); queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS; + err = mt7615_mcu_set_wmm(dev, queue, params); - return mt7615_mcu_set_wmm(dev, queue, params); + mt7615_mutex_release(dev); + + return err; } static void mt7615_configure_filter(struct ieee80211_hw *hw, @@ -419,10 +501,13 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, MT_WF_RFCR1_DROP_CFACK; u32 flags = 0; + mt7615_mutex_acquire(dev); + #define MT76_FILTER(_flag, _hw) do { \ flags |= *total_flags & FIF_##_flag; \ phy->rxfilter &= ~(_hw); \ - phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \ + if (!mt76_testmode_enabled(&dev->mt76)) \ + phy->rxfilter |= !(flags & FIF_##_flag) * (_hw);\ } while (0) phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | @@ -455,6 +540,8 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags); else mt76_set(dev, MT_WF_RFCR1(band), ctl_flags); + + mt7615_mutex_release(dev); } static void mt7615_bss_info_changed(struct ieee80211_hw *hw, @@ -465,7 +552,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; @@ -491,7 +578,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_PS) mt7615_mcu_set_vif_ps(dev, vif); - mutex_unlock(&dev->mt76.mutex); + if (changed & BSS_CHANGED_ARP_FILTER) + mt7615_mcu_update_arp_filter(hw, vif, info); + + mt7615_mutex_release(dev); } static void @@ -501,9 +591,9 @@ mt7615_channel_switch_beacon(struct ieee80211_hw *hw, { struct mt7615_dev *dev = mt7615_hw_dev(hw); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt7615_mcu_add_beacon(dev, hw, vif, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -512,7 +602,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - int idx; + int idx, err; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); if (idx < 0) @@ -524,6 +614,10 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.idx = idx; msta->wcid.ext_phy = mvif->band_idx; + err = mt7615_pm_wake(dev); + if (err) + return err; + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { struct mt7615_phy *phy; @@ -534,6 +628,8 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); mt7615_mcu_sta_add(dev, vif, sta, true); + mt7615_pm_power_save_sched(dev); + return 0; } EXPORT_SYMBOL_GPL(mt7615_mac_sta_add); @@ -544,6 +640,9 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; + mt7615_free_pending_tx_skbs(dev, msta); + mt7615_pm_wake(dev); + mt7615_mcu_sta_add(dev, vif, sta, false); mt7615_mac_wtbl_update(dev, msta->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -559,6 +658,8 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (!list_empty(&msta->poll_list)) list_del_init(&msta->poll_list); spin_unlock_bh(&dev->sta_poll_lock); + + mt7615_pm_power_save_sched(dev); } EXPORT_SYMBOL_GPL(mt7615_mac_sta_remove); @@ -582,11 +683,29 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, break; } msta->n_rates = i; - mt7615_mac_set_rates(phy, msta, NULL, msta->rates); - msta->rate_probe = false; + if (!test_bit(MT76_STATE_PM, &phy->mt76->state)) + mt7615_mac_set_rates(phy, msta, NULL, msta->rates); spin_unlock_bh(&dev->mt76.lock); } +static void +mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct mt7615_phy *phy = mt7615_hw_phy(hw); + struct mt76_phy *mphy = phy->mt76; + + if (!test_bit(MT76_STATE_RUNNING, &mphy->state)) + return; + + if (test_bit(MT76_STATE_PM, &mphy->state)) { + queue_work(dev->mt76.wq, &dev->pm.wake_work); + return; + } + + tasklet_schedule(&dev->mt76.tx_tasklet); +} + static void mt7615_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) @@ -596,22 +715,43 @@ static void mt7615_tx(struct ieee80211_hw *hw, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + struct mt7615_sta *msta = NULL; + int qid; if (control->sta) { - struct mt7615_sta *sta; - - sta = (struct mt7615_sta *)control->sta->drv_priv; - wcid = &sta->wcid; + msta = (struct mt7615_sta *)control->sta->drv_priv; + wcid = &msta->wcid; } if (vif && !control->sta) { struct mt7615_vif *mvif; mvif = (struct mt7615_vif *)vif->drv_priv; - wcid = &mvif->sta.wcid; + msta = &mvif->sta; + wcid = &msta->wcid; + } + + if (!test_bit(MT76_STATE_PM, &mphy->state)) { + mt76_tx(mphy, control->sta, wcid, skb); + return; + } + + qid = skb_get_queue_mapping(skb); + if (qid >= MT_TXQ_PSD) { + qid = IEEE80211_AC_BE; + skb_set_queue_mapping(skb, qid); } - mt76_tx(mphy, control->sta, wcid, skb); + spin_lock_bh(&dev->pm.txq_lock); + if (!dev->pm.tx_q[qid].skb) { + ieee80211_stop_queues(hw); + dev->pm.tx_q[qid].msta = msta; + dev->pm.tx_q[qid].skb = skb; + queue_work(dev->mt76.wq, &dev->pm.wake_work); + } else { + dev_kfree_skb(skb); + } + spin_unlock_bh(&dev->pm.txq_lock); } static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) @@ -619,9 +759,9 @@ static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt7615_mcu_set_rts_thresh(phy, val); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -645,7 +785,8 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); + switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -660,6 +801,9 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq->aggr = true; mtxq->send_bar = false; mt7615_mcu_add_tx_ba(dev, params, true); + ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid); + ieee80211_send_bar(vif, sta->addr, tid, + IEEE80211_SN_TO_SEQ(ssn)); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: @@ -667,6 +811,8 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mt7615_mcu_add_tx_ba(dev, params, false); break; case IEEE80211_AMPDU_TX_START: + ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid); + params->ssn = ssn; mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; @@ -676,7 +822,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return ret; } @@ -721,27 +867,47 @@ mt7615_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) u32 t32[2]; } tsf; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ tsf.t32[0] = mt76_rr(dev, MT_LPON_UTTR0); tsf.t32[1] = mt76_rr(dev, MT_LPON_UTTR1); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return tsf.t64; } static void +mt7615_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 timestamp) +{ + struct mt7615_dev *dev = mt7615_hw_dev(hw); + union { + u64 t64; + u32 t32[2]; + } tsf = { .t64 = timestamp, }; + + mt7615_mutex_acquire(dev); + + mt76_wr(dev, MT_LPON_UTTR0, tsf.t32[0]); + mt76_wr(dev, MT_LPON_UTTR1, tsf.t32[1]); + /* TSF software overwrite */ + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_WRITE); + + mt7615_mutex_release(dev); +} + +static void mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = phy->dev; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); phy->coverage_class = max_t(s16, coverage_class, 0); mt7615_mac_set_timing(phy); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); } static int @@ -758,7 +924,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) if ((BIT(hweight8(tx_ant)) - 1) != tx_ant) tx_ant = BIT(ffs(tx_ant) - 1) - 1; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); phy->mt76->antenna_mask = tx_ant; if (ext_phy) { @@ -771,7 +937,7 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) mt76_set_stream_caps(phy->mt76, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -794,9 +960,11 @@ void mt7615_roc_work(struct work_struct *work) if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) return; + mt7615_mutex_acquire(phy->dev); ieee80211_iterate_active_interfaces(phy->mt76->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7615_roc_iter, phy); + mt7615_mutex_release(phy->dev); ieee80211_remain_on_channel_expired(phy->mt76->hw); } @@ -844,17 +1012,26 @@ static int mt7615_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *req) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; + int err; + + mt7615_mutex_acquire(dev); + err = mt7615_mcu_hw_scan(mphy->priv, vif, req); + mt7615_mutex_release(dev); - return mt7615_mcu_hw_scan(mphy->priv, vif, req); + return err; } static void mt7615_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; + mt7615_mutex_acquire(dev); mt7615_mcu_cancel_hw_scan(mphy->priv, vif); + mt7615_mutex_release(dev); } static int @@ -862,22 +1039,35 @@ mt7615_start_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, struct ieee80211_scan_ies *ies) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; int err; + mt7615_mutex_acquire(dev); + err = mt7615_mcu_sched_scan_req(mphy->priv, vif, req); if (err < 0) - return err; + goto out; + + err = mt7615_mcu_sched_scan_enable(mphy->priv, vif, true); +out: + mt7615_mutex_release(dev); - return mt7615_mcu_sched_scan_enable(mphy->priv, vif, true); + return err; } static int mt7615_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt76_phy *mphy = hw->priv; + int err; - return mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); + mt7615_mutex_acquire(dev); + err = mt7615_mcu_sched_scan_enable(mphy->priv, vif, false); + mt7615_mutex_release(dev); + + return err; } static int mt7615_remain_on_channel(struct ieee80211_hw *hw, @@ -892,20 +1082,24 @@ static int mt7615_remain_on_channel(struct ieee80211_hw *hw, if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)) return 0; + mt7615_mutex_acquire(phy->dev); + err = mt7615_mcu_set_roc(phy, vif, chan, duration); if (err < 0) { clear_bit(MT76_STATE_ROC, &phy->mt76->state); - return err; + goto out; } if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, HZ)) { mt7615_mcu_set_roc(phy, vif, NULL, 0); clear_bit(MT76_STATE_ROC, &phy->mt76->state); - - return -ETIMEDOUT; + err = -ETIMEDOUT; } - return 0; +out: + mt7615_mutex_release(phy->dev); + + return err; } static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw, @@ -919,7 +1113,9 @@ static int mt7615_cancel_remain_on_channel(struct ieee80211_hw *hw, del_timer_sync(&phy->roc_timer); cancel_work_sync(&phy->roc_work); + mt7615_mutex_acquire(phy->dev); mt7615_mcu_set_roc(phy, vif, NULL, 0); + mt7615_mutex_release(phy->dev); return 0; } @@ -933,7 +1129,10 @@ static int mt7615_suspend(struct ieee80211_hw *hw, bool ext_phy = phy != &dev->phy; int err = 0; - mutex_lock(&dev->mt76.mutex); + cancel_delayed_work_sync(&dev->pm.ps_work); + mt7615_free_pending_tx_skbs(dev, NULL); + + mt7615_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); cancel_delayed_work_sync(&phy->scan_work); @@ -949,7 +1148,7 @@ static int mt7615_suspend(struct ieee80211_hw *hw, if (!mt7615_dev_running(dev)) err = mt7615_mcu_set_hif_suspend(dev, true); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return err; } @@ -960,7 +1159,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) struct mt7615_phy *phy = mt7615_hw_phy(hw); bool running, ext_phy = phy != &dev->phy; - mutex_lock(&dev->mt76.mutex); + mt7615_mutex_acquire(dev); running = mt7615_dev_running(dev); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -970,7 +1169,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) err = mt7615_mcu_set_hif_suspend(dev, false); if (err < 0) { - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return err; } } @@ -984,7 +1183,7 @@ static int mt7615_resume(struct ieee80211_hw *hw) MT7615_WATCHDOG_TIME); mt76_clear(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON); - mutex_unlock(&dev->mt76.mutex); + mt7615_mutex_release(dev); return 0; } @@ -1001,7 +1200,11 @@ static void mt7615_set_rekey_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *data) { + struct mt7615_dev *dev = mt7615_hw_dev(hw); + + mt7615_mutex_acquire(dev); mt7615_mcu_update_gtk_rekey(hw, vif, data); + mt7615_mutex_release(dev); } #endif /* CONFIG_PM */ @@ -1021,7 +1224,7 @@ const struct ieee80211_ops mt7615_ops = { .set_key = mt7615_set_key, .ampdu_action = mt7615_ampdu_action, .set_rts_threshold = mt7615_set_rts_threshold, - .wake_tx_queue = mt76_wake_tx_queue, + .wake_tx_queue = mt7615_wake_tx_queue, .sta_rate_tbl_update = mt7615_sta_rate_tbl_update, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76_sw_scan_complete, @@ -1030,6 +1233,7 @@ const struct ieee80211_ops mt7615_ops = { .channel_switch_beacon = mt7615_channel_switch_beacon, .get_stats = mt7615_get_stats, .get_tsf = mt7615_get_tsf, + .set_tsf = mt7615_set_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7615_set_antenna, @@ -1040,6 +1244,8 @@ const struct ieee80211_ops mt7615_ops = { .sched_scan_stop = mt7615_stop_sched_scan, .remain_on_channel = mt7615_remain_on_channel, .cancel_remain_on_channel = mt7615_cancel_remain_on_channel, + CFG80211_TESTMODE_CMD(mt76_testmode_cmd) + CFG80211_TESTMODE_DUMP(mt76_testmode_dump) #ifdef CONFIG_PM .suspend = mt7615_suspend, .resume = mt7615_resume, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 6e869b8c5e26..d0cbb283982f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -146,13 +146,19 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, mcu_txd->cid = mcu_cmd; break; case MCU_CE_PREFIX: - mcu_txd->set_query = MCU_Q_SET; + if (cmd & MCU_QUERY_MASK) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; mcu_txd->cid = mcu_cmd; break; default: mcu_txd->cid = MCU_CMD_EXT_CID; - mcu_txd->set_query = MCU_Q_SET; - mcu_txd->ext_cid = cmd; + if (cmd & MCU_QUERY_PREFIX) + mcu_txd->set_query = MCU_Q_QUERY; + else + mcu_txd->set_query = MCU_Q_SET; + mcu_txd->ext_cid = mcu_cmd; mcu_txd->ext_cid_ack = 1; break; } @@ -180,8 +186,10 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; int ret = 0; - if (seq != rxd->seq) - return -EAGAIN; + if (seq != rxd->seq) { + ret = -EAGAIN; + goto out; + } switch (cmd) { case MCU_CMD_PATCH_SEM_CONTROL: @@ -192,6 +200,10 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)skb->data); break; + case MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX: + skb_pull(skb, sizeof(*rxd)); + ret = le32_to_cpu(*(__le32 *)&skb->data[8]); + break; case MCU_UNI_CMD_DEV_INFO_UPDATE: case MCU_UNI_CMD_BSS_INFO_UPDATE: case MCU_UNI_CMD_STA_REC_UPDATE: @@ -205,9 +217,18 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, ret = le32_to_cpu(event->status); break; } + case MCU_CMD_REG_READ: { + struct mt7615_mcu_reg_event *event; + + skb_pull(skb, sizeof(*rxd)); + event = (struct mt7615_mcu_reg_event *)skb->data; + ret = (int)le32_to_cpu(event->val); + break; + } default: break; } +out: dev_kfree_skb(skb); return ret; @@ -271,6 +292,38 @@ int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, } EXPORT_SYMBOL_GPL(mt7615_mcu_msg_send); +u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg) +{ + struct { + __le32 wifi_stream; + __le32 address; + __le32 data; + } req = { + .wifi_stream = cpu_to_le32(wf), + .address = cpu_to_le32(reg), + }; + + return __mt76_mcu_send_msg(&dev->mt76, + MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX, + &req, sizeof(req), true); +} + +int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val) +{ + struct { + __le32 wifi_stream; + __le32 address; + __le32 data; + } req = { + .wifi_stream = cpu_to_le32(wf), + .address = cpu_to_le32(reg), + .data = cpu_to_le32(val), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RF_REG_ACCESS, &req, + sizeof(req), false); +} + static void mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { @@ -927,6 +980,38 @@ mt7615_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) } static void +mt7615_mcu_sta_uapsd(struct sk_buff *skb, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct sta_rec_uapsd *uapsd; + struct tlv *tlv; + + if (vif->type != NL80211_IFTYPE_AP || !sta->wme) + return; + + tlv = mt7615_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd)); + uapsd = (struct sta_rec_uapsd *)tlv; + + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) { + uapsd->dac_map |= BIT(3); + uapsd->tac_map |= BIT(3); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) { + uapsd->dac_map |= BIT(2); + uapsd->tac_map |= BIT(2); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) { + uapsd->dac_map |= BIT(1); + uapsd->tac_map |= BIT(1); + } + if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) { + uapsd->dac_map |= BIT(0); + uapsd->tac_map |= BIT(0); + } + uapsd->max_sp = sta->max_sp; +} + +static void mt7615_mcu_wtbl_ba_tlv(struct sk_buff *skb, struct ieee80211_ampdu_params *params, bool enable, bool tx, void *sta_wtbl, @@ -1188,8 +1273,10 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(sskb); mt7615_mcu_sta_basic_tlv(sskb, vif, sta, enable); - if (enable && sta) + if (enable && sta) { mt7615_mcu_sta_ht_tlv(sskb, sta); + mt7615_mcu_sta_uapsd(sskb, vif, sta); + } wtbl_hdr = mt7615_mcu_alloc_wtbl_req(dev, msta, WTBL_RESET_AND_SET, NULL, &wskb); @@ -1206,8 +1293,12 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif, skb = enable ? wskb : sskb; err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true); - if (err < 0) + if (err < 0) { + skb = enable ? sskb : wskb; + dev_kfree_skb(skb); + return err; + } cmd = enable ? MCU_EXT_CMD_STA_REC_UPDATE : MCU_EXT_CMD_WTBL_UPDATE; skb = enable ? sskb : wskb; @@ -1285,8 +1376,10 @@ mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); mt7615_mcu_sta_basic_tlv(skb, vif, sta, enable); - if (enable && sta) + if (enable && sta) { mt7615_mcu_sta_ht_tlv(skb, sta); + mt7615_mcu_sta_uapsd(skb, vif, sta); + } sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); @@ -1429,6 +1522,7 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, u8 pad[3]; } __packed hdr; struct mt7615_bss_basic_tlv basic; + struct mt7615_bss_qos_tlv qos; } basic_req = { .hdr = { .bss_idx = mvif->idx, @@ -1444,6 +1538,11 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif, .active = true, /* keep bss deactivated */ .phymode = 0x38, }, + .qos = { + .tag = cpu_to_le16(UNI_BSS_INFO_QBSS), + .len = cpu_to_le16(sizeof(struct mt7615_bss_qos_tlv)), + .qos = vif->bss_conf.qos, + }, }; struct { struct { @@ -1808,44 +1907,66 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en) int mt7615_driver_own(struct mt7615_dev *dev) { + struct mt76_phy *mphy = &dev->mt76.phy; struct mt76_dev *mdev = &dev->mt76; - u32 addr; + int i; - addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; - mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); + if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) + goto out; mt7622_trigger_hif_int(dev, true); - addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; - if (!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) { - dev_err(dev->mt76.dev, "Timeout for driver own\n"); - return -EIO; + for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) { + u32 addr; + + addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST; + mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN); + + addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; + if (mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 50)) + break; } mt7622_trigger_hif_int(dev, false); + if (i == MT7615_DRV_OWN_RETRY_COUNT) { + dev_err(mdev->dev, "driver own failed\n"); + set_bit(MT76_STATE_PM, &mphy->state); + return -EIO; + } + +out: + dev->pm.last_activity = jiffies; + return 0; } EXPORT_SYMBOL_GPL(mt7615_driver_own); int mt7615_firmware_own(struct mt7615_dev *dev) { + struct mt76_phy *mphy = &dev->mt76.phy; + int err = 0; u32 addr; - addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; + if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) + return 0; + mt7622_trigger_hif_int(dev, true); + addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST; mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN); - if (!is_mt7615(&dev->mt76) && + if (is_mt7622(&dev->mt76) && !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, - MT_CFG_LPCR_HOST_FW_OWN, 3000)) { + MT_CFG_LPCR_HOST_FW_OWN, 300)) { dev_err(dev->mt76.dev, "Timeout for firmware own\n"); - return -EIO; + clear_bit(MT76_STATE_PM, &mphy->state); + err = -EIO; } + mt7622_trigger_hif_int(dev, false); - return 0; + return err; } EXPORT_SYMBOL_GPL(mt7615_firmware_own); @@ -2725,6 +2846,14 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) .center_chan2 = ieee80211_frequency_to_channel(freq2), }; +#ifdef CONFIG_NL80211_TESTMODE + if (dev->mt76.test.state == MT76_TM_STATE_TX_FRAMES && + dev->mt76.test.tx_antenna_mask) { + req.tx_streams = hweight8(dev->mt76.test.tx_antenna_mask); + req.rx_streams_mask = dev->mt76.test.tx_antenna_mask; + } +#endif + if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && @@ -2736,7 +2865,10 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd) req.band_idx = phy != &dev->phy; req.bw = mt7615_mcu_chan_bw(chandef); - mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); + if (mt76_testmode_enabled(&dev->mt76)) + memset(req.txpower_sku, 0x3f, 49); + else + mt7615_mcu_set_txpower_sku(phy, req.txpower_sku); return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true); } @@ -2754,6 +2886,27 @@ int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) sizeof(req), true); } +int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, + u32 val) +{ + struct { + u8 test_mode_en; + u8 param_idx; + u8 _rsv[2]; + + __le32 value; + + u8 pad[8]; + } req = { + .test_mode_en = test_mode, + .param_idx = param, + .value = cpu_to_le32(val), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req, + sizeof(req), false); +} + int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable) { struct mt7615_dev *dev = phy->dev; @@ -3332,43 +3485,8 @@ out: return ret; } -#ifdef CONFIG_PM -int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) -{ - struct { - struct { - u8 hif_type; /* 0x0: HIF_SDIO - * 0x1: HIF_USB - * 0x2: HIF_PCIE - */ - u8 pad[3]; - } __packed hdr; - struct hif_suspend_tlv { - __le16 tag; - __le16 len; - u8 suspend; - } __packed hif_suspend; - } req = { - .hif_suspend = { - .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ - .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), - .suspend = suspend, - }, - }; - - if (mt76_is_mmio(&dev->mt76)) - req.hdr.hif_type = 2; - else if (mt76_is_usb(&dev->mt76)) - req.hdr.hif_type = 1; - - return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, - &req, sizeof(req), true); -} -EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); - -static int -mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, - bool enable) +int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct { @@ -3408,6 +3526,40 @@ mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, &req, sizeof(req), false); } +#ifdef CONFIG_PM +int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend) +{ + struct { + struct { + u8 hif_type; /* 0x0: HIF_SDIO + * 0x1: HIF_USB + * 0x2: HIF_PCIE + */ + u8 pad[3]; + } __packed hdr; + struct hif_suspend_tlv { + __le16 tag; + __le16 len; + u8 suspend; + } __packed hif_suspend; + } req = { + .hif_suspend = { + .tag = cpu_to_le16(0), /* 0: UNI_HIF_CTRL_BASIC */ + .len = cpu_to_le16(sizeof(struct hif_suspend_tlv)), + .suspend = suspend, + }, + }; + + if (mt76_is_mmio(&dev->mt76)) + req.hdr.hif_type = 2; + else if (mt76_is_usb(&dev->mt76)) + req.hdr.hif_type = 1; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend); + static int mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif, bool suspend, struct cfg80211_wowlan *wowlan) @@ -3542,6 +3694,32 @@ mt7615_mcu_set_gtk_rekey(struct mt7615_dev *dev, &req, sizeof(req), true); } +static int +mt7615_mcu_set_arp_filter(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool suspend) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_arpns_tlv arpns; + } req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .arpns = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), + .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), + .mode = suspend, + }, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, + &req, sizeof(req), true); +} + void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { @@ -3554,6 +3732,7 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, mt7615_mcu_set_bss_pm(phy->dev, vif, suspend); mt7615_mcu_set_gtk_rekey(phy->dev, vif, suspend); + mt7615_mcu_set_arp_filter(phy->dev, vif, suspend); mt7615_mcu_set_suspend_mode(phy->dev, vif, suspend, 1, true); @@ -3653,6 +3832,53 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, sizeof(req), false); } +int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info) +{ + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_dev *dev = mt7615_hw_dev(hw); + struct sk_buff *skb; + int i, len = min_t(int, info->arp_addr_cnt, + IEEE80211_BSS_ARP_ADDR_LIST_LEN); + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct mt7615_arpns_tlv arp; + } req_hdr = { + .hdr = { + .bss_idx = mvif->idx, + }, + .arp = { + .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP), + .len = cpu_to_le16(sizeof(struct mt7615_arpns_tlv)), + .ips_num = len, + .mode = 2, /* update */ + .option = 1, + }, + }; + + if (!mt7615_firmware_offload(dev)) + return 0; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, + sizeof(req_hdr) + len * sizeof(__be32)); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req_hdr, sizeof(req_hdr)); + for (i = 0; i < len; i++) { + u8 *addr = (u8 *)skb_put(skb, sizeof(__be32)); + + memcpy(addr, &info->arp_addr_list[i], sizeof(__be32)); + } + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_UNI_CMD_OFFLOAD, true); +} + int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -3674,3 +3900,32 @@ int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw, return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, &req, sizeof(req), false); } + +u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset) +{ + struct { + __le32 addr; + __le32 val; + } __packed req = { + .addr = cpu_to_le32(offset), + }; + + return __mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr); + +void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + struct { + __le32 addr; + __le32 val; + } __packed req = { + .addr = cpu_to_le32(offset), + .val = cpu_to_le32(val), + }; + + __mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, + &req, sizeof(req), false); +} +EXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index 2314d0b23af1..7b856e9eee1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -81,6 +81,7 @@ enum { MCU_EVENT_GENERIC = 0x01, MCU_EVENT_ACCESS_REG = 0x02, MCU_EVENT_MT_PATCH_SEM = 0x04, + MCU_EVENT_REG_ACCESS = 0x05, MCU_EVENT_SCAN_DONE = 0x0d, MCU_EVENT_ROC = 0x10, MCU_EVENT_BSS_ABSENCE = 0x11, @@ -238,8 +239,11 @@ enum { #define MCU_FW_PREFIX BIT(31) #define MCU_UNI_PREFIX BIT(30) #define MCU_CE_PREFIX BIT(29) +#define MCU_QUERY_PREFIX BIT(28) #define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX | \ - MCU_CE_PREFIX) + MCU_CE_PREFIX | MCU_QUERY_PREFIX) + +#define MCU_QUERY_MASK BIT(16) enum { MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01, @@ -254,6 +258,7 @@ enum { }; enum { + MCU_EXT_CMD_RF_REG_ACCESS = 0x02, MCU_EXT_CMD_PM_STATE_CTRL = 0x07, MCU_EXT_CMD_CHANNEL_SWITCH = 0x08, MCU_EXT_CMD_SET_TX_POWER_CTRL = 0x11, @@ -266,6 +271,7 @@ enum { MCU_EXT_CMD_GET_TEMP = 0x2c, MCU_EXT_CMD_WTBL_UPDATE = 0x32, MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, + MCU_EXT_CMD_ATE_CTRL = 0x3d, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, MCU_EXT_CMD_DBDC_CTRL = 0x45, MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, @@ -287,6 +293,11 @@ enum { MCU_UNI_CMD_HIF_CTRL = MCU_UNI_PREFIX | 0x07, }; +enum { + MCU_ATE_SET_FREQ_OFFSET = 0xa, + MCU_ATE_SET_TX_POWER_CONTROL = 0x15, +}; + struct mt7615_mcu_uni_event { u8 cid; u8 pad[3]; @@ -421,6 +432,11 @@ struct nt7615_sched_scan_done { __le16 pad; } __packed; +struct mt7615_mcu_reg_event { + __le32 reg; + __le32 val; +} __packed; + struct mt7615_mcu_bss_event { u8 bss_idx; u8 is_absent; @@ -454,6 +470,13 @@ struct mt7615_bss_basic_tlv { u8 pad[3]; } __packed; +struct mt7615_bss_qos_tlv { + __le16 tag; + __le16 len; + u8 qos; + u8 pad[3]; +} __packed; + struct mt7615_wow_ctrl_tlv { __le16 tag; __le16 len; @@ -545,6 +568,15 @@ struct mt7615_roc_tlv { u8 rsv1[8]; } __packed; +struct mt7615_arpns_tlv { + __le16 tag; + __le16 len; + u8 mode; + u8 ips_num; + u8 option; + u8 pad[1]; +} __packed; + /* offload mcu commands */ enum { MCU_CMD_START_HW_SCAN = MCU_CE_PREFIX | 0x03, @@ -557,6 +589,8 @@ enum { MCU_CMD_SET_P2P_OPPPS = MCU_CE_PREFIX | 0x33, MCU_CMD_SCHED_SCAN_ENABLE = MCU_CE_PREFIX | 0x61, MCU_CMD_SCHED_SCAN_REQ = MCU_CE_PREFIX | 0x62, + MCU_CMD_REG_WRITE = MCU_CE_PREFIX | 0xc0, + MCU_CMD_REG_READ = MCU_CE_PREFIX | MCU_QUERY_MASK | 0xc0, }; #define MCU_CMD_ACK BIT(0) @@ -569,6 +603,8 @@ enum { UNI_BSS_INFO_BASIC = 0, UNI_BSS_INFO_RLM = 2, UNI_BSS_INFO_BCN_CONTENT = 7, + UNI_BSS_INFO_QBSS = 15, + UNI_BSS_INFO_UAPSD = 19, }; enum { @@ -580,8 +616,8 @@ enum { }; enum { - UNI_OFFLOAD_OFFLOAD_ARPNS_IPV4, - UNI_OFFLOAD_OFFLOAD_ARPNS_IPV6, + UNI_OFFLOAD_OFFLOAD_ARP, + UNI_OFFLOAD_OFFLOAD_ND, UNI_OFFLOAD_OFFLOAD_GTK_REKEY, UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT, }; @@ -882,6 +918,7 @@ struct wtbl_raw { sizeof(struct sta_rec_basic) + \ sizeof(struct sta_rec_ht) + \ sizeof(struct sta_rec_vht) + \ + sizeof(struct sta_rec_uapsd) + \ sizeof(struct tlv) + \ MT7615_WTBL_UPDATE_MAX_SIZE) @@ -971,6 +1008,17 @@ struct sta_rec_ba { __le16 winsize; } __packed; +struct sta_rec_uapsd { + __le16 tag; + __le16 len; + u8 dac_map; + u8 tac_map; + u8 max_sp; + u8 rsv0; + __le16 listen_interval; + u8 rsv1[2]; +} __packed; + enum { STA_REC_BASIC, STA_REC_RA, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c index 2e99845b9c96..133f93a6ed1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c @@ -17,7 +17,6 @@ const u32 mt7615e_reg_map[] = { [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, - [MT_PHY_BASE] = 0x10000, [MT_CFG_BASE] = 0x20200, [MT_AGG_BASE] = 0x20a00, [MT_TMAC_BASE] = 0x21000, @@ -44,7 +43,7 @@ const u32 mt7663e_reg_map[] = { [MT_CSR_BASE] = 0x07000, [MT_PLE_BASE] = 0x08000, [MT_PSE_BASE] = 0x0c000, - [MT_PHY_BASE] = 0x10000, + [MT_PP_BASE] = 0x0e000, [MT_CFG_BASE] = 0x20000, [MT_AGG_BASE] = 0x22000, [MT_TMAC_BASE] = 0x24000, @@ -140,6 +139,38 @@ static void mt7615_irq_tasklet(unsigned long data) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +static u32 __mt7615_reg_addr(struct mt7615_dev *dev, u32 addr) +{ + if (addr < 0x100000) + return addr; + + return mt7615_reg_map(dev, addr); +} + +static u32 mt7615_rr(struct mt76_dev *mdev, u32 offset) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + u32 addr = __mt7615_reg_addr(dev, offset); + + return dev->bus_ops->rr(mdev, addr); +} + +static void mt7615_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + u32 addr = __mt7615_reg_addr(dev, offset); + + dev->bus_ops->wr(mdev, addr, val); +} + +static u32 mt7615_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + u32 addr = __mt7615_reg_addr(dev, offset); + + return dev->bus_ops->rmw(mdev, addr, mask, val); +} + int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq, const u32 *map) { @@ -159,6 +190,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, .sta_remove = mt7615_mac_sta_remove, .update_survey = mt7615_update_channel, }; + struct mt76_bus_ops *bus_ops; struct ieee80211_ops *ops; struct mt7615_dev *dev; struct mt76_dev *mdev; @@ -182,6 +214,19 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + dev->bus_ops = dev->mt76.bus; + bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops), + GFP_KERNEL); + if (!bus_ops) { + ret = -ENOMEM; + goto error; + } + + bus_ops->rr = mt7615_rr; + bus_ops->wr = mt7615_wr; + bus_ops->rmw = mt7615_rmw; + dev->mt76.bus = bus_ops; + ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 3e7d51bf42a4..571eadc033a3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -4,6 +4,7 @@ #ifndef __MT7615_H #define __MT7615_H +#include <linux/completion.h> #include <linux/interrupt.h> #include <linux/ktime.h> #include <linux/regmap.h> @@ -18,6 +19,7 @@ #define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \ MT7615_MAX_INTERFACES) +#define MT7615_PM_TIMEOUT (HZ / 12) #define MT7615_WATCHDOG_TIME (HZ / 10) #define MT7615_HW_SCAN_TIMEOUT (HZ / 10) #define MT7615_RESET_TIMEOUT (30 * HZ) @@ -31,6 +33,8 @@ #define MT7615_RX_RING_SIZE 1024 #define MT7615_RX_MCU_RING_SIZE 512 +#define MT7615_DRV_OWN_RETRY_COUNT 10 + #define MT7615_FIRMWARE_CR4 "mediatek/mt7615_cr4.bin" #define MT7615_FIRMWARE_N9 "mediatek/mt7615_n9.bin" #define MT7615_ROM_PATCH "mediatek/mt7615_rom_patch.bin" @@ -169,6 +173,8 @@ struct mt7615_phy { struct mt76_phy *mt76; struct mt7615_dev *dev; + struct ieee80211_vif *monitor_vif; + u32 rxfilter; u32 omac_mask; @@ -240,10 +246,10 @@ struct mt7615_dev { struct mt76_phy mphy; }; + const struct mt76_bus_ops *bus_ops; struct tasklet_struct irq_tasklet; struct mt7615_phy phy; - u32 vif_mask; u32 omac_mask; u16 chainmask; @@ -280,6 +286,37 @@ struct mt7615_dev { struct work_struct wtbl_work; struct list_head wd_head; + + u32 debugfs_rf_wf; + u32 debugfs_rf_reg; + +#ifdef CONFIG_NL80211_TESTMODE + struct { + u32 *reg_backup; + + s16 last_freq_offset; + u8 last_rcpi[4]; + s8 last_ib_rssi; + s8 last_wb_rssi; + } test; +#endif + + struct { + bool enable; + + spinlock_t txq_lock; + struct { + struct mt7615_sta *msta; + struct sk_buff *skb; + } tx_q[IEEE80211_NUM_ACS]; + + struct work_struct wake_work; + struct completion wake_cmpl; + + struct delayed_work ps_work; + unsigned long last_activity; + unsigned long idle_timeout; + } pm; }; enum tx_pkt_queue_idx { @@ -372,8 +409,10 @@ extern struct ieee80211_rate mt7615_rates[12]; extern const struct ieee80211_ops mt7615_ops; extern const u32 mt7615e_reg_map[__MT_BASE_MAX]; extern const u32 mt7663e_reg_map[__MT_BASE_MAX]; +extern const u32 mt7663_usb_sdio_reg_map[__MT_BASE_MAX]; extern struct pci_driver mt7615_pci_driver; extern struct platform_driver mt7622_wmac_driver; +extern const struct mt76_testmode_ops mt7615_testmode_ops; #ifdef CONFIG_MT7622_WMAC int mt7622_wmac_init(struct mt7615_dev *dev); @@ -408,6 +447,11 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev); void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); +int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable); +void mt7615_pm_wake_work(struct work_struct *work); +int mt7615_pm_wake(struct mt7615_dev *dev); +void mt7615_pm_power_save_sched(struct mt7615_dev *dev); +void mt7615_pm_power_save_work(struct work_struct *work); int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev); int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd); int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, @@ -462,6 +506,20 @@ static inline u16 mt7615_wtbl_size(struct mt7615_dev *dev) return MT7615_WTBL_SIZE; } +static inline void mt7615_mutex_acquire(struct mt7615_dev *dev) + __acquires(&dev->mt76.mutex) +{ + mutex_lock(&dev->mt76.mutex); + mt7615_pm_wake(dev); +} + +static inline void mt7615_mutex_release(struct mt7615_dev *dev) + __releases(&dev->mt76.mutex) +{ + mt7615_pm_power_save_sched(dev); + mutex_unlock(&dev->mt76.mutex); +} + static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac) { static const u8 lmac_queue_map[] = { @@ -485,6 +543,7 @@ void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband); void mt7615_phy_init(struct mt7615_dev *dev); void mt7615_mac_init(struct mt7615_dev *dev); +int mt7615_set_channel(struct mt7615_phy *phy); int mt7615_mcu_restart(struct mt76_dev *dev); void mt7615_update_channel(struct mt76_dev *mdev); @@ -516,15 +575,19 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, enum mt7615_cipher_type cipher, enum set_key_cmd cmd); void mt7615_mac_reset_work(struct work_struct *work); +u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int len, bool wait_resp); +u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg); +int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val); int mt7615_mcu_set_dbdc(struct mt7615_dev *dev); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable); int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val); int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); +int mt7615_mcu_set_tx_power(struct mt7615_phy *phy); void mt7615_mcu_exit(struct mt7615_dev *dev); void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq); @@ -563,6 +626,8 @@ int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev, const struct mt7615_dfs_pulse *pulse); int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index, const struct mt7615_dfs_pattern *pattern); +int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode, + u32 val); int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); @@ -579,18 +644,40 @@ int mt7615_driver_own(struct mt7615_dev *dev); int mt7615_init_debugfs(struct mt7615_dev *dev); int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq); +int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif, + bool enable); int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend); void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_gtk_rekey_data *key); - +int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info); int __mt7663_load_firmware(struct mt7615_dev *dev); +u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset); +void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val); /* usb */ -void mt7663u_wtbl_work(struct work_struct *work); +int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info); +bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update); +void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, + enum mt76_txq_id qid, + struct mt76_queue_entry *e); +void mt7663_usb_sdio_wtbl_work(struct work_struct *work); +int mt7663_usb_sdio_register_device(struct mt7615_dev *dev); int mt7663u_mcu_init(struct mt7615_dev *dev); -int mt7663u_register_device(struct mt7615_dev *dev); + +/* sdio */ +u32 mt7663s_read_pcr(struct mt7615_dev *dev); +int mt7663s_mcu_init(struct mt7615_dev *dev); +int mt7663s_driver_own(struct mt7615_dev *dev); +int mt7663s_firmware_own(struct mt7615_dev *dev); +int mt7663s_kthread_run(void *data); +void mt7663s_sdio_irq(struct sdio_func *func); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index ba12f199bce0..2328d78e06a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -75,6 +75,10 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state) bool hif_suspend; int i, err; + err = mt7615_pm_wake(dev); + if (err < 0) + return err; + hif_suspend = !test_bit(MT76_STATE_SUSPEND, &dev->mphy.state) && mt7615_firmware_offload(dev); if (hif_suspend) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index 69cba8609edf..7224a0078211 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -70,6 +70,10 @@ mt7615_led_set_config(struct led_classdev *led_cdev, mt76 = container_of(led_cdev, struct mt76_dev, led_cdev); dev = container_of(mt76, struct mt7615_dev, mt76); + + if (test_bit(MT76_STATE_PM, &mt76->phy.state)) + return; + val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | FIELD_PREP(MT_LED_STATUS_ON, delay_on); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 7ec91c0856f5..2d67f9a148cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -155,7 +155,6 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, spin_lock_bh(&dev->mt76.lock); mt7615_mac_set_rates(phy, msta, &info->control.rates[0], msta->rates); - msta->rate_probe = true; spin_unlock_bh(&dev->mt76.lock); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index aee433a9eff6..9137d9e6b51d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -14,7 +14,6 @@ enum mt7615_reg_base { MT_CSR_BASE, MT_PLE_BASE, MT_PSE_BASE, - MT_PHY_BASE, MT_CFG_BASE, MT_AGG_BASE, MT_TMAC_BASE, @@ -29,6 +28,7 @@ enum mt7615_reg_base { MT_PCIE_REMAP_BASE2, MT_TOP_MISC_BASE, MT_EFUSE_ADDR_BASE, + MT_PP_BASE, __MT_BASE_MAX, }; @@ -153,6 +153,8 @@ enum mt7615_reg_base { #define MT_PLE(ofs) ((dev)->reg_map[MT_PLE_BASE] + (ofs)) +#define MT_PLE_PG_HIF0_GROUP MT_PLE(0x110) +#define MT_HIF0_MIN_QUOTA GENMASK(11, 0) #define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) #define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) #define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) @@ -162,6 +164,10 @@ enum mt7615_reg_base { ((n) << 2)) #define MT_PSE(ofs) ((dev)->reg_map[MT_PSE_BASE] + (ofs)) +#define MT_PSE_PG_HIF0_GROUP MT_PSE(0x110) +#define MT_HIF0_MIN_QUOTA GENMASK(11, 0) +#define MT_PSE_PG_HIF1_GROUP MT_PSE(0x118) +#define MT_HIF1_MIN_QUOTA GENMASK(11, 0) #define MT_PSE_QUEUE_EMPTY MT_PSE(0x0b4) #define MT_HIF_0_EMPTY_MASK BIT(16) #define MT_HIF_1_EMPTY_MASK BIT(17) @@ -169,7 +175,12 @@ enum mt7615_reg_base { #define MT_PSE_PG_INFO MT_PSE(0x194) #define MT_PSE_SRC_CNT GENMASK(27, 16) -#define MT_WF_PHY_BASE ((dev)->reg_map[MT_PHY_BASE]) +#define MT_PP(ofs) ((dev)->reg_map[MT_PP_BASE] + (ofs)) +#define MT_PP_TXDWCNT MT_PP(0x0) +#define MT_PP_TXDWCNT_TX0_ADD_DW_CNT GENMASK(7, 0) +#define MT_PP_TXDWCNT_TX1_ADD_DW_CNT GENMASK(15, 8) + +#define MT_WF_PHY_BASE 0x82070000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) #define MT_WF_PHY_WF2_RFCTRL0(n) MT_WF_PHY(0x1900 + (n) * 0x400) @@ -213,6 +224,9 @@ enum mt7615_reg_base { #define MT_WF_PHY_RXTD2_BASE MT_WF_PHY(0x2a00) #define MT_WF_PHY_RXTD2(_n) (MT_WF_PHY_RXTD2_BASE + ((_n) << 2)) +#define MT_WF_PHY_RFINTF3_0(_n) MT_WF_PHY(0x1100 + (_n) * 0x400) +#define MT_WF_PHY_RFINTF3_0_ANT GENMASK(7, 4) + #define MT_WF_CFG_BASE ((dev)->reg_map[MT_CFG_BASE]) #define MT_WF_CFG(ofs) (MT_WF_CFG_BASE + (ofs)) @@ -256,6 +270,13 @@ enum mt7615_reg_base { #define MT_WF_ARB_BASE ((dev)->reg_map[MT_ARB_BASE]) #define MT_WF_ARB(ofs) (MT_WF_ARB_BASE + (ofs)) +#define MT_ARB_RQCR MT_WF_ARB(0x070) +#define MT_ARB_RQCR_RX_START BIT(0) +#define MT_ARB_RQCR_RXV_START BIT(4) +#define MT_ARB_RQCR_RXV_R_EN BIT(7) +#define MT_ARB_RQCR_RXV_T_EN BIT(8) +#define MT_ARB_RQCR_BAND_SHIFT 16 + #define MT_ARB_SCR MT_WF_ARB(0x080) #define MT_ARB_SCR_TX0_DISABLE BIT(8) #define MT_ARB_SCR_RX0_DISABLE BIT(9) @@ -417,6 +438,7 @@ enum mt7615_reg_base { #define MT_LPON_T0CR MT_LPON(0x010) #define MT_LPON_T0CR_MODE GENMASK(1, 0) +#define MT_LPON_T0CR_WRITE BIT(0) #define MT_LPON_UTTR0 MT_LPON(0x018) #define MT_LPON_UTTR1 MT_LPON(0x01c) @@ -550,4 +572,11 @@ enum mt7615_reg_base { #define MT_WL_RX_BUSY BIT(30) #define MT_WL_TX_BUSY BIT(31) +#define MT_MCU_PTA_BASE 0x81060000 +#define MT_MCU_PTA(_n) (MT_MCU_PTA_BASE + (_n)) + +#define MT_ANT_SWITCH_CON(n) MT_MCU_PTA(0x0c8) +#define MT_ANT_SWITCH_CON_MODE(_n) (GENMASK(4, 0) << (_n * 8)) +#define MT_ANT_SWITCH_CON_MODE1(_n) (GENMASK(3, 0) << (_n * 8)) + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c new file mode 100644 index 000000000000..dabce51117b0 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau <nbd@nbd.name> + * Lorenzo Bianconi <lorenzo@kernel.org> + * Sean Wang <sean.wang@mediatek.com> + */ + +#include <linux/kernel.h> +#include <linux/iopoll.h> +#include <linux/module.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio_func.h> + +#include "mt7615.h" +#include "sdio.h" +#include "mac.h" + +static const struct sdio_device_id mt7663s_table[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7603) }, + { } /* Terminating entry */ +}; + +static u32 mt7663s_read_whisr(struct mt76_dev *dev) +{ + return sdio_readl(dev->sdio.func, MCR_WHISR, NULL); +} + +u32 mt7663s_read_pcr(struct mt7615_dev *dev) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + + return sdio_readl(sdio->func, MCR_WHLPCR, NULL); +} + +static u32 mt7663s_read_mailbox(struct mt76_dev *dev, u32 offset) +{ + struct sdio_func *func = dev->sdio.func; + u32 val = ~0, status; + int err; + + sdio_claim_host(func); + + sdio_writel(func, offset, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting address [err=%d]\n", err); + goto out; + } + + sdio_writel(func, H2D_SW_INT_READ, MCR_WSICR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); + goto out; + } + + err = readx_poll_timeout(mt7663s_read_whisr, dev, status, + status & H2D_SW_INT_READ, 0, 1000000); + if (err < 0) { + dev_err(dev->dev, "query whisr timeout\n"); + goto out; + } + + sdio_writel(func, H2D_SW_INT_READ, MCR_WHISR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting read mode [err=%d]\n", err); + goto out; + } + + val = sdio_readl(func, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); + goto out; + } + + if (val != offset) { + dev_err(dev->dev, "register mismatch\n"); + val = ~0; + goto out; + } + + val = sdio_readl(func, MCR_D2HRM1R, &err); + if (err < 0) + dev_err(dev->dev, "failed reading d2hrm1r [err=%d]\n", err); + +out: + sdio_release_host(func); + + return val; +} + +static void mt7663s_write_mailbox(struct mt76_dev *dev, u32 offset, u32 val) +{ + struct sdio_func *func = dev->sdio.func; + u32 status; + int err; + + sdio_claim_host(func); + + sdio_writel(func, offset, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting address [err=%d]\n", err); + goto out; + } + + sdio_writel(func, val, MCR_H2DSM1R, &err); + if (err < 0) { + dev_err(dev->dev, + "failed setting write value [err=%d]\n", err); + goto out; + } + + sdio_writel(func, H2D_SW_INT_WRITE, MCR_WSICR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); + goto out; + } + + err = readx_poll_timeout(mt7663s_read_whisr, dev, status, + status & H2D_SW_INT_WRITE, 0, 1000000); + if (err < 0) { + dev_err(dev->dev, "query whisr timeout\n"); + goto out; + } + + sdio_writel(func, H2D_SW_INT_WRITE, MCR_WHISR, &err); + if (err < 0) { + dev_err(dev->dev, "failed setting write mode [err=%d]\n", err); + goto out; + } + + val = sdio_readl(func, MCR_H2DSM0R, &err); + if (err < 0) { + dev_err(dev->dev, "failed reading h2dsm0r [err=%d]\n", err); + goto out; + } + + if (val != offset) + dev_err(dev->dev, "register mismatch\n"); + +out: + sdio_release_host(func); +} + +static u32 mt7663s_rr(struct mt76_dev *dev, u32 offset) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) + return dev->mcu_ops->mcu_rr(dev, offset); + else + return mt7663s_read_mailbox(dev, offset); +} + +static void mt7663s_wr(struct mt76_dev *dev, u32 offset, u32 val) +{ + if (test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) + dev->mcu_ops->mcu_wr(dev, offset, val); + else + mt7663s_write_mailbox(dev, offset, val); +} + +static u32 mt7663s_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) +{ + val |= mt7663s_rr(dev, offset) & ~mask; + mt7663s_wr(dev, offset, val); + + return val; +} + +static void mt7663s_write_copy(struct mt76_dev *dev, u32 offset, + const void *data, int len) +{ + const u32 *val = data; + int i; + + for (i = 0; i < len / sizeof(u32); i++) { + mt7663s_wr(dev, offset, val[i]); + offset += sizeof(u32); + } +} + +static void mt7663s_read_copy(struct mt76_dev *dev, u32 offset, + void *data, int len) +{ + u32 *val = data; + int i; + + for (i = 0; i < len / sizeof(u32); i++) { + val[i] = mt7663s_rr(dev, offset); + offset += sizeof(u32); + } +} + +static int mt7663s_wr_rp(struct mt76_dev *dev, u32 base, + const struct mt76_reg_pair *data, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + mt7663s_wr(dev, data->reg, data->value); + data++; + } + + return 0; +} + +static int mt7663s_rd_rp(struct mt76_dev *dev, u32 base, + struct mt76_reg_pair *data, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + data->value = mt7663s_rr(dev, data->reg); + data++; + } + + return 0; +} + +static void mt7663s_init_work(struct work_struct *work) +{ + struct mt7615_dev *dev; + + dev = container_of(work, struct mt7615_dev, mcu_work); + if (mt7663s_mcu_init(dev)) + return; + + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); + mt7615_check_offload_capability(dev); +} + +static int mt7663s_hw_init(struct mt7615_dev *dev, struct sdio_func *func) +{ + u32 status, ctrl; + int ret; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret < 0) + goto release; + + /* Get ownership from the device */ + sdio_writel(func, WHLPCR_INT_EN_CLR | WHLPCR_FW_OWN_REQ_CLR, + MCR_WHLPCR, &ret); + if (ret < 0) + goto disable_func; + + ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + if (ret < 0) { + dev_err(dev->mt76.dev, "Cannot get ownership from device"); + goto disable_func; + } + + ret = sdio_set_block_size(func, 512); + if (ret < 0) + goto disable_func; + + /* Enable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, &ret); + if (ret < 0) + goto disable_func; + + ctrl = WHIER_RX0_DONE_INT_EN | WHIER_TX_DONE_INT_EN; + sdio_writel(func, ctrl, MCR_WHIER, &ret); + if (ret < 0) + goto disable_func; + + /* set WHISR as read clear and Rx aggregation number as 16 */ + ctrl = FIELD_PREP(MAX_HIF_RX_LEN_NUM, 16); + sdio_writel(func, ctrl, MCR_WHCR, &ret); + if (ret < 0) + goto disable_func; + + ret = sdio_claim_irq(func, mt7663s_sdio_irq); + if (ret < 0) + goto disable_func; + + sdio_release_host(func); + + return 0; + +disable_func: + sdio_disable_func(func); +release: + sdio_release_host(func); + + return ret; +} + +static int mt7663s_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_sdio *sdio = &mdev->sdio; + u32 pse, ple; + int err; + + err = mt7615_mac_sta_add(mdev, vif, sta); + if (err < 0) + return err; + + /* init sched data quota */ + pse = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + + mutex_lock(&sdio->sched.lock); + sdio->sched.pse_data_quota = pse; + sdio->sched.ple_data_quota = ple; + mutex_unlock(&sdio->sched.lock); + + return 0; +} + +static int mt7663s_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + static const struct mt76_driver_ops drv_ops = { + .txwi_size = MT_USB_TXD_SIZE, + .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ, + .tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb, + .tx_complete_skb = mt7663_usb_sdio_tx_complete_skb, + .tx_status_data = mt7663_usb_sdio_tx_status_data, + .rx_skb = mt7615_queue_rx_skb, + .sta_ps = mt7615_sta_ps, + .sta_add = mt7663s_sta_add, + .sta_remove = mt7615_mac_sta_remove, + .update_survey = mt7615_update_channel, + }; + static const struct mt76_bus_ops mt7663s_ops = { + .rr = mt7663s_rr, + .rmw = mt7663s_rmw, + .wr = mt7663s_wr, + .write_copy = mt7663s_write_copy, + .read_copy = mt7663s_read_copy, + .wr_rp = mt7663s_wr_rp, + .rd_rp = mt7663s_rd_rp, + .type = MT76_BUS_SDIO, + }; + struct ieee80211_ops *ops; + struct mt7615_dev *dev; + struct mt76_dev *mdev; + int ret; + + ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops), + GFP_KERNEL); + if (!ops) + return -ENOMEM; + + mdev = mt76_alloc_device(&func->dev, sizeof(*dev), ops, &drv_ops); + if (!mdev) + return -ENOMEM; + + dev = container_of(mdev, struct mt7615_dev, mt76); + + INIT_WORK(&dev->mcu_work, mt7663s_init_work); + dev->reg_map = mt7663_usb_sdio_reg_map; + dev->ops = ops; + sdio_set_drvdata(func, dev); + + mdev->sdio.tx_kthread = kthread_create(mt7663s_kthread_run, dev, + "mt7663s_tx"); + if (IS_ERR(mdev->sdio.tx_kthread)) + return PTR_ERR(mdev->sdio.tx_kthread); + + ret = mt76s_init(mdev, func, &mt7663s_ops); + if (ret < 0) + goto err_free; + + ret = mt7663s_hw_init(dev, func); + if (ret) + goto err_free; + + mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | + (mt76_rr(dev, MT_HW_REV) & 0xff); + dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); + + ret = mt76s_alloc_queues(&dev->mt76); + if (ret) + goto err_deinit; + + ret = mt7663_usb_sdio_register_device(dev); + if (ret) + goto err_deinit; + + return 0; + +err_deinit: + mt76s_deinit(&dev->mt76); +err_free: + mt76_free_device(&dev->mt76); + + return ret; +} + +static void mt7663s_remove(struct sdio_func *func) +{ + struct mt7615_dev *dev = sdio_get_drvdata(func); + + if (!test_and_clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + return; + + ieee80211_unregister_hw(dev->mt76.hw); + mt76s_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); +} + +#ifdef CONFIG_PM +static int mt7663s_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct mt7615_dev *mdev = sdio_get_drvdata(func); + + if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && + mt7615_firmware_offload(mdev)) { + int err; + + err = mt7615_mcu_set_hif_suspend(mdev, true); + if (err < 0) + return err; + } + + mt76s_stop_txrx(&mdev->mt76); + + return mt7663s_firmware_own(mdev); +} + +static int mt7663s_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct mt7615_dev *mdev = sdio_get_drvdata(func); + int err; + + err = mt7663s_driver_own(mdev); + if (err) + return err; + + if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) && + mt7615_firmware_offload(mdev)) + err = mt7615_mcu_set_hif_suspend(mdev, false); + + return err; +} + +static const struct dev_pm_ops mt7663s_pm_ops = { + .suspend = mt7663s_suspend, + .resume = mt7663s_resume, +}; +#endif + +MODULE_DEVICE_TABLE(sdio, mt7663s_table); +MODULE_FIRMWARE(MT7663_OFFLOAD_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_OFFLOAD_ROM_PATCH); +MODULE_FIRMWARE(MT7663_FIRMWARE_N9); +MODULE_FIRMWARE(MT7663_ROM_PATCH); + +static struct sdio_driver mt7663s_driver = { + .name = KBUILD_MODNAME, + .probe = mt7663s_probe, + .remove = mt7663s_remove, + .id_table = mt7663s_table, +#ifdef CONFIG_PM + .drv = { + .pm = &mt7663s_pm_ops, + } +#endif +}; +module_sdio_driver(mt7663s_driver); + +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h new file mode 100644 index 000000000000..05180971de84 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.h @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Sean Wang <sean.wang@mediatek.com> + */ + +#ifndef __MT76S_H +#define __MT76S_H + +#define MT_PSE_PAGE_SZ 128 + +#define MCR_WCIR 0x0000 +#define MCR_WHLPCR 0x0004 +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +#define MCR_WSDIOCSR 0x0008 +#define MCR_WHCR 0x000C +#define W_INT_CLR_CTRL BIT(1) +#define RECV_MAILBOX_RD_CLR_EN BIT(2) +#define MAX_HIF_RX_LEN_NUM GENMASK(13, 8) +#define RX_ENHANCE_MODE BIT(16) + +#define MCR_WHISR 0x0010 +#define MCR_WHIER 0x0014 +#define WHIER_D2H_SW_INT GENMASK(31, 8) +#define WHIER_FW_OWN_BACK_INT_EN BIT(7) +#define WHIER_ABNORMAL_INT_EN BIT(6) +#define WHIER_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT (WHIER_RX0_DONE_INT_EN | \ + WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | \ + WHIER_ABNORMAL_INT_EN | \ + WHIER_D2H_SW_INT) + +#define MCR_WASR 0x0020 +#define MCR_WSICR 0x0024 +#define MCR_WTSR0 0x0028 +#define TQ0_CNT GENMASK(7, 0) +#define TQ1_CNT GENMASK(15, 8) +#define TQ2_CNT GENMASK(23, 16) +#define TQ3_CNT GENMASK(31, 24) + +#define MCR_WTSR1 0x002c +#define TQ4_CNT GENMASK(7, 0) +#define TQ5_CNT GENMASK(15, 8) +#define TQ6_CNT GENMASK(23, 16) +#define TQ7_CNT GENMASK(31, 24) + +#define MCR_WTDR1 0x0034 +#define MCR_WRDR0 0x0050 +#define MCR_WRDR1 0x0054 +#define MCR_WRDR(p) (0x0050 + 4 * (p)) +#define MCR_H2DSM0R 0x0070 +#define H2D_SW_INT_READ BIT(16) +#define H2D_SW_INT_WRITE BIT(17) + +#define MCR_H2DSM1R 0x0074 +#define MCR_D2HRM0R 0x0078 +#define MCR_D2HRM1R 0x007c +#define MCR_D2HRM2R 0x0080 +#define MCR_WRPLR 0x0090 +#define RX0_PACKET_LENGTH GENMASK(15, 0) +#define RX1_PACKET_LENGTH GENMASK(31, 16) + +#define MCR_WTMDR 0x00b0 +#define MCR_WTMCR 0x00b4 +#define MCR_WTMDPCR0 0x00b8 +#define MCR_WTMDPCR1 0x00bc +#define MCR_WPLRCR 0x00d4 +#define MCR_WSR 0x00D8 +#define MCR_CLKIOCR 0x0100 +#define MCR_CMDIOCR 0x0104 +#define MCR_DAT0IOCR 0x0108 +#define MCR_DAT1IOCR 0x010C +#define MCR_DAT2IOCR 0x0110 +#define MCR_DAT3IOCR 0x0114 +#define MCR_CLKDLYCR 0x0118 +#define MCR_CMDDLYCR 0x011C +#define MCR_ODATDLYCR 0x0120 +#define MCR_IDATDLYCR1 0x0124 +#define MCR_IDATDLYCR2 0x0128 +#define MCR_ILCHCR 0x012C +#define MCR_WTQCR0 0x0130 +#define MCR_WTQCR1 0x0134 +#define MCR_WTQCR2 0x0138 +#define MCR_WTQCR3 0x013C +#define MCR_WTQCR4 0x0140 +#define MCR_WTQCR5 0x0144 +#define MCR_WTQCR6 0x0148 +#define MCR_WTQCR7 0x014C +#define MCR_WTQCR(x) (0x130 + 4 * (x)) +#define TXQ_CNT_L GENMASK(15, 0) +#define TXQ_CNT_H GENMASK(31, 16) + +#define MCR_SWPCDBGR 0x0154 + +struct mt76s_intr { + u32 isr; + struct { + u32 wtqcr[8]; + } tx; + struct { + u16 num[2]; + u16 len[2][16]; + } rx; + u32 rec_mb[2]; +} __packed; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c new file mode 100644 index 000000000000..28b86bec7fc2 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau <nbd@nbd.name> + * Lorenzo Bianconi <lorenzo@kernel.org> + * Sean Wang <sean.wang@mediatek.com> + */ +#include <linux/kernel.h> +#include <linux/mmc/sdio_func.h> +#include <linux/module.h> +#include <linux/iopoll.h> + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" +#include "sdio.h" + +static int mt7663s_mcu_init_sched(struct mt7615_dev *dev) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + u32 pse0, ple, pse1, txdwcnt; + + pse0 = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + pse1 = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, MT_HIF1_MIN_QUOTA); + ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA); + txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT, + MT_PP_TXDWCNT_TX1_ADD_DW_CNT); + + mutex_lock(&sdio->sched.lock); + + sdio->sched.pse_data_quota = pse0; + sdio->sched.ple_data_quota = ple; + sdio->sched.pse_mcu_quota = pse1; + sdio->sched.deficit = txdwcnt << 2; + + mutex_unlock(&sdio->sched.lock); + + return 0; +} + +static int +mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, + int cmd, bool wait_resp) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + int ret, seq; + + mutex_lock(&mdev->mcu.mutex); + + mt7615_mcu_fill_msg(dev, skb, cmd, &seq); + ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0); + if (ret) + goto out; + + mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU].q); + if (wait_resp) + ret = mt7615_mcu_wait_response(dev, cmd, seq); + +out: + mutex_unlock(&mdev->mcu.mutex); + + return ret; +} + +int mt7663s_driver_own(struct mt7615_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + u32 status; + int ret; + + if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state)) + goto out; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, 0); + + ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000); + if (ret < 0) { + dev_err(dev->mt76.dev, "Cannot get ownership from device"); + set_bit(MT76_STATE_PM, &mphy->state); + sdio_release_host(func); + + return ret; + } + + sdio_release_host(func); + +out: + dev->pm.last_activity = jiffies; + + return 0; +} + +int mt7663s_firmware_own(struct mt7615_dev *dev) +{ + struct sdio_func *func = dev->mt76.sdio.func; + struct mt76_phy *mphy = &dev->mt76.phy; + u32 status; + int ret; + + if (test_and_set_bit(MT76_STATE_PM, &mphy->state)) + return 0; + + sdio_claim_host(func); + + sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, 0); + + ret = readx_poll_timeout(mt7663s_read_pcr, dev, status, + !(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000); + if (ret < 0) { + dev_err(dev->mt76.dev, "Cannot set ownership to device"); + clear_bit(MT76_STATE_PM, &mphy->state); + } + + sdio_release_host(func); + + return ret; +} + +int mt7663s_mcu_init(struct mt7615_dev *dev) +{ + static const struct mt76_mcu_ops mt7663s_mcu_ops = { + .headroom = sizeof(struct mt7615_mcu_txd), + .tailroom = MT_USB_TAIL_SIZE, + .mcu_skb_send_msg = mt7663s_mcu_send_message, + .mcu_send_msg = mt7615_mcu_msg_send, + .mcu_restart = mt7615_mcu_restart, + .mcu_rr = mt7615_mcu_reg_rr, + .mcu_wr = mt7615_mcu_reg_wr, + }; + int ret; + + ret = mt7663s_driver_own(dev); + if (ret) + return ret; + + dev->mt76.mcu_ops = &mt7663s_mcu_ops, + + ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY); + if (ret) { + mt7615_mcu_restart(&dev->mt76); + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, + MT_TOP_MISC2_FW_N9_RDY, 0, 500)) + return -EIO; + } + + ret = __mt7663_load_firmware(dev); + if (ret) + return ret; + + ret = mt7663s_mcu_init_sched(dev); + if (ret) + return ret; + + set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c new file mode 100644 index 000000000000..443a4ecdad3a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Felix Fietkau <nbd@nbd.name> + * Lorenzo Bianconi <lorenzo@kernel.org> + * Sean Wang <sean.wang@mediatek.com> + */ + +#include <linux/kernel.h> +#include <linux/iopoll.h> +#include <linux/module.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio_func.h> + +#include "../trace.h" +#include "mt7615.h" +#include "sdio.h" +#include "mac.h" + +static void mt7663s_refill_sched_quota(struct mt7615_dev *dev, u32 *data) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + + mutex_lock(&sdio->sched.lock); + sdio->sched.pse_data_quota += FIELD_GET(TXQ_CNT_L, data[0]) + /* BK */ + FIELD_GET(TXQ_CNT_H, data[0]) + /* BE */ + FIELD_GET(TXQ_CNT_L, data[1]) + /* VI */ + FIELD_GET(TXQ_CNT_H, data[1]); /* VO */ + sdio->sched.ple_data_quota += FIELD_GET(TXQ_CNT_H, data[2]) + /* BK */ + FIELD_GET(TXQ_CNT_L, data[3]) + /* BE */ + FIELD_GET(TXQ_CNT_H, data[3]) + /* VI */ + FIELD_GET(TXQ_CNT_L, data[4]); /* VO */ + sdio->sched.pse_mcu_quota += FIELD_GET(TXQ_CNT_L, data[2]); + mutex_unlock(&sdio->sched.lock); +} + +static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len, + int buf_len) +{ + int len = min_t(int, data_len, MT_SKB_HEAD_LEN); + struct sk_buff *skb; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return NULL; + + skb_put_data(skb, data, len); + if (data_len > len) { + struct page *page; + + data += len; + page = virt_to_head_page(data); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + page, data - page_address(page), + data_len - len, buf_len); + get_page(page); + } + + return skb; +} + +static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid, + struct mt76s_intr *intr) +{ + struct mt76_queue *q = &dev->mt76.q_rx[qid]; + struct mt76_sdio *sdio = &dev->mt76.sdio; + int len = 0, err, i, order; + struct page *page; + u8 *buf; + + for (i = 0; i < intr->rx.num[qid]; i++) + len += round_up(intr->rx.len[qid][i] + 4, 4); + + if (!len) + return 0; + + if (len > sdio->func->cur_blksize) + len = roundup(len, sdio->func->cur_blksize); + + order = get_order(len); + page = __dev_alloc_pages(GFP_KERNEL, order); + if (!page) + return -ENOMEM; + + buf = page_address(page); + + err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len); + if (err < 0) { + dev_err(dev->mt76.dev, "sdio read data failed:%d\n", err); + __free_pages(page, order); + return err; + } + + for (i = 0; i < intr->rx.num[qid]; i++) { + int index = (q->tail + i) % q->ndesc; + struct mt76_queue_entry *e = &q->entry[index]; + + len = intr->rx.len[qid][i]; + e->skb = mt7663s_build_rx_skb(buf, len, round_up(len + 4, 4)); + if (!e->skb) + break; + + buf += round_up(len + 4, 4); + if (q->queued + i + 1 == q->ndesc) + break; + } + __free_pages(page, order); + + spin_lock_bh(&q->lock); + q->tail = (q->tail + i) % q->ndesc; + q->queued += i; + spin_unlock_bh(&q->lock); + + return err; +} + +static int mt7663s_tx_update_sched(struct mt7615_dev *dev, + struct mt76_queue_entry *e, + bool mcu) +{ + struct mt76_sdio *sdio = &dev->mt76.sdio; + struct mt76_phy *mphy = &dev->mt76.phy; + struct ieee80211_hdr *hdr; + int size, ret = -EBUSY; + + size = DIV_ROUND_UP(e->buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ); + + if (mcu) { + if (!test_bit(MT76_STATE_MCU_RUNNING, &mphy->state)) + return 0; + + mutex_lock(&sdio->sched.lock); + if (sdio->sched.pse_mcu_quota > size) { + sdio->sched.pse_mcu_quota -= size; + ret = 0; + } + mutex_unlock(&sdio->sched.lock); + + return ret; + } + + hdr = (struct ieee80211_hdr *)(e->skb->data + MT_USB_TXD_SIZE); + if (ieee80211_is_ctl(hdr->frame_control)) + return 0; + + mutex_lock(&sdio->sched.lock); + if (sdio->sched.pse_data_quota > size && + sdio->sched.ple_data_quota > 0) { + sdio->sched.pse_data_quota -= size; + sdio->sched.ple_data_quota--; + ret = 0; + } + mutex_unlock(&sdio->sched.lock); + + return ret; +} + +static int mt7663s_tx_run_queue(struct mt7615_dev *dev, struct mt76_queue *q) +{ + bool mcu = q == dev->mt76.q_tx[MT_TXQ_MCU].q; + struct mt76_sdio *sdio = &dev->mt76.sdio; + int nframes = 0; + + while (q->first != q->tail) { + struct mt76_queue_entry *e = &q->entry[q->first]; + int err, len = e->skb->len; + + if (mt7663s_tx_update_sched(dev, e, mcu)) + break; + + if (len > sdio->func->cur_blksize) + len = roundup(len, sdio->func->cur_blksize); + + /* TODO: skb_walk_frags and then write to SDIO port */ + err = sdio_writesb(sdio->func, MCR_WTDR1, e->skb->data, len); + if (err) { + dev_err(dev->mt76.dev, "sdio write failed: %d\n", err); + return -EIO; + } + + e->done = true; + q->first = (q->first + 1) % q->ndesc; + nframes++; + } + + return nframes; +} + +static int mt7663s_tx_run_queues(struct mt7615_dev *dev) +{ + int i, nframes = 0; + + for (i = 0; i < MT_TXQ_MCU_WA; i++) { + int ret; + + ret = mt7663s_tx_run_queue(dev, dev->mt76.q_tx[i].q); + if (ret < 0) + return ret; + + nframes += ret; + } + + return nframes; +} + +int mt7663s_kthread_run(void *data) +{ + struct mt7615_dev *dev = data; + struct mt76_phy *mphy = &dev->mt76.phy; + + while (!kthread_should_stop()) { + int ret; + + cond_resched(); + + sdio_claim_host(dev->mt76.sdio.func); + ret = mt7663s_tx_run_queues(dev); + sdio_release_host(dev->mt76.sdio.func); + + if (ret <= 0 || !test_bit(MT76_STATE_RUNNING, &mphy->state)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } else { + wake_up_process(dev->mt76.sdio.kthread); + } + } + + return 0; +} + +void mt7663s_sdio_irq(struct sdio_func *func) +{ + struct mt7615_dev *dev = sdio_get_drvdata(func); + struct mt76_sdio *sdio = &dev->mt76.sdio; + struct mt76s_intr intr; + + /* disable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, 0); + + do { + sdio_readsb(func, &intr, MCR_WHISR, sizeof(struct mt76s_intr)); + trace_dev_irq(&dev->mt76, intr.isr, 0); + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state)) + goto out; + + if (intr.isr & WHIER_RX0_DONE_INT_EN) { + mt7663s_rx_run_queue(dev, 0, &intr); + wake_up_process(sdio->kthread); + } + + if (intr.isr & WHIER_RX1_DONE_INT_EN) { + mt7663s_rx_run_queue(dev, 1, &intr); + wake_up_process(sdio->kthread); + } + + if (intr.isr & WHIER_TX_DONE_INT_EN) { + mt7663s_refill_sched_quota(dev, intr.tx.wtqcr); + mt7663s_tx_run_queues(dev); + wake_up_process(sdio->kthread); + } + } while (intr.isr); +out: + /* enable interrupt */ + sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, 0); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c new file mode 100644 index 000000000000..1730751133aa --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ + +#include "mt7615.h" +#include "eeprom.h" +#include "mcu.h" + +enum { + TM_CHANGED_TXPOWER_CTRL, + TM_CHANGED_TXPOWER, + TM_CHANGED_FREQ_OFFSET, + + /* must be last */ + NUM_TM_CHANGED +}; + + +static const u8 tm_change_map[] = { + [TM_CHANGED_TXPOWER_CTRL] = MT76_TM_ATTR_TX_POWER_CONTROL, + [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER, + [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET, +}; + +static const u32 reg_backup_list[] = { + MT_WF_PHY_RFINTF3_0(0), + MT_WF_PHY_RFINTF3_0(1), + MT_WF_PHY_RFINTF3_0(2), + MT_WF_PHY_RFINTF3_0(3), + MT_ANT_SWITCH_CON(2), + MT_ANT_SWITCH_CON(3), + MT_ANT_SWITCH_CON(4), + MT_ANT_SWITCH_CON(6), + MT_ANT_SWITCH_CON(7), + MT_ANT_SWITCH_CON(8), +}; + +static const struct { + u16 wf; + u16 reg; +} rf_backup_list[] = { + { 0, 0x48 }, + { 1, 0x48 }, + { 2, 0x48 }, + { 3, 0x48 }, +}; + +static int +mt7615_tm_set_tx_power(struct mt7615_phy *phy) +{ + struct mt7615_dev *dev = phy->dev; + struct mt76_phy *mphy = phy->mt76; + int i, ret, n_chains = hweight8(mphy->antenna_mask); + struct cfg80211_chan_def *chandef = &mphy->chandef; + int freq = chandef->center_freq1, len, target_chains; + u8 *data, *eep = (u8 *)dev->mt76.eeprom.data; + enum nl80211_band band = chandef->chan->band; + struct sk_buff *skb; + struct { + u8 center_chan; + u8 dbdc_idx; + u8 band; + u8 rsv; + } __packed req_hdr = { + .center_chan = ieee80211_frequency_to_channel(freq), + .band = band, + .dbdc_idx = phy != &dev->phy, + }; + u8 *tx_power = NULL; + + if (dev->mt76.test.state != MT76_TM_STATE_OFF) + tx_power = dev->mt76.test.tx_power; + + len = sizeof(req_hdr) + MT7615_EE_MAX - MT_EE_NIC_CONF_0; + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, &req_hdr, sizeof(req_hdr)); + data = skb_put_data(skb, eep + MT_EE_NIC_CONF_0, len); + + target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains; + for (i = 0; i < target_chains; i++) { + int index; + + ret = mt7615_eeprom_get_target_power_index(dev, chandef->chan, i); + if (ret < 0) + return -EINVAL; + + index = ret - MT_EE_NIC_CONF_0; + if (tx_power && tx_power[i]) + data[ret - MT_EE_NIC_CONF_0] = tx_power[i]; + } + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_SET_TX_POWER_CTRL, false); +} + +static void +mt7615_tm_reg_backup_restore(struct mt7615_dev *dev) +{ + u32 *b = dev->test.reg_backup; + int n_regs = ARRAY_SIZE(reg_backup_list); + int n_rf_regs = ARRAY_SIZE(rf_backup_list); + int i; + + if (dev->mt76.test.state == MT76_TM_STATE_OFF) { + for (i = 0; i < n_regs; i++) + mt76_wr(dev, reg_backup_list[i], b[i]); + + for (i = 0; i < n_rf_regs; i++) + mt7615_rf_wr(dev, rf_backup_list[i].wf, + rf_backup_list[i].reg, b[n_regs + i]); + return; + } + + if (b) + return; + + b = devm_kzalloc(dev->mt76.dev, 4 * (n_regs + n_rf_regs), + GFP_KERNEL); + if (!b) + return; + + dev->test.reg_backup = b; + for (i = 0; i < n_regs; i++) + b[i] = mt76_rr(dev, reg_backup_list[i]); + for (i = 0; i < n_rf_regs; i++) + b[n_regs + i] = mt7615_rf_rr(dev, rf_backup_list[i].wf, + rf_backup_list[i].reg); +} + + +static void +mt7615_tm_init_phy(struct mt7615_dev *dev, struct mt7615_phy *phy) +{ + unsigned int total_flags = ~0; + + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + return; + + mutex_unlock(&dev->mt76.mutex); + mt7615_set_channel(phy); + mt7615_ops.configure_filter(phy->mt76->hw, 0, &total_flags, 0); + mutex_lock(&dev->mt76.mutex); + + mt7615_tm_reg_backup_restore(dev); +} + +static void +mt7615_tm_init(struct mt7615_dev *dev) +{ + mt7615_tm_init_phy(dev, &dev->phy); + + if (dev->mt76.phy2) + mt7615_tm_init_phy(dev, dev->mt76.phy2->priv); +} + +static void +mt7615_tm_set_rx_enable(struct mt7615_dev *dev, bool en) +{ + u32 rqcr_mask = (MT_ARB_RQCR_RX_START | + MT_ARB_RQCR_RXV_START | + MT_ARB_RQCR_RXV_R_EN | + MT_ARB_RQCR_RXV_T_EN) * + (BIT(0) | BIT(MT_ARB_RQCR_BAND_SHIFT)); + + if (en) { + mt76_clear(dev, MT_ARB_SCR, + MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE); + mt76_set(dev, MT_ARB_RQCR, rqcr_mask); + } else { + mt76_set(dev, MT_ARB_SCR, + MT_ARB_SCR_RX0_DISABLE | MT_ARB_SCR_RX1_DISABLE); + mt76_clear(dev, MT_ARB_RQCR, rqcr_mask); + } +} + +static void +mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en) +{ + struct mt76_testmode_data *td = &dev->mt76.test; + u8 mask = td->tx_antenna_mask; + int i; + + if (!mask) + return; + + if (!en) + mask = dev->phy.chainmask; + + for (i = 0; i < 4; i++) { + mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i), + MT_WF_PHY_RFINTF3_0_ANT, + td->tx_antenna_mask & BIT(i) ? 0 : 0xa); + + } + + /* 2.4 GHz band */ + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(3), MT_ANT_SWITCH_CON_MODE(0), + (td->tx_antenna_mask & BIT(0)) ? 0x8 : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(2), + (td->tx_antenna_mask & BIT(1)) ? 0xe : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(6), MT_ANT_SWITCH_CON_MODE1(0), + (td->tx_antenna_mask & BIT(2)) ? 0x0 : 0xf); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(2), + (td->tx_antenna_mask & BIT(3)) ? 0x6 : 0xf); + + /* 5 GHz band */ + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(4), MT_ANT_SWITCH_CON_MODE(1), + (td->tx_antenna_mask & BIT(0)) ? 0xd : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(2), MT_ANT_SWITCH_CON_MODE(3), + (td->tx_antenna_mask & BIT(1)) ? 0x13 : 0x1b); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(7), MT_ANT_SWITCH_CON_MODE1(1), + (td->tx_antenna_mask & BIT(2)) ? 0x5 : 0xf); + mt76_rmw_field(dev, MT_ANT_SWITCH_CON(8), MT_ANT_SWITCH_CON_MODE1(3), + (td->tx_antenna_mask & BIT(3)) ? 0xb : 0xf); + + for (i = 0; i < 4; i++) { + u32 val; + + val = mt7615_rf_rr(dev, i, 0x48); + val &= ~(0x3ff << 20); + if (td->tx_antenna_mask & BIT(i)) + val |= 3 << 20; + else + val |= (2 << 28) | (2 << 26) | (8 << 20); + mt7615_rf_wr(dev, i, 0x48, val); + } +} + +static void +mt7615_tm_set_tx_frames(struct mt7615_dev *dev, bool en) +{ + struct ieee80211_tx_info *info; + struct sk_buff *skb = dev->mt76.test.tx_skb; + + mt7615_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH); + mt7615_tm_set_tx_antenna(dev, en); + mt7615_tm_set_rx_enable(dev, !en); + if (!en || !skb) + return; + + info = IEEE80211_SKB_CB(skb); + info->control.vif = dev->phy.monitor_vif; +} + +static void +mt7615_tm_update_params(struct mt7615_dev *dev, u32 changed) +{ + struct mt76_testmode_data *td = &dev->mt76.test; + bool en = dev->mt76.test.state != MT76_TM_STATE_OFF; + + if (changed & BIT(TM_CHANGED_TXPOWER_CTRL)) + mt7615_mcu_set_test_param(dev, MCU_ATE_SET_TX_POWER_CONTROL, + en, en && td->tx_power_control); + if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) + mt7615_mcu_set_test_param(dev, MCU_ATE_SET_FREQ_OFFSET, + en, en ? td->freq_offset : 0); + if (changed & BIT(TM_CHANGED_TXPOWER)) + mt7615_tm_set_tx_power(&dev->phy); +} + +static int +mt7615_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_testmode_data *td = &mdev->test; + enum mt76_testmode_state prev_state = td->state; + + mdev->test.state = state; + + if (prev_state == MT76_TM_STATE_TX_FRAMES) + mt7615_tm_set_tx_frames(dev, false); + else if (state == MT76_TM_STATE_TX_FRAMES) + mt7615_tm_set_tx_frames(dev, true); + + if (state <= MT76_TM_STATE_IDLE) + mt7615_tm_init(dev); + + if ((state == MT76_TM_STATE_IDLE && + prev_state == MT76_TM_STATE_OFF) || + (state == MT76_TM_STATE_OFF && + prev_state == MT76_TM_STATE_IDLE)) { + u32 changed = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { + u16 cur = tm_change_map[i]; + + if (td->param_set[cur / 32] & BIT(cur % 32)) + changed |= BIT(i); + } + + mt7615_tm_update_params(dev, changed); + } + + return 0; +} + +static int +mt7615_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb, + enum mt76_testmode_state new_state) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_testmode_data *td = &dev->mt76.test; + u32 changed = 0; + int i; + + BUILD_BUG_ON(NUM_TM_CHANGED >= 32); + + if (new_state == MT76_TM_STATE_OFF || + td->state == MT76_TM_STATE_OFF) + return 0; + + if (td->tx_antenna_mask & ~dev->phy.chainmask) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { + if (tb[tm_change_map[i]]) + changed |= BIT(i); + } + + mt7615_tm_update_params(dev, changed); + + return 0; +} + +static int +mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + void *rx, *rssi; + int i; + + rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); + if (!rx) + return -ENOMEM; + + if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset) || + nla_put_s32(msg, MT76_TM_RX_ATTR_IB_RSSI, dev->test.last_ib_rssi) || + nla_put_s32(msg, MT76_TM_RX_ATTR_WB_RSSI, dev->test.last_wb_rssi)) + return -ENOMEM; + + rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); + if (!rssi) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(dev->test.last_rcpi); i++) + if (nla_put_u8(msg, i, dev->test.last_rcpi[i])) + return -ENOMEM; + + nla_nest_end(msg, rssi); + + nla_nest_end(msg, rx); + + return 0; +} + +const struct mt76_testmode_ops mt7615_testmode_ops = { + .set_state = mt7615_tm_set_state, + .set_params = mt7615_tm_set_params, + .dump_stats = mt7615_tm_dump_stats, +}; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index 5be6704770ad..23a21338c46e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -15,31 +15,6 @@ #include "mcu.h" #include "regs.h" -static const u32 mt7663u_reg_map[] = { - [MT_TOP_CFG_BASE] = 0x80020000, - [MT_HW_BASE] = 0x80000000, - [MT_DMA_SHDL_BASE] = 0x5000a000, - [MT_HIF_BASE] = 0x50000000, - [MT_CSR_BASE] = 0x40000000, - [MT_EFUSE_ADDR_BASE] = 0x78011000, - [MT_TOP_MISC_BASE] = 0x81020000, - [MT_PLE_BASE] = 0x82060000, - [MT_PSE_BASE] = 0x82068000, - [MT_PHY_BASE] = 0x82070000, - [MT_WTBL_BASE_ADDR] = 0x820e0000, - [MT_CFG_BASE] = 0x820f0000, - [MT_AGG_BASE] = 0x820f2000, - [MT_ARB_BASE] = 0x820f3000, - [MT_TMAC_BASE] = 0x820f4000, - [MT_RMAC_BASE] = 0x820f5000, - [MT_DMA_BASE] = 0x820f7000, - [MT_PF_BASE] = 0x820f8000, - [MT_WTBL_BASE_ON] = 0x820f9000, - [MT_WTBL_BASE_OFF] = 0x820f9800, - [MT_LPON_BASE] = 0x820fb000, - [MT_MIB_BASE] = 0x820fd000, -}; - static const struct usb_device_id mt7615_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7663, 0xff, 0xff, 0xff) }, { }, @@ -64,205 +39,19 @@ static void mt7663u_cleanup(struct mt7615_dev *dev) mt76u_queues_deinit(&dev->mt76); } -static void -mt7663u_mac_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, - enum mt76_txq_id qid, struct ieee80211_sta *sta, - struct sk_buff *skb) -{ - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *key = info->control.hw_key; - __le32 *txwi; - int pid; - - if (!wcid) - wcid = &dev->mt76.global_wcid; - - pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); - - txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); - memset(txwi, 0, MT_USB_TXD_SIZE); - mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); - skb_push(skb, MT_USB_TXD_SIZE); -} - -static int -__mt7663u_mac_set_rates(struct mt7615_dev *dev, - struct mt7615_wtbl_desc *wd) -{ - struct mt7615_rate_desc *rate = &wd->rate; - struct mt7615_sta *sta = wd->sta; - u32 w5, w27, addr, val; - - lockdep_assert_held(&dev->mt76.mutex); - - if (!sta) - return -EINVAL; - - if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) - return -ETIMEDOUT; - - addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); - - w27 = mt76_rr(dev, addr + 27 * 4); - w27 &= ~MT_WTBL_W27_CC_BW_SEL; - w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); - - w5 = mt76_rr(dev, addr + 5 * 4); - w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | - MT_WTBL_W5_MPDU_OK_COUNT | - MT_WTBL_W5_MPDU_FAIL_COUNT | - MT_WTBL_W5_RATE_IDX); - w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | - FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, - rate->bw_idx ? rate->bw_idx - 1 : 7); - - mt76_wr(dev, MT_WTBL_RIUCR0, w5); - - mt76_wr(dev, MT_WTBL_RIUCR1, - FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); - - mt76_wr(dev, MT_WTBL_RIUCR2, - FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); - - mt76_wr(dev, MT_WTBL_RIUCR3, - FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); - - mt76_wr(dev, MT_WTBL_UPDATE, - FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | - MT_WTBL_UPDATE_RATE_UPDATE | - MT_WTBL_UPDATE_TX_COUNT_CLEAR); - - mt76_wr(dev, addr + 27 * 4, w27); - - mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ - val = mt76_rr(dev, MT_LPON_UTTR0); - sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; - - if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) - mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); - - sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; - sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; - - return 0; -} - -static int -__mt7663u_mac_set_key(struct mt7615_dev *dev, - struct mt7615_wtbl_desc *wd) -{ - struct mt7615_key_desc *key = &wd->key; - struct mt7615_sta *sta = wd->sta; - enum mt7615_cipher_type cipher; - struct mt76_wcid *wcid; - int err; - - lockdep_assert_held(&dev->mt76.mutex); - - if (!sta) - return -EINVAL; - - cipher = mt7615_mac_get_cipher(key->cipher); - if (cipher == MT_CIPHER_NONE) - return -EOPNOTSUPP; - - wcid = &wd->sta->wcid; - - mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd); - err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, - cipher, key->cmd); - if (err < 0) - return err; - - err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, - key->cmd); - if (err < 0) - return err; - - if (key->cmd == SET_KEY) - wcid->cipher |= BIT(cipher); - else - wcid->cipher &= ~BIT(cipher); - - return 0; -} - -void mt7663u_wtbl_work(struct work_struct *work) +static void mt7663u_init_work(struct work_struct *work) { - struct mt7615_wtbl_desc *wd, *wd_next; struct mt7615_dev *dev; - dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, - wtbl_work); - - list_for_each_entry_safe(wd, wd_next, &dev->wd_head, node) { - spin_lock_bh(&dev->mt76.lock); - list_del(&wd->node); - spin_unlock_bh(&dev->mt76.lock); - - mutex_lock(&dev->mt76.mutex); - switch (wd->type) { - case MT7615_WTBL_RATE_DESC: - __mt7663u_mac_set_rates(dev, wd); - break; - case MT7615_WTBL_KEY_DESC: - __mt7663u_mac_set_key(dev, wd); - break; - } - mutex_unlock(&dev->mt76.mutex); - - kfree(wd); - } -} - -static void -mt7663u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, - struct mt76_queue_entry *e) -{ - skb_pull(e->skb, MT_USB_HDR_SIZE + MT_USB_TXD_SIZE); - mt76_tx_complete_skb(mdev, e->skb); -} - -static int -mt7663u_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, - enum mt76_txq_id qid, struct mt76_wcid *wcid, - struct ieee80211_sta *sta, - struct mt76_tx_info *tx_info) -{ - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); - - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { - struct mt7615_sta *msta; - - msta = container_of(wcid, struct mt7615_sta, wcid); - spin_lock_bh(&dev->mt76.lock); - mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], - msta->rates); - msta->rate_probe = true; - spin_unlock_bh(&dev->mt76.lock); - } - mt7663u_mac_write_txwi(dev, wcid, qid, sta, tx_info->skb); - - return mt76u_skb_dma_info(tx_info->skb, tx_info->skb->len); -} - -static bool mt7663u_tx_status_data(struct mt76_dev *mdev, u8 *update) -{ - struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); - - mutex_lock(&dev->mt76.mutex); - mt7615_mac_sta_poll(dev); - mutex_unlock(&dev->mt76.mutex); + dev = container_of(work, struct mt7615_dev, mcu_work); + if (mt7663u_mcu_init(dev)) + return; - return 0; + mt7615_mcu_set_eeprom(dev); + mt7615_mac_init(dev); + mt7615_phy_init(dev); + mt7615_mcu_del_wtbl_all(dev); + mt7615_check_offload_capability(dev); } static int mt7663u_probe(struct usb_interface *usb_intf, @@ -271,9 +60,9 @@ static int mt7663u_probe(struct usb_interface *usb_intf, static const struct mt76_driver_ops drv_ops = { .txwi_size = MT_USB_TXD_SIZE, .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ, - .tx_prepare_skb = mt7663u_tx_prepare_skb, - .tx_complete_skb = mt7663u_tx_complete_skb, - .tx_status_data = mt7663u_tx_status_data, + .tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb, + .tx_complete_skb = mt7663_usb_sdio_tx_complete_skb, + .tx_status_data = mt7663_usb_sdio_tx_status_data, .rx_skb = mt7615_queue_rx_skb, .sta_ps = mt7615_sta_ps, .sta_add = mt7615_mac_sta_add, @@ -303,7 +92,8 @@ static int mt7663u_probe(struct usb_interface *usb_intf, usb_set_intfdata(usb_intf, dev); - dev->reg_map = mt7663u_reg_map; + INIT_WORK(&dev->mcu_work, mt7663u_init_work); + dev->reg_map = mt7663_usb_sdio_reg_map; dev->ops = ops; ret = mt76u_init(mdev, usb_intf, true); if (ret < 0) @@ -342,7 +132,7 @@ alloc_queues: if (ret) goto error_free_q; - ret = mt7663u_register_device(dev); + ret = mt7663_usb_sdio_register_device(dev); if (ret) goto error_free_q; @@ -351,11 +141,10 @@ alloc_queues: error_free_q: mt76u_queues_deinit(&dev->mt76); error: - mt76u_deinit(&dev->mt76); usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - ieee80211_free_hw(mdev->hw); + mt76_free_device(&dev->mt76); return ret; } @@ -373,8 +162,7 @@ static void mt7663u_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - mt76u_deinit(&dev->mt76); - ieee80211_free_hw(dev->mt76.hw); + mt76_free_device(&dev->mt76); } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c deleted file mode 100644 index 1fbc9601391d..000000000000 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_init.c +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2019 MediaTek Inc. - * - * Author: Felix Fietkau <nbd@nbd.name> - * Lorenzo Bianconi <lorenzo@kernel.org> - * Sean Wang <sean.wang@mediatek.com> - */ - -#include <linux/kernel.h> -#include <linux/module.h> - -#include "mt7615.h" -#include "mac.h" -#include "regs.h" - -static int mt7663u_dma_sched_init(struct mt7615_dev *dev) -{ - int i; - - mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), - MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, - FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | - FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); - - /* disable refill group 5 - group 15 and raise group 2 - * and 3 as high priority. - */ - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); - mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); - - for (i = 0; i < 5; i++) - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), - FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | - FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); - - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); - - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); - - /* group pririority from high to low: - * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. - */ - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); - mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); - - mt76_wr(dev, MT_UDMA_WLCFG_1, - FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | - FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); - - /* setup UDMA Rx Flush */ - mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); - /* hif reset */ - mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); - - mt76_set(dev, MT_UDMA_WLCFG_0, - MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | - MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | - MT_WL_TX_TMOUT_FUNC_EN); - mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, - FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | - FIELD_PREP(MT_WL_RX_AGG_TO, 100)); - - return 0; -} - -static int mt7663u_init_hardware(struct mt7615_dev *dev) -{ - int ret, idx; - - ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); - if (ret < 0) - return ret; - - ret = mt7663u_dma_sched_init(dev); - if (ret) - return ret; - - set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); - - /* Beacon and mgmt frames should occupy wcid 0 */ - idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); - if (idx) - return -ENOSPC; - - dev->mt76.global_wcid.idx = idx; - dev->mt76.global_wcid.hw_key_idx = -1; - rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); - - return 0; -} - -static void mt7663u_init_work(struct work_struct *work) -{ - struct mt7615_dev *dev; - - dev = container_of(work, struct mt7615_dev, mcu_work); - if (mt7663u_mcu_init(dev)) - return; - - mt7615_mcu_set_eeprom(dev); - mt7615_mac_init(dev); - mt7615_phy_init(dev); - mt7615_mcu_del_wtbl_all(dev); - mt7615_check_offload_capability(dev); -} - -int mt7663u_register_device(struct mt7615_dev *dev) -{ - struct ieee80211_hw *hw = mt76_hw(dev); - int err; - - INIT_WORK(&dev->wtbl_work, mt7663u_wtbl_work); - INIT_WORK(&dev->mcu_work, mt7663u_init_work); - INIT_LIST_HEAD(&dev->wd_head); - mt7615_init_device(dev); - - err = mt7663u_init_hardware(dev); - if (err) - return err; - - hw->extra_tx_headroom += MT_USB_HDR_SIZE + MT_USB_TXD_SIZE; - /* check hw sg support in order to enable AMSDU */ - hw->max_tx_fragments = dev->mt76.usb.sg_en ? MT_HW_TXP_MAX_BUF_NUM : 1; - - err = mt76_register_device(&dev->mt76, true, mt7615_rates, - ARRAY_SIZE(mt7615_rates)); - if (err < 0) - return err; - - if (!dev->mt76.usb.sg_en) { - struct ieee80211_sta_vht_cap *vht_cap; - - /* decrease max A-MSDU size if SG is not supported */ - vht_cap = &dev->mphy.sband_5g.sband.vht_cap; - vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; - } - - ieee80211_queue_work(hw, &dev->mcu_work); - mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); - mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); - - return mt7615_init_debugfs(dev); -} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c index cd709fd617db..0b33df3e3bfe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c @@ -28,13 +28,13 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, else ep = MT_EP_OUT_AC_BE; - ret = mt76u_skb_dma_info(skb, skb->len); + put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len))); + ret = mt76_skb_adjust_pad(skb); if (ret < 0) goto out; ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL, 1000, ep); - dev_kfree_skb(skb); if (ret < 0) goto out; @@ -43,6 +43,7 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, out: mutex_unlock(&mdev->mcu.mutex); + dev_kfree_skb(skb); return ret; } @@ -60,6 +61,8 @@ int mt7663u_mcu_init(struct mt7615_dev *dev) dev->mt76.mcu_ops = &mt7663u_mcu_ops, + /* usb does not support runtime-pm */ + clear_bit(MT76_STATE_PM, &dev->mphy.state); mt76_set(dev, MT_UDMA_TX_QSEL, MT_FW_DL_EN); if (test_and_clear_bit(MT76_STATE_POWER_OFF, &dev->mphy.state)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c new file mode 100644 index 000000000000..6dffdaaa9ad5 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * Author: Lorenzo Bianconi <lorenzo@kernel.org> + * Sean Wang <sean.wang@mediatek.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb.h> + +#include "mt7615.h" +#include "mac.h" +#include "mcu.h" +#include "regs.h" + +const u32 mt7663_usb_sdio_reg_map[] = { + [MT_TOP_CFG_BASE] = 0x80020000, + [MT_HW_BASE] = 0x80000000, + [MT_DMA_SHDL_BASE] = 0x5000a000, + [MT_HIF_BASE] = 0x50000000, + [MT_CSR_BASE] = 0x40000000, + [MT_EFUSE_ADDR_BASE] = 0x78011000, + [MT_TOP_MISC_BASE] = 0x81020000, + [MT_PLE_BASE] = 0x82060000, + [MT_PSE_BASE] = 0x82068000, + [MT_PP_BASE] = 0x8206c000, + [MT_WTBL_BASE_ADDR] = 0x820e0000, + [MT_CFG_BASE] = 0x820f0000, + [MT_AGG_BASE] = 0x820f2000, + [MT_ARB_BASE] = 0x820f3000, + [MT_TMAC_BASE] = 0x820f4000, + [MT_RMAC_BASE] = 0x820f5000, + [MT_DMA_BASE] = 0x820f7000, + [MT_PF_BASE] = 0x820f8000, + [MT_WTBL_BASE_ON] = 0x820f9000, + [MT_WTBL_BASE_OFF] = 0x820f9800, + [MT_LPON_BASE] = 0x820fb000, + [MT_MIB_BASE] = 0x820fd000, +}; +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_reg_map); + +static void +mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid, + enum mt76_txq_id qid, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *key = info->control.hw_key; + __le32 *txwi; + int pid; + + if (!wcid) + wcid = &dev->mt76.global_wcid; + + pid = mt76_tx_status_skb_add(&dev->mt76, wcid, skb); + + txwi = (__le32 *)(skb->data - MT_USB_TXD_SIZE); + memset(txwi, 0, MT_USB_TXD_SIZE); + mt7615_mac_write_txwi(dev, txwi, skb, wcid, sta, pid, key, false); + skb_push(skb, MT_USB_TXD_SIZE); +} + +static int +mt7663_usb_sdio_set_rates(struct mt7615_dev *dev, + struct mt7615_wtbl_desc *wd) +{ + struct mt7615_rate_desc *rate = &wd->rate; + struct mt7615_sta *sta = wd->sta; + u32 w5, w27, addr, val; + + lockdep_assert_held(&dev->mt76.mutex); + + if (!sta) + return -EINVAL; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return -ETIMEDOUT; + + addr = mt7615_mac_wtbl_addr(dev, sta->wcid.idx); + + w27 = mt76_rr(dev, addr + 27 * 4); + w27 &= ~MT_WTBL_W27_CC_BW_SEL; + w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, rate->bw); + + w5 = mt76_rr(dev, addr + 5 * 4); + w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | + MT_WTBL_W5_MPDU_OK_COUNT | + MT_WTBL_W5_MPDU_FAIL_COUNT | + MT_WTBL_W5_RATE_IDX); + w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, rate->bw) | + FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, + rate->bw_idx ? rate->bw_idx - 1 : 7); + + mt76_wr(dev, MT_WTBL_RIUCR0, w5); + + mt76_wr(dev, MT_WTBL_RIUCR1, + FIELD_PREP(MT_WTBL_RIUCR1_RATE0, rate->probe_val) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE1, rate->val[0]) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, rate->val[1])); + + mt76_wr(dev, MT_WTBL_RIUCR2, + FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, rate->val[1] >> 8) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE3, rate->val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE4, rate->val[2]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, rate->val[2])); + + mt76_wr(dev, MT_WTBL_RIUCR3, + FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, rate->val[2] >> 4) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE6, rate->val[3]) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE7, rate->val[3])); + + mt76_wr(dev, MT_WTBL_UPDATE, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, sta->wcid.idx) | + MT_WTBL_UPDATE_RATE_UPDATE | + MT_WTBL_UPDATE_TX_COUNT_CLEAR); + + mt76_wr(dev, addr + 27 * 4, w27); + + sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1; + + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ + val = mt76_rr(dev, MT_LPON_UTTR0); + sta->rate_set_tsf = (val & ~BIT(0)) | rate->rateset; + + if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + sta->rate_count = 2 * MT7615_RATE_RETRY * sta->n_rates; + sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + + return 0; +} + +static int +mt7663_usb_sdio_set_key(struct mt7615_dev *dev, + struct mt7615_wtbl_desc *wd) +{ + struct mt7615_key_desc *key = &wd->key; + struct mt7615_sta *sta = wd->sta; + enum mt7615_cipher_type cipher; + struct mt76_wcid *wcid; + int err; + + lockdep_assert_held(&dev->mt76.mutex); + + if (!sta) { + err = -EINVAL; + goto out; + } + + cipher = mt7615_mac_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) { + err = -EOPNOTSUPP; + goto out; + } + + wcid = &wd->sta->wcid; + + mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd); + err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen, + cipher, key->cmd); + if (err < 0) + goto out; + + err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, + key->cmd); + if (err < 0) + goto out; + + if (key->cmd == SET_KEY) + wcid->cipher |= BIT(cipher); + else + wcid->cipher &= ~BIT(cipher); +out: + kfree(key->key); + + return err; +} + +void mt7663_usb_sdio_wtbl_work(struct work_struct *work) +{ + struct mt7615_wtbl_desc *wd, *wd_next; + struct list_head wd_list; + struct mt7615_dev *dev; + + dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev, + wtbl_work); + + INIT_LIST_HEAD(&wd_list); + spin_lock_bh(&dev->mt76.lock); + list_splice_init(&dev->wd_head, &wd_list); + spin_unlock_bh(&dev->mt76.lock); + + list_for_each_entry_safe(wd, wd_next, &wd_list, node) { + list_del(&wd->node); + + mt7615_mutex_acquire(dev); + + switch (wd->type) { + case MT7615_WTBL_RATE_DESC: + mt7663_usb_sdio_set_rates(dev, wd); + break; + case MT7615_WTBL_KEY_DESC: + mt7663_usb_sdio_set_key(dev, wd); + break; + } + + mt7615_mutex_release(dev); + + kfree(wd); + } +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_wtbl_work); + +bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + + mt7615_mutex_acquire(dev); + mt7615_mac_sta_poll(dev); + mt7615_mutex_release(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data); + +void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, + enum mt76_txq_id qid, + struct mt76_queue_entry *e) +{ + unsigned int headroom = MT_USB_TXD_SIZE; + + if (mt76_is_usb(mdev)) + headroom += MT_USB_HDR_SIZE; + skb_pull(e->skb, headroom); + + mt76_tx_complete_skb(mdev, e->skb); +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_complete_skb); + +int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, + enum mt76_txq_id qid, struct mt76_wcid *wcid, + struct ieee80211_sta *sta, + struct mt76_tx_info *tx_info) +{ + struct mt7615_sta *msta = container_of(wcid, struct mt7615_sta, wcid); + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct sk_buff *skb = tx_info->skb; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && + !msta->rate_probe) { + /* request to configure sampling rate */ + spin_lock_bh(&dev->mt76.lock); + mt7615_mac_set_rates(&dev->phy, msta, &info->control.rates[0], + msta->rates); + spin_unlock_bh(&dev->mt76.lock); + } + + mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, skb); + if (mt76_is_usb(mdev)) + put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len))); + + return mt76_skb_adjust_pad(skb); +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb); + +static int mt7663u_dma_sched_init(struct mt7615_dev *dev) +{ + int i; + + mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE), + MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE, + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) | + FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8)); + + /* disable refill group 5 - group 15 and raise group 2 + * and 3 as high priority. + */ + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffe00006); + mt76_clear(dev, MT_DMA_SHDL(MT_DMASHDL_PAGE), BIT(16)); + + for (i = 0; i < 5; i++) + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)), + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x3) | + FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x1ff)); + + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210); + + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x4444); + + /* group pririority from high to low: + * 15 (cmd groups) > 4 > 3 > 2 > 1 > 0. + */ + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6501234f); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987); + mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x7004801c); + + mt76_wr(dev, MT_UDMA_WLCFG_1, + FIELD_PREP(MT_WL_TX_TMOUT_LMT, 80000) | + FIELD_PREP(MT_WL_RX_AGG_PKT_LMT, 1)); + + /* setup UDMA Rx Flush */ + mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); + /* hif reset */ + mt76_set(dev, MT_HIF_RST, MT_HIF_LOGIC_RST_N); + + mt76_set(dev, MT_UDMA_WLCFG_0, + MT_WL_RX_AGG_EN | MT_WL_RX_EN | MT_WL_TX_EN | + MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN | + MT_WL_TX_TMOUT_FUNC_EN); + mt76_rmw(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_LMT | MT_WL_RX_AGG_TO, + FIELD_PREP(MT_WL_RX_AGG_LMT, 32) | + FIELD_PREP(MT_WL_RX_AGG_TO, 100)); + + return 0; +} + +static int mt7663_usb_sdio_init_hardware(struct mt7615_dev *dev) +{ + int ret, idx; + + ret = mt7615_eeprom_init(dev, MT_EFUSE_BASE); + if (ret < 0) + return ret; + + if (mt76_is_usb(&dev->mt76)) { + ret = mt7663u_dma_sched_init(dev); + if (ret) + return ret; + } + + set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); + + /* Beacon and mgmt frames should occupy wcid 0 */ + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); + if (idx) + return -ENOSPC; + + dev->mt76.global_wcid.idx = idx; + dev->mt76.global_wcid.hw_key_idx = -1; + rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid); + + return 0; +} + +int mt7663_usb_sdio_register_device(struct mt7615_dev *dev) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + int err; + + INIT_WORK(&dev->wtbl_work, mt7663_usb_sdio_wtbl_work); + INIT_LIST_HEAD(&dev->wd_head); + mt7615_init_device(dev); + + err = mt7663_usb_sdio_init_hardware(dev); + if (err) + return err; + + /* check hw sg support in order to enable AMSDU */ + if (dev->mt76.usb.sg_en || mt76_is_sdio(&dev->mt76)) + hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM; + else + hw->max_tx_fragments = 1; + hw->extra_tx_headroom += MT_USB_TXD_SIZE; + if (mt76_is_usb(&dev->mt76)) + hw->extra_tx_headroom += MT_USB_HDR_SIZE; + + err = mt76_register_device(&dev->mt76, true, mt7615_rates, + ARRAY_SIZE(mt7615_rates)); + if (err < 0) + return err; + + if (!dev->mt76.usb.sg_en) { + struct ieee80211_sta_vht_cap *vht_cap; + + /* decrease max A-MSDU size if SG is not supported */ + vht_cap = &dev->mphy.sband_5g.sband.vht_cap; + vht_cap->cap &= ~IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + } + + ieee80211_queue_work(hw, &dev->mcu_work); + mt7615_init_txpower(dev, &dev->mphy.sband_2g.sband); + mt7615_init_txpower(dev, &dev->mphy.sband_5g.sband); + + return mt7615_init_debugfs(dev); +} +EXPORT_SYMBOL_GPL(mt7663_usb_sdio_register_device); + +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 5535b9c0632f..ce6b286a8152 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -277,9 +277,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - mt76u_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); - ieee80211_free_hw(mdev->hw); return ret; } @@ -297,8 +296,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); - mt76u_deinit(&dev->mt76); - ieee80211_free_hw(dev->mt76.hw); + mt76_free_device(&dev->mt76); } static int __maybe_unused mt76x0_suspend(struct usb_interface *usb_intf, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 4c9bbc7ce023..4660b9691ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -80,7 +80,6 @@ struct mt76x02_dev { struct mutex phy_mutex; - u16 vif_mask; u16 chainmask; u8 txdone_seq; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 5fda6e7b120c..bacb1f10a699 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -439,7 +439,7 @@ static void mt76x02_reset_state(struct mt76x02_dev *dev) memset(msta, 0, sizeof(*msta)); } - dev->vif_mask = 0; + dev->mphy.vif_mask = 0; dev->mt76.beacon_mask = 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 0180b6200b17..37321e656776 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -56,8 +56,9 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) */ info = FIELD_PREP(MT_TXD_INFO_LEN, round_up(skb->len, 4)) | FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags; + put_unaligned_le32(info, skb_push(skb, sizeof(info))); - return mt76u_skb_dma_info(skb, info); + return mt76_skb_adjust_pad(skb); } int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index a30bb536fc8a..e43d13d7c988 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -87,8 +87,10 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, u32 info; int ret; - if (test_bit(MT76_REMOVED, &dev->phy.state)) - return 0; + if (test_bit(MT76_REMOVED, &dev->phy.state)) { + ret = 0; + goto out; + } if (wait_resp) { seq = ++dev->mcu.msg_seq & 0xf; @@ -111,6 +113,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, if (wait_resp) ret = mt76x02u_mcu_wait_resp(dev, seq); +out: consume_skb(skb); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 44822a849eb1..dbd4077ea283 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -305,7 +305,7 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) unsigned int idx = 0; /* Allow to change address in HW if we create first interface. */ - if (!dev->vif_mask && + if (!dev->mphy.vif_mask && (((vif->addr[0] ^ dev->mt76.macaddr[0]) & ~GENMASK(4, 1)) || memcmp(vif->addr + 1, dev->mt76.macaddr + 1, ETH_ALEN - 1))) mt76x02_mac_setaddr(dev, vif->addr); @@ -330,11 +330,11 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx += 8; /* vif is already set or idx is 8 for AP/Mesh/... */ - if (dev->vif_mask & BIT(idx) || + if (dev->mphy.vif_mask & BIT(idx) || (vif->type != NL80211_IFTYPE_STATION && idx > 7)) return -EBUSY; - dev->vif_mask |= BIT(idx); + dev->mphy.vif_mask |= BIT(idx); mt76x02_vif_init(dev, vif, idx); return 0; @@ -348,7 +348,7 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw, struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; mt76_txq_remove(&dev->mt76, vif->txq); - dev->vif_mask &= ~BIT(mvif->idx); + dev->mphy.vif_mask &= ~BIT(mvif->idx); } EXPORT_SYMBOL_GPL(mt76x02_remove_interface); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index eca95b7f64d2..d01f47c83eb1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -39,6 +39,7 @@ static inline bool mt76x2_channel_silent(struct mt76x02_dev *dev) extern const struct ieee80211_ops mt76x2_ops; int mt76x2_register_device(struct mt76x02_dev *dev); +int mt76x2_resume_device(struct mt76x02_dev *dev); void mt76x2_phy_power_on(struct mt76x02_dev *dev); void mt76x2_stop_hardware(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 53ca0cedf026..6dfb0df8ec8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -9,7 +9,7 @@ #include "mt76x2.h" -static const struct pci_device_id mt76pci_device_table[] = { +static const struct pci_device_id mt76x2e_device_table[] = { { PCI_DEVICE(0x14c3, 0x7662) }, { PCI_DEVICE(0x14c3, 0x7612) }, { PCI_DEVICE(0x14c3, 0x7602) }, @@ -17,7 +17,7 @@ static const struct pci_device_id mt76pci_device_table[] = { }; static int -mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), @@ -93,7 +93,7 @@ error: } static void -mt76pci_remove(struct pci_dev *pdev) +mt76x2e_remove(struct pci_dev *pdev) { struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); @@ -103,16 +103,72 @@ mt76pci_remove(struct pci_dev *pdev) mt76_free_device(mdev); } -MODULE_DEVICE_TABLE(pci, mt76pci_device_table); +static int __maybe_unused +mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + int i, err; + + napi_disable(&mdev->tx_napi); + tasklet_kill(&mdev->pre_tbtt_tasklet); + tasklet_kill(&mdev->tx_tasklet); + + mt76_for_each_q_rx(mdev, i) + napi_disable(&mdev->napi[i]); + + pci_enable_wake(pdev, pci_choose_state(pdev, state), true); + pci_save_state(pdev); + err = pci_set_power_state(pdev, pci_choose_state(pdev, state)); + if (err) + goto restore; + + return 0; + +restore: + mt76_for_each_q_rx(mdev, i) + napi_enable(&mdev->napi[i]); + napi_enable(&mdev->tx_napi); + + return err; +} + +static int __maybe_unused +mt76x2e_resume(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); + int i, err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + mt76_for_each_q_rx(mdev, i) { + napi_enable(&mdev->napi[i]); + napi_schedule(&mdev->napi[i]); + } + napi_enable(&mdev->tx_napi); + napi_schedule(&mdev->tx_napi); + + return mt76x2_resume_device(dev); +} + +MODULE_DEVICE_TABLE(pci, mt76x2e_device_table); MODULE_FIRMWARE(MT7662_FIRMWARE); MODULE_FIRMWARE(MT7662_ROM_PATCH); MODULE_LICENSE("Dual BSD/GPL"); static struct pci_driver mt76pci_driver = { .name = KBUILD_MODNAME, - .id_table = mt76pci_device_table, - .probe = mt76pci_probe, - .remove = mt76pci_remove, + .id_table = mt76x2e_device_table, + .probe = mt76x2e_probe, + .remove = mt76x2e_remove, +#ifdef CONFIG_PM + .suspend = mt76x2e_suspend, + .resume = mt76x2e_resume, +#endif /* CONFIG_PM */ }; module_pci_driver(mt76pci_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index f27774f57438..101a0fe00ef3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -217,6 +217,23 @@ mt76x2_power_on(struct mt76x02_dev *dev) mt76x2_power_on_rf(dev, 1); } +int mt76x2_resume_device(struct mt76x02_dev *dev) +{ + int err; + + mt76x02_dma_disable(dev); + mt76x2_reset_wlan(dev, true); + mt76x2_power_on(dev); + + err = mt76x2_mac_reset(dev, true); + if (err) + return err; + + mt76x02_mac_start(dev); + + return mt76x2_mcu_init(dev); +} + static int mt76x2_init_hardware(struct mt76x02_dev *dev) { int ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 3a4e41724af1..4e003c7b62cf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -16,6 +16,7 @@ static const struct usb_device_id mt76x2u_device_table[] = { { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ + { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ @@ -74,8 +75,7 @@ static int mt76x2u_probe(struct usb_interface *intf, return 0; err: - ieee80211_free_hw(mt76_hw(dev)); - mt76u_deinit(&dev->mt76); + mt76_free_device(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -91,9 +91,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf) set_bit(MT76_REMOVED, &dev->mphy.state); ieee80211_unregister_hw(hw); mt76x2u_cleanup(dev); - mt76u_deinit(&dev->mt76); - - ieee80211_free_hw(hw); + mt76_free_device(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 5278bee812f1..38f473d587c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -178,7 +178,14 @@ mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s) seq_printf(s, "Tx Beamformee feedback triggered counts: %ld\n", FIELD_GET(MT_ETBF_TX_FB_TRI, cnt)); - /* Tx SU counters */ + /* Tx SU & MU counters */ + cnt = mt76_rr(dev, MT_MIB_SDR34(ext_phy)); + seq_printf(s, "Tx multi-user Beamforming counts: %ld\n", + FIELD_GET(MT_MIB_MU_BF_TX_CNT, cnt)); + cnt = mt76_rr(dev, MT_MIB_DR8(ext_phy)); + seq_printf(s, "Tx multi-user MPDU counts: %d\n", cnt); + cnt = mt76_rr(dev, MT_MIB_DR9(ext_phy)); + seq_printf(s, "Tx multi-user successful MPDU counts: %d\n", cnt); cnt = mt76_rr(dev, MT_MIB_DR11(ext_phy)); seq_printf(s, "Tx single-user successful MPDU counts: %d\n", cnt); @@ -384,6 +391,7 @@ int mt7915_init_debugfs(struct mt7915_dev *dev) return 0; } +#ifdef CONFIG_MAC80211_DEBUGFS /** per-station debugfs **/ /* usage: <tx mode> <ldpc> <stbc> <bw> <gi> <nss> <mcs> */ @@ -461,3 +469,4 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, debugfs_create_file("fixed_rate", 0600, dir, sta, &fops_fixed_rate); debugfs_create_file("stats", 0400, dir, sta, &fops_sta_stats); } +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 766185d1aa21..a8832c5e6004 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -79,26 +79,27 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } +static void +mt7915_tx_cleanup(struct mt7915_dev *dev) +{ + mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_MCU_WA, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false); + mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false); +} + static int mt7915_poll_tx(struct napi_struct *napi, int budget) { - static const u8 queue_map[] = { - MT_TXQ_MCU, - MT_TXQ_MCU_WA, - MT_TXQ_BE - }; struct mt7915_dev *dev; - int i; dev = container_of(napi, struct mt7915_dev, mt76.tx_napi); - for (i = 0; i < ARRAY_SIZE(queue_map); i++) - mt76_queue_tx_cleanup(dev, queue_map[i], false); + mt7915_tx_cleanup(dev); if (napi_complete_done(napi, 0)) mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL); - for (i = 0; i < ARRAY_SIZE(queue_map); i++) - mt76_queue_tx_cleanup(dev, queue_map[i], false); + mt7915_tx_cleanup(dev); mt7915_mac_sta_poll(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index aadf56e80bae..e90d0087e377 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -417,11 +417,6 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; - he_cap_elem->mac_cap_info[1] = - IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_0US | - IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_1; - he_cap_elem->mac_cap_info[2] = - IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL | IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; @@ -443,27 +438,27 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ; - /* TODO: OFDMA */ - switch (i) { case NL80211_IFTYPE_AP: he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES; + he_cap_elem->mac_cap_info[2] |= + IEEE80211_HE_MAC_CAP2_BSR; he_cap_elem->mac_cap_info[4] |= IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->mac_cap_info[5] |= + IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX; he_cap_elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; he_cap_elem->phy_cap_info[6] |= IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; - he_cap_elem->phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; break; case NL80211_IFTYPE_STATION: he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; - he_cap_elem->mac_cap_info[3] |= - IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED; + he_cap_elem->mac_cap_info[1] |= + IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; if (band == NL80211_BAND_2GHZ) he_cap_elem->phy_cap_info[0] |= @@ -473,18 +468,31 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G; he_cap_elem->phy_cap_info[1] |= - IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A; + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; + he_cap_elem->phy_cap_info[3] |= + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK; + he_cap_elem->phy_cap_info[6] |= + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[7] |= + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484; he_cap_elem->phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; break; -#ifdef CONFIG_MAC80211_MESH - case NL80211_IFTYPE_MESH_POINT: - break; -#endif } he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index a264e304a3df..6825afca1efb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -178,14 +178,14 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev) static void mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, - struct mt7915_rxv *rxv, - struct ieee80211_radiotap_he *he) + struct ieee80211_radiotap_he *he, + __le32 *rxv) { u32 ru_h, ru_l; u8 ru, offs = 0; - ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv->v[0])); - ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv->v[1])); + ru_l = FIELD_GET(MT_PRXV_HE_RU_ALLOC_L, le32_to_cpu(rxv[0])); + ru_h = FIELD_GET(MT_PRXV_HE_RU_ALLOC_H, le32_to_cpu(rxv[1])); ru = (u8)(ru_l | ru_h << 4); status->bw = RATE_INFO_BW_HE_RU; @@ -228,7 +228,7 @@ mt7915_mac_decode_he_radiotap_ru(struct mt76_rx_status *status, static void mt7915_mac_decode_he_radiotap(struct sk_buff *skb, struct mt76_rx_status *status, - struct mt7915_rxv *rxv) + __le32 *rxv, u32 phy) { /* TODO: struct ieee80211_radiotap_he_mu */ static const struct ieee80211_radiotap_he known = { @@ -245,48 +245,45 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, HE_BITS(DATA2_TXOP_KNOWN), }; struct ieee80211_radiotap_he *he = NULL; - __le32 v2 = rxv->v[2]; - __le32 v11 = rxv->v[11]; - __le32 v14 = rxv->v[14]; - u32 ltf_size = le32_get_bits(v2, MT_CRXV_HE_LTF_SIZE) + 1; + u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1; he = skb_push(skb, sizeof(known)); memcpy(he, &known, sizeof(known)); - he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, v14) | - HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, v2); - he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, v2) | + he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) | + HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]); + he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) | le16_encode_bits(ltf_size, IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE); - he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, v14) | - HE_PREP(DATA6_DOPPLER, DOPPLER, v14); + he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) | + HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]); - switch (rxv->phy) { + switch (phy) { case MT_PHY_TYPE_HE_SU: he->data1 |= HE_BITS(DATA1_FORMAT_SU) | HE_BITS(DATA1_UL_DL_KNOWN) | HE_BITS(DATA1_BEAM_CHANGE_KNOWN) | HE_BITS(DATA1_SPTL_REUSE_KNOWN); - he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, v14) | - HE_PREP(DATA3_UL_DL, UPLINK, v2); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) | + HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); break; case MT_PHY_TYPE_HE_EXT_SU: he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) | HE_BITS(DATA1_UL_DL_KNOWN); - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); break; case MT_PHY_TYPE_HE_MU: he->data1 |= HE_BITS(DATA1_FORMAT_MU) | HE_BITS(DATA1_UL_DL_KNOWN) | HE_BITS(DATA1_SPTL_REUSE_KNOWN); - he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, v2); - he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, v11); + he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]); + he->data4 |= HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]); - mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + mt7915_mac_decode_he_radiotap_ru(status, he, rxv); break; case MT_PHY_TYPE_HE_TB: he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) | @@ -295,12 +292,12 @@ mt7915_mac_decode_he_radiotap(struct sk_buff *skb, HE_BITS(DATA1_SPTL_REUSE3_KNOWN) | HE_BITS(DATA1_SPTL_REUSE4_KNOWN); - he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, v11) | - HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, v11) | - HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, v11) | - HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, v11); + he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) | + HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]); - mt7915_mac_decode_he_radiotap_ru(status, rxv, he); + mt7915_mac_decode_he_radiotap_ru(status, he, rxv); break; default: break; @@ -314,8 +311,9 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) struct mt7915_phy *phy = &dev->phy; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; - struct mt7915_rxv rxv = {}; __le32 *rxd = (__le32 *)skb->data; + __le32 *rxv = NULL; + u32 mode = 0; u32 rxd1 = le32_to_cpu(rxd[1]); u32 rxd2 = le32_to_cpu(rxd[2]); u32 rxd3 = le32_to_cpu(rxd[3]); @@ -427,15 +425,14 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) if (rxd1 & MT_RXD1_NORMAL_GROUP_3) { u32 v0, v1, v2; - memcpy(rxv.v, rxd, sizeof(rxv.v)); - + rxv = rxd; rxd += 2; if ((u8 *)rxd - skb->data >= skb->len) return -EINVAL; - v0 = le32_to_cpu(rxv.v[0]); - v1 = le32_to_cpu(rxv.v[1]); - v2 = le32_to_cpu(rxv.v[2]); + v0 = le32_to_cpu(rxv[0]); + v1 = le32_to_cpu(rxv[1]); + v2 = le32_to_cpu(rxv[2]); if (v0 & MT_PRXV_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; @@ -466,9 +463,9 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) return -EINVAL; idx = i = FIELD_GET(MT_PRXV_TX_RATE, v0); - rxv.phy = FIELD_GET(MT_CRXV_TX_MODE, v2); + mode = FIELD_GET(MT_CRXV_TX_MODE, v2); - switch (rxv.phy) { + switch (mode) { case MT_PHY_TYPE_CCK: cck = true; /* fall through */ @@ -503,8 +500,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) if (gi <= NL80211_RATE_INFO_HE_GI_3_2) status->he_gi = gi; - if (idx & MT_PRXV_TX_DCM) - status->he_dcm = true; + status->he_dcm = !!(idx & MT_PRXV_TX_DCM); break; default: return -EINVAL; @@ -515,7 +511,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: - if (rxv.phy & MT_PHY_TYPE_HE_EXT_SU && + if (mode & MT_PHY_TYPE_HE_EXT_SU && (idx & MT_PRXV_TX_ER_SU_106T)) { status->bw = RATE_INFO_BW_HE_RU; status->he_ru = @@ -535,7 +531,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) } status->enc_flags |= RX_ENC_FLAG_STBC_MASK * stbc; - if (rxv.phy < MT_PHY_TYPE_HE_SU && gi) + if (mode < MT_PHY_TYPE_HE_SU && gi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; } } @@ -548,8 +544,8 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb) mt76_insert_ccmp_hdr(skb, key_id); } - if (status->flag & RX_FLAG_RADIOTAP_HE) - mt7915_mac_decode_he_radiotap(skb, status, &rxv); + if (rxv && status->flag & RX_FLAG_RADIOTAP_HE) + mt7915_mac_decode_he_radiotap(skb, status, rxv, mode); hdr = mt76_skb_get_hdr(skb); if (!status->wcid || !ieee80211_is_data_qos(hdr->frame_control)) @@ -591,16 +587,16 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; - if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { - q_idx = wmm_idx * MT7915_MAX_WMM_SETS + - skb_get_queue_mapping(skb); - p_fmt = MT_TX_TYPE_CT; - } else if (beacon) { - q_idx = MT_LMAC_BCN0; + if (beacon) { p_fmt = MT_TX_TYPE_FW; - } else { + q_idx = MT_LMAC_BCN0; + } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) { + p_fmt = MT_TX_TYPE_CT; q_idx = MT_LMAC_ALTX0; + } else { p_fmt = MT_TX_TYPE_CT; + q_idx = wmm_idx * MT7915_MAX_WMM_SETS + + mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb)); } val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) | @@ -616,6 +612,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi, FIELD_PREP(MT_TXD1_TID, skb->priority & IEEE80211_QOS_CTL_TID_MASK) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); + if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) val |= MT_TXD1_TGID; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h index b9bc8b25b031..c8bb5ea96c60 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h @@ -128,13 +128,6 @@ enum rx_pkt_type { #define MT_CRXV_HE_BEAM_CHNG BIT(13) #define MT_CRXV_HE_DOPPLER BIT(16) -struct mt7915_rxv { - u32 phy; - - /* P-RXV: bit 0~1, C-RXV: bit 2~19 */ - __le32 v[20]; -}; - enum tx_header_format { MT_HDR_FORMAT_802_3, MT_HDR_FORMAT_CMD, @@ -149,16 +142,6 @@ enum tx_pkt_type { MT_TX_TYPE_FW, }; -enum tx_pkt_queue_idx { - MT_LMAC_AC00, - MT_LMAC_AC01, - MT_LMAC_AC02, - MT_LMAC_AC03, - MT_LMAC_ALTX0 = 0x10, - MT_LMAC_BMC0 = 0x10, - MT_LMAC_BCN0 = 0x12, -}; - enum tx_port_idx { MT_TX_PORT_IDX_LMAC, MT_TX_PORT_IDX_MCU diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 05b5650c56c8..f95a0b55c4a2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -125,7 +125,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); - mvif->idx = ffs(~phy->vif_mask) - 1; + mvif->idx = ffs(~phy->mt76->vif_mask) - 1; if (mvif->idx >= MT7915_MAX_INTERFACES) { ret = -ENOSPC; goto out; @@ -150,7 +150,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, if (ret) goto out; - phy->vif_mask |= BIT(mvif->idx); + phy->mt76->vif_mask |= BIT(mvif->idx); phy->omac_mask |= BIT(mvif->omac_idx); idx = MT7915_WTBL_RESERVED - mvif->idx; @@ -194,7 +194,7 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, mt76_txq_remove(&dev->mt76, vif->txq); mutex_lock(&dev->mt76.mutex); - phy->vif_mask &= ~BIT(mvif->idx); + phy->mt76->vif_mask &= ~BIT(mvif->idx); phy->omac_mask &= ~BIT(mvif->omac_idx); mutex_unlock(&dev->mt76.mutex); @@ -350,13 +350,12 @@ static int mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { + struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; /* no need to update right away, we'll get BSS_CHANGED_QOS */ - mvif->wmm[queue].cw_min = params->cw_min; - mvif->wmm[queue].cw_max = params->cw_max; - mvif->wmm[queue].aifs = params->aifs; - mvif->wmm[queue].txop = params->txop; + queue = mt7915_lmac_mapping(dev, queue); + mvif->queue_params[queue] = *params; return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c8c12c740c1a..eaed5ef05401 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -312,8 +312,10 @@ mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data; int ret = 0; - if (seq != rxd->seq) - return -EAGAIN; + if (seq != rxd->seq) { + ret = -EAGAIN; + goto out; + } switch (cmd) { case -MCU_CMD_PATCH_SEM_CONTROL: @@ -330,6 +332,7 @@ mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd, default: break; } +out: dev_kfree_skb(skb); return ret; @@ -505,15 +508,22 @@ static void mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb) { struct mt7915_mcu_ra_info *ra = (struct mt7915_mcu_ra_info *)skb->data; - u16 wcidx = le16_to_cpu(ra->wlan_idx); - struct mt76_wcid *wcid = rcu_dereference(dev->mt76.wcid[wcidx]); - struct mt7915_sta *msta = container_of(wcid, struct mt7915_sta, wcid); - struct mt7915_sta_stats *stats = &msta->stats; - struct mt76_phy *mphy = &dev->mphy; struct rate_info rate = {}, prob_rate = {}; + u16 probe = le16_to_cpu(ra->prob_up_rate); u16 attempts = le16_to_cpu(ra->attempts); u16 curr = le16_to_cpu(ra->curr_rate); - u16 probe = le16_to_cpu(ra->prob_up_rate); + u16 wcidx = le16_to_cpu(ra->wlan_idx); + struct mt76_phy *mphy = &dev->mphy; + struct mt7915_sta_stats *stats; + struct mt7915_sta *msta; + struct mt76_wcid *wcid; + + if (wcidx >= MT76_N_WCIDS) + return; + + wcid = rcu_dereference(dev->mt76.wcid[wcidx]); + msta = container_of(wcid, struct mt7915_sta, wcid); + stats = &msta->stats; if (msta->wcid.ext_phy && dev->mt76.phy2) mphy = dev->mt76.phy2; @@ -1166,19 +1176,31 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev, struct wtbl_req_hdr *wtbl_hdr; struct tlv *sta_wtbl; struct sk_buff *skb; + int ret; skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, MT7915_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv)); wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, sta_wtbl, &skb); mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr); + ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); + if (ret) + return ret; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, + MT7915_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7915_mcu_sta_ba_tlv(skb, params, enable, tx); + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_STA_REC_UPDATE, true); } @@ -1466,16 +1488,39 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]); } +static int +mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct sk_buff *skb; + int len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_muru); + + if (!sta->vht_cap.vht_supported && !sta->he_cap.has_he) + return 0; + + skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + /* starec muru */ + mt7915_mcu_sta_muru_tlv(skb, sta); + + return __mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD_STA_REC_UPDATE, true); +} + static void mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta) { struct tlv *tlv; + /* starec ht */ if (sta->ht_cap.ht_supported) { struct sta_rec_ht *ht; - /* starec ht */ tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht)); ht = (struct sta_rec_ht *)tlv; ht->ht_cap = cpu_to_le16(sta->ht_cap.cap); @@ -1495,10 +1540,6 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb, /* starec he */ if (sta->he_cap.has_he) mt7915_mcu_sta_he_tlv(skb, sta); - - /* starec muru */ - if (sta->he_cap.has_he || sta->vht_cap.vht_supported) - mt7915_mcu_sta_muru_tlv(skb, sta); } static void @@ -2064,6 +2105,32 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, MCU_EXT_CMD_STA_REC_UPDATE, true); } +static int +mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ +#define MT_STA_BSS_GROUP 1 + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv; + struct { + __le32 action; + u8 wlan_idx_lo; + u8 status; + u8 wlan_idx_hi; + u8 rsv0[5]; + __le32 val; + u8 rsv1[8]; + } __packed req = { + .action = cpu_to_le32(MT_STA_BSS_GROUP), + .wlan_idx_lo = to_wcid_lo(msta->wcid.idx), + .wlan_idx_hi = to_wcid_hi(msta->wcid.idx), + .val = cpu_to_le32(mvif->idx), + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_DRR_CTRL, + &req, sizeof(req), true); +} + int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, bool enable) { @@ -2073,10 +2140,18 @@ int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif, return 0; /* must keep the order */ + ret = mt7915_mcu_add_group(dev, vif, sta); + if (ret) + return ret; + ret = mt7915_mcu_add_txbf(dev, vif, sta, enable); if (ret) return ret; + ret = mt7915_mcu_add_mu(dev, vif, sta); + if (ret) + return ret; + if (enable) return mt7915_mcu_add_rate_ctrl(dev, vif, sta); @@ -2823,23 +2898,23 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif) int ac; for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac]; struct edca *e = &req.edca[ac]; e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS; - e->aifs = mvif->wmm[ac].aifs; - e->txop = cpu_to_le16(mvif->wmm[ac].txop); + e->aifs = q->aifs; + e->txop = cpu_to_le16(q->txop); - if (mvif->wmm[ac].cw_min) - e->cw_min = fls(mvif->wmm[ac].cw_max); + if (q->cw_min) + e->cw_min = fls(q->cw_min); else e->cw_min = 5; - if (mvif->wmm[ac].cw_max) - e->cw_max = cpu_to_le16(fls(mvif->wmm[ac].cw_max)); + if (q->cw_max) + e->cw_max = cpu_to_le16(fls(q->cw_max)); else e->cw_max = cpu_to_le16(10); } - return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, sizeof(req), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index c241dd7c4c36..cb35e718409a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -201,6 +201,7 @@ enum { MCU_EXT_CMD_EDCA_UPDATE = 0x27, MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, MCU_EXT_CMD_THERMAL_CTRL = 0x2c, + MCU_EXT_CMD_SET_DRR_CTRL = 0x36, MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, @@ -653,7 +654,7 @@ struct sta_rec_muru { bool ofdma_ul_en; bool mimo_dl_en; bool mimo_ul_en; - bool rsv[4]; + u8 rsv[4]; } cfg; struct { @@ -664,7 +665,7 @@ struct sta_rec_muru { bool lt16_sigb; bool rx_su_comp_sigb; bool rx_su_non_comp_sigb; - bool rsv; + u8 rsv; } ofdma_dl; struct { @@ -951,7 +952,6 @@ enum { sizeof(struct sta_rec_ba) + \ sizeof(struct sta_rec_vht) + \ sizeof(struct tlv) + \ - sizeof(struct sta_rec_muru) + \ MT7915_WTBL_UPDATE_MAX_SIZE) #define MT7915_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index 85d74ecd0351..d8a13b4a2359 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -99,15 +99,10 @@ struct mt7915_vif { u8 band_idx; u8 wmm_idx; - struct { - u16 cw_min; - u16 cw_max; - u16 txop; - u8 aifs; - } wmm[IEEE80211_NUM_ACS]; - struct mt7915_sta sta; struct mt7915_dev *dev; + + struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; }; struct mib_stats { @@ -125,7 +120,6 @@ struct mt7915_phy { struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES]; u32 rxfilter; - u32 vif_mask; u32 omac_mask; u16 noise; @@ -200,6 +194,16 @@ enum { }; enum { + MT_LMAC_AC00, + MT_LMAC_AC01, + MT_LMAC_AC02, + MT_LMAC_AC03, + MT_LMAC_ALTX0 = 0x10, + MT_LMAC_BMC0, + MT_LMAC_BCN0, +}; + +enum { MT_RX_SEL0, MT_RX_SEL1, }; @@ -254,6 +258,21 @@ mt7915_ext_phy(struct mt7915_dev *dev) return phy->priv; } +static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac) +{ + static const u8 lmac_queue_map[] = { + [IEEE80211_AC_BK] = MT_LMAC_AC00, + [IEEE80211_AC_BE] = MT_LMAC_AC01, + [IEEE80211_AC_VI] = MT_LMAC_AC02, + [IEEE80211_AC_VO] = MT_LMAC_AC03, + }; + + if (WARN_ON_ONCE(ac >= ARRAY_SIZE(lmac_queue_map))) + return MT_LMAC_AC01; /* BE */ + + return lmac_queue_map[ac]; +} + static inline void mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid, enum mt7915_ampdu_state state) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index 7937c6965f59..0ec4e184b889 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -103,7 +103,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp), - .drv_flags = MT_DRV_TXWI_NO_FREE, + .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index c121715f8bff..e0989141d9da 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -117,11 +117,16 @@ #define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048) #define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR34(_band) MT_WF_MIB(_band, 0x090) +#define MT_MIB_MU_BF_TX_CNT GENMASK(15, 0) + #define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098) #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) #define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c) #define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) +#define MT_MIB_DR8(_band) MT_WF_MIB(_band, 0x0c0) +#define MT_MIB_DR9(_band) MT_WF_MIB(_band, 0x0c4) #define MT_MIB_DR11(_band) MT_WF_MIB(_band, 0x0cc) #define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4)) diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c index 04c5a692bc85..4c1c159fbb62 100644 --- a/drivers/net/wireless/mediatek/mt76/pci.c +++ b/drivers/net/wireless/mediatek/mt76/pci.c @@ -3,6 +3,7 @@ * Copyright (C) 2019 Lorenzo Bianconi <lorenzo@kernel.org> */ +#include "mt76.h" #include <linux/pci.h> void mt76_pci_disable_aspm(struct pci_dev *pdev) diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c new file mode 100644 index 000000000000..d2b38ed7f3b4 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 MediaTek Inc. + * + * This file is written based on mt76/usb.c. + * + * Author: Felix Fietkau <nbd@nbd.name> + * Lorenzo Bianconi <lorenzo@kernel.org> + * Sean Wang <sean.wang@mediatek.com> + */ + +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mmc/sdio_func.h> +#include <linux/sched.h> +#include <linux/kthread.h> + +#include "mt76.h" + +static int +mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid) +{ + struct mt76_queue *q = &dev->q_rx[qid]; + + spin_lock_init(&q->lock); + q->entry = devm_kcalloc(dev->dev, + MT_NUM_RX_ENTRIES, sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + + q->ndesc = MT_NUM_RX_ENTRIES; + q->head = q->tail = 0; + q->queued = 0; + + return 0; +} + +static int mt76s_alloc_tx(struct mt76_dev *dev) +{ + struct mt76_queue *q; + int i; + + for (i = 0; i < MT_TXQ_MCU_WA; i++) { + INIT_LIST_HEAD(&dev->q_tx[i].swq); + + q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL); + if (!q) + return -ENOMEM; + + spin_lock_init(&q->lock); + q->hw_idx = i; + dev->q_tx[i].q = q; + + q->entry = devm_kcalloc(dev->dev, + MT_NUM_TX_ENTRIES, sizeof(*q->entry), + GFP_KERNEL); + if (!q->entry) + return -ENOMEM; + + q->ndesc = MT_NUM_TX_ENTRIES; + } + + return 0; +} + +void mt76s_stop_txrx(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + + cancel_work_sync(&sdio->stat_work); + clear_bit(MT76_READING_STATS, &dev->phy.state); + + mt76_tx_status_check(dev, NULL, true); +} +EXPORT_SYMBOL_GPL(mt76s_stop_txrx); + +int mt76s_alloc_queues(struct mt76_dev *dev) +{ + int err; + + err = mt76s_alloc_rx_queue(dev, MT_RXQ_MAIN); + if (err < 0) + return err; + + return mt76s_alloc_tx(dev); +} +EXPORT_SYMBOL_GPL(mt76s_alloc_queues); + +static struct mt76_queue_entry * +mt76s_get_next_rx_entry(struct mt76_queue *q) +{ + struct mt76_queue_entry *e = NULL; + + spin_lock_bh(&q->lock); + if (q->queued > 0) { + e = &q->entry[q->head]; + q->head = (q->head + 1) % q->ndesc; + q->queued--; + } + spin_unlock_bh(&q->lock); + + return e; +} + +static int +mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) +{ + int qid = q - &dev->q_rx[MT_RXQ_MAIN]; + int nframes = 0; + + while (true) { + struct mt76_queue_entry *e; + + if (!test_bit(MT76_STATE_INITIALIZED, &dev->phy.state)) + break; + + e = mt76s_get_next_rx_entry(q); + if (!e || !e->skb) + break; + + dev->drv->rx_skb(dev, MT_RXQ_MAIN, e->skb); + e->skb = NULL; + nframes++; + } + if (qid == MT_RXQ_MAIN) + mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL); + + return nframes; +} + +static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid) +{ + struct mt76_sw_queue *sq = &dev->q_tx[qid]; + u32 n_dequeued = 0, n_sw_dequeued = 0; + struct mt76_queue_entry entry; + struct mt76_queue *q = sq->q; + bool wake; + + while (q->queued > n_dequeued) { + if (!q->entry[q->head].done) + break; + + if (q->entry[q->head].schedule) { + q->entry[q->head].schedule = false; + n_sw_dequeued++; + } + + entry = q->entry[q->head]; + q->entry[q->head].done = false; + q->head = (q->head + 1) % q->ndesc; + n_dequeued++; + + if (qid == MT_TXQ_MCU) + dev_kfree_skb(entry.skb); + else + dev->drv->tx_complete_skb(dev, qid, &entry); + } + + spin_lock_bh(&q->lock); + + sq->swq_queued -= n_sw_dequeued; + q->queued -= n_dequeued; + + wake = q->stopped && q->queued < q->ndesc - 8; + if (wake) + q->stopped = false; + + if (!q->queued) + wake_up(&dev->tx_wait); + + spin_unlock_bh(&q->lock); + + if (qid == MT_TXQ_MCU) + goto out; + + mt76_txq_schedule(&dev->phy, qid); + + if (wake) + ieee80211_wake_queue(dev->hw, qid); + + wake_up_process(dev->sdio.tx_kthread); +out: + return n_dequeued; +} + +static void mt76s_tx_status_data(struct work_struct *work) +{ + struct mt76_sdio *sdio; + struct mt76_dev *dev; + u8 update = 1; + u16 count = 0; + + sdio = container_of(work, struct mt76_sdio, stat_work); + dev = container_of(sdio, struct mt76_dev, sdio); + + while (true) { + if (test_bit(MT76_REMOVED, &dev->phy.state)) + break; + + if (!dev->drv->tx_status_data(dev, &update)) + break; + count++; + } + + if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) + queue_work(dev->wq, &sdio->stat_work); + else + clear_bit(MT76_READING_STATS, &dev->phy.state); +} + +static int +mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, struct mt76_wcid *wcid, + struct ieee80211_sta *sta) +{ + struct mt76_queue *q = dev->q_tx[qid].q; + struct mt76_tx_info tx_info = { + .skb = skb, + }; + int err, len = skb->len; + u16 idx = q->tail; + + if (q->queued == q->ndesc) + return -ENOSPC; + + skb->prev = skb->next = NULL; + err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); + if (err < 0) + return err; + + q->entry[q->tail].skb = tx_info.skb; + q->entry[q->tail].buf_sz = len; + q->tail = (q->tail + 1) % q->ndesc; + q->queued++; + + return idx; +} + +static int +mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid, + struct sk_buff *skb, u32 tx_info) +{ + struct mt76_queue *q = dev->q_tx[qid].q; + int ret = -ENOSPC, len = skb->len; + + spin_lock_bh(&q->lock); + if (q->queued == q->ndesc) + goto out; + + ret = mt76_skb_adjust_pad(skb); + if (ret) + goto out; + + q->entry[q->tail].buf_sz = len; + q->entry[q->tail].skb = skb; + q->tail = (q->tail + 1) % q->ndesc; + q->queued++; + +out: + spin_unlock_bh(&q->lock); + + return ret; +} + +static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) +{ + struct mt76_sdio *sdio = &dev->sdio; + + wake_up_process(sdio->tx_kthread); +} + +static const struct mt76_queue_ops sdio_queue_ops = { + .tx_queue_skb = mt76s_tx_queue_skb, + .kick = mt76s_tx_kick, + .tx_queue_skb_raw = mt76s_tx_queue_skb_raw, +}; + +static int mt76s_kthread_run(void *data) +{ + struct mt76_dev *dev = data; + struct mt76_phy *mphy = &dev->phy; + + while (!kthread_should_stop()) { + int i, nframes = 0; + + cond_resched(); + + /* rx processing */ + local_bh_disable(); + rcu_read_lock(); + + mt76_for_each_q_rx(dev, i) + nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]); + + rcu_read_unlock(); + local_bh_enable(); + + /* tx processing */ + for (i = 0; i < MT_TXQ_MCU_WA; i++) + nframes += mt76s_process_tx_queue(dev, i); + + if (dev->drv->tx_status_data && + !test_and_set_bit(MT76_READING_STATS, &mphy->state)) + queue_work(dev->wq, &dev->sdio.stat_work); + + if (!nframes || !test_bit(MT76_STATE_RUNNING, &mphy->state)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + } + + return 0; +} + +void mt76s_deinit(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + int i; + + kthread_stop(sdio->kthread); + kthread_stop(sdio->tx_kthread); + mt76s_stop_txrx(dev); + + sdio_claim_host(sdio->func); + sdio_release_irq(sdio->func); + sdio_release_host(sdio->func); + + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int j; + + for (j = 0; j < q->ndesc; j++) { + struct mt76_queue_entry *e = &q->entry[j]; + + if (!e->skb) + continue; + + dev_kfree_skb(e->skb); + e->skb = NULL; + } + } +} +EXPORT_SYMBOL_GPL(mt76s_deinit); + +int mt76s_init(struct mt76_dev *dev, struct sdio_func *func, + const struct mt76_bus_ops *bus_ops) +{ + struct mt76_sdio *sdio = &dev->sdio; + + sdio->kthread = kthread_create(mt76s_kthread_run, dev, "mt76s"); + if (IS_ERR(sdio->kthread)) + return PTR_ERR(sdio->kthread); + + INIT_WORK(&sdio->stat_work, mt76s_tx_status_data); + + mutex_init(&sdio->sched.lock); + dev->queue_ops = &sdio_queue_ops; + dev->bus = bus_ops; + dev->sdio.func = func; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76s_init); + +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>"); +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c new file mode 100644 index 000000000000..75bb02cdfdae --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/testmode.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */ +#include "mt76.h" + +static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { + [MT76_TM_ATTR_RESET] = { .type = NLA_FLAG }, + [MT76_TM_ATTR_STATE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 }, + [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 }, + [MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED }, + [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 }, +}; + +void mt76_testmode_tx_pending(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + struct mt76_wcid *wcid = &dev->global_wcid; + struct sk_buff *skb = td->tx_skb; + struct mt76_queue *q; + int qid; + + if (!skb || !td->tx_pending) + return; + + qid = skb_get_queue_mapping(skb); + q = dev->q_tx[qid].q; + + spin_lock_bh(&q->lock); + + while (td->tx_pending > 0 && q->queued < q->ndesc / 2) { + int ret; + + ret = dev->queue_ops->tx_queue_skb(dev, qid, skb_get(skb), wcid, NULL); + if (ret < 0) + break; + + td->tx_pending--; + td->tx_queued++; + } + + dev->queue_ops->kick(dev, q); + + spin_unlock_bh(&q->lock); +} + + +static int +mt76_testmode_tx_init(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + struct ieee80211_tx_info *info; + struct ieee80211_hdr *hdr; + struct sk_buff *skb; + u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | + IEEE80211_FCTL_FROMDS; + struct ieee80211_tx_rate *rate; + u8 max_nss = hweight8(dev->phy.antenna_mask); + + if (td->tx_antenna_mask) + max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask)); + + skb = alloc_skb(td->tx_msdu_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + dev_kfree_skb(td->tx_skb); + td->tx_skb = skb; + hdr = __skb_put_zero(skb, td->tx_msdu_len); + hdr->frame_control = cpu_to_le16(fc); + memcpy(hdr->addr1, dev->macaddr, sizeof(dev->macaddr)); + memcpy(hdr->addr2, dev->macaddr, sizeof(dev->macaddr)); + memcpy(hdr->addr3, dev->macaddr, sizeof(dev->macaddr)); + + info = IEEE80211_SKB_CB(skb); + info->flags = IEEE80211_TX_CTL_INJECTED | + IEEE80211_TX_CTL_NO_ACK | + IEEE80211_TX_CTL_NO_PS_BUFFER; + rate = &info->control.rates[0]; + rate->count = 1; + rate->idx = td->tx_rate_idx; + + switch (td->tx_rate_mode) { + case MT76_TM_TX_MODE_CCK: + if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ) + return -EINVAL; + + if (rate->idx > 4) + return -EINVAL; + break; + case MT76_TM_TX_MODE_OFDM: + if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ) + break; + + if (rate->idx > 8) + return -EINVAL; + + rate->idx += 4; + break; + case MT76_TM_TX_MODE_HT: + if (rate->idx > 8 * max_nss && + !(rate->idx == 32 && + dev->phy.chandef.width >= NL80211_CHAN_WIDTH_40)) + return -EINVAL; + + rate->flags |= IEEE80211_TX_RC_MCS; + break; + case MT76_TM_TX_MODE_VHT: + if (rate->idx > 9) + return -EINVAL; + + if (td->tx_rate_nss > max_nss) + return -EINVAL; + + ieee80211_rate_set_vht(rate, td->tx_rate_idx, td->tx_rate_nss); + rate->flags |= IEEE80211_TX_RC_VHT_MCS; + break; + default: + break; + } + + if (td->tx_rate_sgi) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + + if (td->tx_rate_ldpc) + info->flags |= IEEE80211_TX_CTL_LDPC; + + if (td->tx_rate_mode >= MT76_TM_TX_MODE_HT) { + switch (dev->phy.chandef.width) { + case NL80211_CHAN_WIDTH_40: + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + break; + case NL80211_CHAN_WIDTH_80: + rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; + break; + case NL80211_CHAN_WIDTH_80P80: + case NL80211_CHAN_WIDTH_160: + rate->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH; + break; + default: + break; + } + } + + skb_set_queue_mapping(skb, IEEE80211_AC_BE); + + return 0; +} + +static void +mt76_testmode_tx_start(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + + td->tx_queued = 0; + td->tx_done = 0; + td->tx_pending = td->tx_count; + tasklet_schedule(&dev->tx_tasklet); +} + +static void +mt76_testmode_tx_stop(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + + tasklet_disable(&dev->tx_tasklet); + + td->tx_pending = 0; + + tasklet_enable(&dev->tx_tasklet); + + wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ); + + dev_kfree_skb(td->tx_skb); + td->tx_skb = NULL; +} + +static inline void +mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx) +{ + td->param_set[idx / 32] |= BIT(idx % 32); +} + +static inline bool +mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx) +{ + return td->param_set[idx / 32] & BIT(idx % 32); +} + +static void +mt76_testmode_init_defaults(struct mt76_dev *dev) +{ + struct mt76_testmode_data *td = &dev->test; + + if (td->tx_msdu_len > 0) + return; + + td->tx_msdu_len = 1024; + td->tx_count = 1; + td->tx_rate_mode = MT76_TM_TX_MODE_OFDM; + td->tx_rate_nss = 1; +} + +static int +__mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state) +{ + enum mt76_testmode_state prev_state = dev->test.state; + int err; + + if (prev_state == MT76_TM_STATE_TX_FRAMES) + mt76_testmode_tx_stop(dev); + + if (state == MT76_TM_STATE_TX_FRAMES) { + err = mt76_testmode_tx_init(dev); + if (err) + return err; + } + + err = dev->test_ops->set_state(dev, state); + if (err) { + if (state == MT76_TM_STATE_TX_FRAMES) + mt76_testmode_tx_stop(dev); + + return err; + } + + if (state == MT76_TM_STATE_TX_FRAMES) + mt76_testmode_tx_start(dev); + else if (state == MT76_TM_STATE_RX_FRAMES) { + memset(&dev->test.rx_stats, 0, sizeof(dev->test.rx_stats)); + } + + dev->test.state = state; + + return 0; +} + +int mt76_testmode_set_state(struct mt76_dev *dev, enum mt76_testmode_state state) +{ + struct mt76_testmode_data *td = &dev->test; + struct ieee80211_hw *hw = dev->phy.hw; + + if (state == td->state && state == MT76_TM_STATE_OFF) + return 0; + + if (state > MT76_TM_STATE_OFF && + (!test_bit(MT76_STATE_RUNNING, &dev->phy.state) || + !(hw->conf.flags & IEEE80211_CONF_MONITOR))) + return -ENOTCONN; + + if (state != MT76_TM_STATE_IDLE && + td->state != MT76_TM_STATE_IDLE) { + int ret; + + ret = __mt76_testmode_set_state(dev, MT76_TM_STATE_IDLE); + if (ret) + return ret; + } + + return __mt76_testmode_set_state(dev, state); + +} +EXPORT_SYMBOL(mt76_testmode_set_state); + +static int +mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max) +{ + u8 val; + + if (!attr) + return 0; + + val = nla_get_u8(attr); + if (val < min || val > max) + return -EINVAL; + + *dest = val; + return 0; +} + +int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + void *data, int len) +{ + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_testmode_data *td = &dev->test; + struct nlattr *tb[NUM_MT76_TM_ATTRS]; + u32 state; + int err; + int i; + + if (!dev->test_ops) + return -EOPNOTSUPP; + + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + + err = -EINVAL; + + mutex_lock(&dev->mutex); + + if (tb[MT76_TM_ATTR_RESET]) { + mt76_testmode_set_state(dev, MT76_TM_STATE_OFF); + memset(td, 0, sizeof(*td)); + } + + mt76_testmode_init_defaults(dev); + + if (tb[MT76_TM_ATTR_TX_COUNT]) + td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]); + + if (tb[MT76_TM_ATTR_TX_LENGTH]) { + u32 val = nla_get_u32(tb[MT76_TM_ATTR_TX_LENGTH]); + + if (val > IEEE80211_MAX_FRAME_LEN || + val < sizeof(struct ieee80211_hdr)) + goto out; + + td->tx_msdu_len = val; + } + + if (tb[MT76_TM_ATTR_TX_RATE_IDX]) + td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]); + + if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode, + 0, MT76_TM_TX_MODE_MAX) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss, + 1, hweight8(phy->antenna_mask)) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 1) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, 1, + phy->antenna_mask) || + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL], + &td->tx_power_control, 0, 1)) + goto out; + + if (tb[MT76_TM_ATTR_FREQ_OFFSET]) + td->freq_offset = nla_get_u32(tb[MT76_TM_ATTR_FREQ_OFFSET]); + + if (tb[MT76_TM_ATTR_STATE]) { + state = nla_get_u32(tb[MT76_TM_ATTR_STATE]); + if (state > MT76_TM_STATE_MAX) + goto out; + } else { + state = td->state; + } + + if (tb[MT76_TM_ATTR_TX_POWER]) { + struct nlattr *cur; + int idx = 0; + int rem; + + nla_for_each_nested(cur, tb[MT76_TM_ATTR_TX_POWER], rem) { + if (nla_len(cur) != 1 || + idx >= ARRAY_SIZE(td->tx_power)) + goto out; + + td->tx_power[idx++] = nla_get_u8(cur); + } + } + + if (dev->test_ops->set_params) { + err = dev->test_ops->set_params(dev, tb, state); + if (err) + goto out; + } + + for (i = MT76_TM_ATTR_STATE; i < ARRAY_SIZE(tb); i++) + if (tb[i]) + mt76_testmode_param_set(td, i); + + err = 0; + if (tb[MT76_TM_ATTR_STATE]) + err = mt76_testmode_set_state(dev, state); + +out: + mutex_unlock(&dev->mutex); + + return err; +} +EXPORT_SYMBOL(mt76_testmode_cmd); + +static int +mt76_testmode_dump_stats(struct mt76_dev *dev, struct sk_buff *msg) +{ + struct mt76_testmode_data *td = &dev->test; + u64 rx_packets = 0; + u64 rx_fcs_error = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(td->rx_stats.packets); i++) { + rx_packets += td->rx_stats.packets[i]; + rx_fcs_error += td->rx_stats.fcs_error[i]; + } + + if (nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_PENDING, td->tx_pending) || + nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_QUEUED, td->tx_queued) || + nla_put_u32(msg, MT76_TM_STATS_ATTR_TX_DONE, td->tx_done) || + nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets, + MT76_TM_STATS_ATTR_PAD) || + nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error, + MT76_TM_STATS_ATTR_PAD)) + return -EMSGSIZE; + + if (dev->test_ops->dump_stats) + return dev->test_ops->dump_stats(dev, msg); + + return 0; +} + +int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, + struct netlink_callback *cb, void *data, int len) +{ + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_testmode_data *td = &dev->test; + struct nlattr *tb[NUM_MT76_TM_ATTRS] = {}; + int err = 0; + void *a; + int i; + + if (!dev->test_ops) + return -EOPNOTSUPP; + + if (cb->args[2]++ > 0) + return -ENOENT; + + if (data) { + err = nla_parse_deprecated(tb, MT76_TM_ATTR_MAX, data, len, + mt76_tm_policy, NULL); + if (err) + return err; + } + + mutex_lock(&dev->mutex); + + if (tb[MT76_TM_ATTR_STATS]) { + a = nla_nest_start(msg, MT76_TM_ATTR_STATS); + err = mt76_testmode_dump_stats(dev, msg); + nla_nest_end(msg, a); + + goto out; + } + + mt76_testmode_init_defaults(dev); + + err = -EMSGSIZE; + if (nla_put_u32(msg, MT76_TM_ATTR_STATE, td->state)) + goto out; + + if (td->mtd_name && + (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, td->mtd_name) || + nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, td->mtd_offset))) + goto out; + + if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) || + nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_msdu_len) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, td->tx_rate_nss) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) || + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) && + nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) && + nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) || + (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) && + nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset))) + goto out; + + if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) { + a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER); + if (!a) + goto out; + + for (i = 0; i < ARRAY_SIZE(td->tx_power); i++) + if (nla_put_u8(msg, i, td->tx_power[i])) + goto out; + + nla_nest_end(msg, a); + } + + err = 0; + +out: + mutex_unlock(&dev->mutex); + + return err; +} +EXPORT_SYMBOL(mt76_testmode_dump); diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h new file mode 100644 index 000000000000..691fe5773244 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/testmode.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> + */ +#ifndef __MT76_TESTMODE_H +#define __MT76_TESTMODE_H + +/** + * enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA + * + * @MT76_TM_ATTR_UNSPEC: (invalid attribute) + * + * @MT76_TM_ATTR_RESET: reset parameters to default (flag) + * @MT76_TM_ATTR_STATE: test state (u32), see &enum mt76_testmode_state + * + * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string) + * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32) + * + * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting + * state to MT76_TM_STATE_TX_FRAMES (u32) + * @MT76_TM_ATTR_TX_PENDING: pending frames during MT76_TM_STATE_TX_FRAMES (u32) + * @MT76_TM_ATTR_TX_LENGTH: packet tx msdu length (u32) + * @MT76_TM_ATTR_TX_RATE_MODE: packet tx mode (u8, see &enum mt76_testmode_tx_mode) + * @MT76_TM_ATTR_TX_RATE_NSS: packet tx number of spatial streams (u8) + * @MT76_TM_ATTR_TX_RATE_IDX: packet tx rate/MCS index (u8) + * @MT76_TM_ATTR_TX_RATE_SGI: packet tx use short guard interval (u8) + * @MT76_TM_ATTR_TX_RATE_LDPC: packet tx enable LDPC (u8) + * + * @MT76_TM_ATTR_TX_ANTENNA: tx antenna mask (u8) + * @MT76_TM_ATTR_TX_POWER_CONTROL: enable tx power control (u8) + * @MT76_TM_ATTR_TX_POWER: per-antenna tx power array (nested, u8 attrs) + * + * @MT76_TM_ATTR_FREQ_OFFSET: RF frequency offset (u32) + * + * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr) + */ +enum mt76_testmode_attr { + MT76_TM_ATTR_UNSPEC, + + MT76_TM_ATTR_RESET, + MT76_TM_ATTR_STATE, + + MT76_TM_ATTR_MTD_PART, + MT76_TM_ATTR_MTD_OFFSET, + + MT76_TM_ATTR_TX_COUNT, + MT76_TM_ATTR_TX_LENGTH, + MT76_TM_ATTR_TX_RATE_MODE, + MT76_TM_ATTR_TX_RATE_NSS, + MT76_TM_ATTR_TX_RATE_IDX, + MT76_TM_ATTR_TX_RATE_SGI, + MT76_TM_ATTR_TX_RATE_LDPC, + + MT76_TM_ATTR_TX_ANTENNA, + MT76_TM_ATTR_TX_POWER_CONTROL, + MT76_TM_ATTR_TX_POWER, + + MT76_TM_ATTR_FREQ_OFFSET, + + MT76_TM_ATTR_STATS, + + /* keep last */ + NUM_MT76_TM_ATTRS, + MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1, +}; + +/** + * enum mt76_testmode_state - statistics attributes + * + * @MT76_TM_STATS_ATTR_TX_PENDING: pending tx frames (u32) + * @MT76_TM_STATS_ATTR_TX_QUEUED: queued tx frames (u32) + * @MT76_TM_STATS_ATTR_TX_QUEUED: completed tx frames (u32) + * + * @MT76_TM_STATS_ATTR_RX_PACKETS: number of rx packets (u64) + * @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64) + * @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet + * see &enum mt76_testmode_rx_attr + */ +enum mt76_testmode_stats_attr { + MT76_TM_STATS_ATTR_UNSPEC, + MT76_TM_STATS_ATTR_PAD, + + MT76_TM_STATS_ATTR_TX_PENDING, + MT76_TM_STATS_ATTR_TX_QUEUED, + MT76_TM_STATS_ATTR_TX_DONE, + + MT76_TM_STATS_ATTR_RX_PACKETS, + MT76_TM_STATS_ATTR_RX_FCS_ERROR, + MT76_TM_STATS_ATTR_LAST_RX, + + /* keep last */ + NUM_MT76_TM_STATS_ATTRS, + MT76_TM_STATS_ATTR_MAX = NUM_MT76_TM_STATS_ATTRS - 1, +}; + + +/** + * enum mt76_testmode_rx_attr - packet rx information + * + * @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32) + * @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8) + * @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (s8) + * @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (s8) + */ +enum mt76_testmode_rx_attr { + MT76_TM_RX_ATTR_UNSPEC, + + MT76_TM_RX_ATTR_FREQ_OFFSET, + MT76_TM_RX_ATTR_RCPI, + MT76_TM_RX_ATTR_IB_RSSI, + MT76_TM_RX_ATTR_WB_RSSI, + + /* keep last */ + NUM_MT76_TM_RX_ATTRS, + MT76_TM_RX_ATTR_MAX = NUM_MT76_TM_RX_ATTRS - 1, +}; + +/** + * enum mt76_testmode_state - phy test state + * + * @MT76_TM_STATE_OFF: test mode disabled (normal operation) + * @MT76_TM_STATE_IDLE: test mode enabled, but idle + * @MT76_TM_STATE_TX_FRAMES: send a fixed number of test frames + * @MT76_TM_STATE_RX_FRAMES: receive packets and keep statistics + */ +enum mt76_testmode_state { + MT76_TM_STATE_OFF, + MT76_TM_STATE_IDLE, + MT76_TM_STATE_TX_FRAMES, + MT76_TM_STATE_RX_FRAMES, + + /* keep last */ + NUM_MT76_TM_STATES, + MT76_TM_STATE_MAX = NUM_MT76_TM_STATES - 1, +}; + +/** + * enum mt76_testmode_tx_mode - packet tx phy mode + * + * @MT76_TM_TX_MODE_CCK: legacy CCK mode + * @MT76_TM_TX_MODE_OFDM: legacy OFDM mode + * @MT76_TM_TX_MODE_HT: 802.11n MCS + * @MT76_TM_TX_MODE_VHT: 802.11ac MCS + */ +enum mt76_testmode_tx_mode { + MT76_TM_TX_MODE_CCK, + MT76_TM_TX_MODE_OFDM, + MT76_TM_TX_MODE_HT, + MT76_TM_TX_MODE_VHT, + + /* keep last */ + NUM_MT76_TM_TX_MODES, + MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1, +}; + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index f10c98aa883c..3afd89ecd6c9 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -236,6 +236,14 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb) struct ieee80211_hw *hw; struct sk_buff_head list; +#ifdef CONFIG_NL80211_TESTMODE + if (skb == dev->test.tx_skb) { + dev->test.tx_done++; + if (dev->test.tx_queued == dev->test.tx_done) + wake_up(&dev->tx_wait); + } +#endif + if (!skb->prev) { hw = mt76_tx_status_get_hw(dev, skb); ieee80211_free_txskb(hw, skb); @@ -259,6 +267,11 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, int qid = skb_get_queue_mapping(skb); bool ext_phy = phy != &dev->phy; + if (mt76_testmode_enabled(dev)) { + ieee80211_free_txskb(phy->hw, skb); + return; + } + if (WARN_ON(qid >= MT_TXQ_PSD)) { qid = MT_TXQ_BE; skb_set_queue_mapping(skb, qid); @@ -579,6 +592,11 @@ void mt76_tx_tasklet(unsigned long data) mt76_txq_schedule_all(&dev->phy); if (dev->phy2) mt76_txq_schedule_all(dev->phy2); + +#ifdef CONFIG_NL80211_TESTMODE + if (dev->test.tx_pending) + mt76_testmode_tx_pending(dev); +#endif } void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, @@ -659,3 +677,32 @@ u8 mt76_ac_to_hwq(u8 ac) return wmm_queue_map[ac]; } EXPORT_SYMBOL_GPL(mt76_ac_to_hwq); + +int mt76_skb_adjust_pad(struct sk_buff *skb) +{ + struct sk_buff *iter, *last = skb; + u32 pad; + + /* Add zero pad of 4 - 7 bytes */ + pad = round_up(skb->len, 4) + 4 - skb->len; + + /* First packet of a A-MSDU burst keeps track of the whole burst + * length, need to update length of it and the last packet. + */ + skb_walk_frags(skb, iter) { + last = iter; + if (!iter->next) { + skb->data_len += pad; + skb->len += pad; + break; + } + } + + if (skb_pad(last, pad)) + return -ENOMEM; + + __skb_put(last, pad); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 87382b2f7443..dcab5993763a 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -672,17 +672,11 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) static void mt76u_rx_tasklet(unsigned long data) { struct mt76_dev *dev = (struct mt76_dev *)data; - struct mt76_queue *q; int i; rcu_read_lock(); - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - - mt76u_process_rx_queue(dev, q); - } + mt76_for_each_q_rx(dev, i) + mt76u_process_rx_queue(dev, &dev->q_rx[i]); rcu_read_unlock(); } @@ -756,27 +750,19 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) static void mt76u_free_rx(struct mt76_dev *dev) { - struct mt76_queue *q; int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; - - mt76u_free_rx_queue(dev, q); - } + mt76_for_each_q_rx(dev, i) + mt76u_free_rx_queue(dev, &dev->q_rx[i]); } void mt76u_stop_rx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j; + int i; - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; - if (!q->ndesc) - continue; + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int j; for (j = 0; j < q->ndesc; j++) usb_poison_urb(q->entry[j].urb); @@ -788,14 +774,11 @@ EXPORT_SYMBOL_GPL(mt76u_stop_rx); int mt76u_resume_rx(struct mt76_dev *dev) { - struct mt76_queue *q; - int i, j, err; - - for (i = 0; i < __MT_RXQ_MAX; i++) { - q = &dev->q_rx[i]; + int i; - if (!q->ndesc) - continue; + mt76_for_each_q_rx(dev, i) { + struct mt76_queue *q = &dev->q_rx[i]; + int err, j; for (j = 0; j < q->ndesc; j++) usb_unpoison_urb(q->entry[j].urb); @@ -859,7 +842,7 @@ static void mt76u_tx_tasklet(unsigned long data) if (dev->drv->tx_status_data && !test_and_set_bit(MT76_READING_STATS, &dev->phy.state)) - queue_work(dev->usb.wq, &dev->usb.stat_work); + queue_work(dev->wq, &dev->usb.stat_work); if (wake) ieee80211_wake_queue(dev->hw, i); } @@ -885,7 +868,7 @@ static void mt76u_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state)) - queue_work(usb->wq, &usb->stat_work); + queue_work(dev->wq, &usb->stat_work); else clear_bit(MT76_READING_STATS, &dev->phy.state); } @@ -921,35 +904,6 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb, return urb->num_sgs; } -int mt76u_skb_dma_info(struct sk_buff *skb, u32 info) -{ - struct sk_buff *iter, *last = skb; - u32 pad; - - put_unaligned_le32(info, skb_push(skb, sizeof(info))); - /* Add zero pad of 4 - 7 bytes */ - pad = round_up(skb->len, 4) + 4 - skb->len; - - /* First packet of a A-MSDU burst keeps track of the whole burst - * length, need to update length of it and the last packet. - */ - skb_walk_frags(skb, iter) { - last = iter; - if (!iter->next) { - skb->data_len += pad; - skb->len += pad; - break; - } - } - - if (skb_pad(last, pad)) - return -ENOMEM; - __skb_put(last, pad); - - return 0; -} -EXPORT_SYMBOL_GPL(mt76u_skb_dma_info); - static int mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, @@ -1161,15 +1115,6 @@ static const struct mt76_queue_ops usb_queue_ops = { .kick = mt76u_tx_kick, }; -void mt76u_deinit(struct mt76_dev *dev) -{ - if (dev->usb.wq) { - destroy_workqueue(dev->usb.wq); - dev->usb.wq = NULL; - } -} -EXPORT_SYMBOL_GPL(mt76u_deinit); - int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, bool ext) { @@ -1192,10 +1137,6 @@ int mt76u_init(struct mt76_dev *dev, tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev); INIT_WORK(&usb->stat_work, mt76u_tx_status_data); - usb->wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0); - if (!usb->wq) - return -ENOMEM; - usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1); if (usb->data_len < 32) usb->data_len = 32; @@ -1219,7 +1160,8 @@ int mt76u_init(struct mt76_dev *dev, return 0; error: - mt76u_deinit(dev); + destroy_workqueue(dev->wq); + return err; } EXPORT_SYMBOL_GPL(mt76u_init); diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index ecde87465bf6..f53bb4ae5001 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -13,7 +13,7 @@ bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, timeout /= 10; do { - cur = dev->bus->rr(dev, offset) & mask; + cur = __mt76_rr(dev, offset) & mask; if (cur == val) return true; @@ -31,7 +31,7 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, timeout /= 10; do { - cur = dev->bus->rr(dev, offset) & mask; + cur = __mt76_rr(dev, offset) & mask; if (cur == val) return true; diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index af55ed82b96f..1b5cc271a9e1 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -116,8 +116,10 @@ mt7601u_mcu_msg_send(struct mt7601u_dev *dev, struct sk_buff *skb, int sent, ret; u8 seq = 0; - if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) + if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) { + consume_skb(skb); return 0; + } mutex_lock(&dev->mcu.mutex); diff --git a/drivers/net/wireless/microchip/Kconfig b/drivers/net/wireless/microchip/Kconfig new file mode 100644 index 000000000000..a6b46fb6b1ec --- /dev/null +++ b/drivers/net/wireless/microchip/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 +config WLAN_VENDOR_MICROCHIP + bool "Microchip devices" + default y + help + If you have a wireless card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for + your specific card in the following questions. + +if WLAN_VENDOR_MICROCHIP +source "drivers/net/wireless/microchip/wilc1000/Kconfig" +endif # WLAN_VENDOR_MICROCHIP diff --git a/drivers/net/wireless/microchip/Makefile b/drivers/net/wireless/microchip/Makefile new file mode 100644 index 000000000000..73b763c7393e --- /dev/null +++ b/drivers/net/wireless/microchip/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_WILC1000) += wilc1000/ diff --git a/drivers/net/wireless/microchip/wilc1000/Kconfig b/drivers/net/wireless/microchip/wilc1000/Kconfig new file mode 100644 index 000000000000..80c92e8bf8a5 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/Kconfig @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0 +config WILC1000 + tristate + help + Add support for the Atmel WILC1000 802.11 b/g/n SoC. + This provides Wi-FI over an SDIO or SPI interface, and + is usually found in IoT devices. + + This module only support IEEE 802.11n WiFi. + +config WILC1000_SDIO + tristate "Atmel WILC1000 SDIO (WiFi only)" + depends on CFG80211 && INET && MMC + select WILC1000 + help + This module adds support for the SDIO interface of adapters using + WILC1000 chipset. The Atmel WILC1000 SDIO is a full speed interface. + It meets SDIO card specification version 2.0. The interface supports + the 1-bit/4-bit SD transfer mode at the clock range of 0-50 MHz. + The host can use this interface to read and write from any register + within the chip as well as configure the WILC1000 for data DMA. + To use this interface, pin9 (SDIO_SPI_CFG) must be grounded. Select + this if your platform is using the SDIO bus. + +config WILC1000_SPI + tristate "Atmel WILC1000 SPI (WiFi only)" + depends on CFG80211 && INET && SPI + select WILC1000 + select CRC7 + help + This module adds support for the SPI interface of adapters using + WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral + Interface (SPI) that operates as a SPI slave. This SPI interface can + be used for control and for serial I/O of 802.11 data. The SPI is a + full-duplex slave synchronous serial interface that is available + immediately following reset when pin 9 (SDIO_SPI_CFG) is tied to + VDDIO. Select this if your platform is using the SPI bus. + +config WILC1000_HW_OOB_INTR + bool "WILC1000 out of band interrupt" + depends on WILC1000_SDIO + help + This option enables out-of-band interrupt support for the WILC1000 + chipset. This OOB interrupt is intended to provide a faster interrupt + mechanism for SDIO host controllers that don't support SDIO interrupt. + Select this option If the SDIO host controller in your platform + doesn't support SDIO time devision interrupt. diff --git a/drivers/net/wireless/microchip/wilc1000/Makefile b/drivers/net/wireless/microchip/wilc1000/Makefile new file mode 100644 index 000000000000..c3c9e34c1eaa --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_WILC1000) += wilc1000.o + +wilc1000-objs := cfg80211.o netdev.o mon.o \ + hif.o wlan_cfg.o wlan.o + +obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o +wilc1000-sdio-objs += sdio.o + +obj-$(CONFIG_WILC1000_SPI) += wilc1000-spi.o +wilc1000-spi-objs += spi.o diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c new file mode 100644 index 000000000000..c1ac1d84790f --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -0,0 +1,1849 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include "cfg80211.h" + +#define GO_NEG_REQ 0x00 +#define GO_NEG_RSP 0x01 +#define GO_NEG_CONF 0x02 +#define P2P_INV_REQ 0x03 +#define P2P_INV_RSP 0x04 + +#define WILC_INVALID_CHANNEL 0 + +/* Operation at 2.4 GHz with channels 1-13 */ +#define WILC_WLAN_OPERATING_CLASS_2_4GHZ 0x51 + +static const struct ieee80211_txrx_stypes + wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) + } +}; + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support wowlan_support = { + .flags = WIPHY_WOWLAN_ANY +}; +#endif + +struct wilc_p2p_mgmt_data { + int size; + u8 *buff; +}; + +struct wilc_p2p_pub_act_frame { + u8 category; + u8 action; + u8 oui[3]; + u8 oui_type; + u8 oui_subtype; + u8 dialog_token; + u8 elem[]; +} __packed; + +struct wilc_vendor_specific_ie { + u8 tag_number; + u8 tag_len; + u8 oui[3]; + u8 oui_type; + u8 attr[]; +} __packed; + +struct wilc_attr_entry { + u8 attr_type; + __le16 attr_len; + u8 val[]; +} __packed; + +struct wilc_attr_oper_ch { + u8 attr_type; + __le16 attr_len; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u8 op_class; + u8 op_channel; +} __packed; + +struct wilc_attr_ch_list { + u8 attr_type; + __le16 attr_len; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u8 elem[]; +} __packed; + +struct wilc_ch_list_elem { + u8 op_class; + u8 no_of_channels; + u8 ch_list[]; +} __packed; + +static void cfg_scan_result(enum scan_event scan_event, + struct wilc_rcvd_net_info *info, void *user_void) +{ + struct wilc_priv *priv = user_void; + + if (!priv->cfg_scanning) + return; + + if (scan_event == SCAN_EVENT_NETWORK_FOUND) { + s32 freq; + struct ieee80211_channel *channel; + struct cfg80211_bss *bss; + struct wiphy *wiphy = priv->dev->ieee80211_ptr->wiphy; + + if (!wiphy || !info) + return; + + freq = ieee80211_channel_to_frequency((s32)info->ch, + NL80211_BAND_2GHZ); + channel = ieee80211_get_channel(wiphy, freq); + if (!channel) + return; + + bss = cfg80211_inform_bss_frame(wiphy, channel, info->mgmt, + info->frame_len, + (s32)info->rssi * 100, + GFP_KERNEL); + if (!bss) + cfg80211_put_bss(wiphy, bss); + } else if (scan_event == SCAN_EVENT_DONE) { + mutex_lock(&priv->scan_req_lock); + + if (priv->scan_req) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + cfg80211_scan_done(priv->scan_req, &info); + priv->cfg_scanning = false; + priv->scan_req = NULL; + } + mutex_unlock(&priv->scan_req_lock); + } else if (scan_event == SCAN_EVENT_ABORTED) { + mutex_lock(&priv->scan_req_lock); + + if (priv->scan_req) { + struct cfg80211_scan_info info = { + .aborted = false, + }; + + cfg80211_scan_done(priv->scan_req, &info); + priv->cfg_scanning = false; + priv->scan_req = NULL; + } + mutex_unlock(&priv->scan_req_lock); + } +} + +static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, + void *priv_data) +{ + struct wilc_priv *priv = priv_data; + struct net_device *dev = priv->dev; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wl = vif->wilc; + struct host_if_drv *wfi_drv = priv->hif_drv; + struct wilc_conn_info *conn_info = &wfi_drv->conn_info; + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + + vif->connecting = false; + + if (conn_disconn_evt == CONN_DISCONN_EVENT_CONN_RESP) { + u16 connect_status = conn_info->status; + + if (mac_status == WILC_MAC_STATUS_DISCONNECTED && + connect_status == WLAN_STATUS_SUCCESS) { + connect_status = WLAN_STATUS_UNSPECIFIED_FAILURE; + wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); + + if (vif->iftype != WILC_CLIENT_MODE) + wl->sta_ch = WILC_INVALID_CHANNEL; + + netdev_err(dev, "Unspecified failure\n"); + } + + if (connect_status == WLAN_STATUS_SUCCESS) + memcpy(priv->associated_bss, conn_info->bssid, + ETH_ALEN); + + cfg80211_ref_bss(wiphy, vif->bss); + cfg80211_connect_bss(dev, conn_info->bssid, vif->bss, + conn_info->req_ies, + conn_info->req_ies_len, + conn_info->resp_ies, + conn_info->resp_ies_len, + connect_status, GFP_KERNEL, + NL80211_TIMEOUT_UNSPECIFIED); + + vif->bss = NULL; + } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) { + u16 reason = 0; + + eth_zero_addr(priv->associated_bss); + wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); + + if (vif->iftype != WILC_CLIENT_MODE) { + wl->sta_ch = WILC_INVALID_CHANNEL; + } else { + if (wfi_drv->ifc_up) + reason = 3; + else + reason = 1; + } + + cfg80211_disconnected(dev, reason, NULL, 0, false, GFP_KERNEL); + } +} + +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) +{ + struct wilc_vif *vif; + + vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list); + if (!vif) + return ERR_PTR(-EINVAL); + + return vif; +} + +static int set_channel(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + u32 channelnum; + int result; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return PTR_ERR(vif); + } + + channelnum = ieee80211_frequency_to_channel(chandef->chan->center_freq); + + wl->op_ch = channelnum; + result = wilc_set_mac_chnl_num(vif, channelnum); + if (result) + netdev_err(vif->ndev, "Error in setting channel\n"); + + srcu_read_unlock(&wl->srcu, srcu_idx); + return result; +} + +static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + struct wilc_vif *vif = netdev_priv(request->wdev->netdev); + struct wilc_priv *priv = &vif->priv; + u32 i; + int ret = 0; + u8 scan_ch_list[WILC_MAX_NUM_SCANNED_CH]; + u8 scan_type; + + if (request->n_channels > WILC_MAX_NUM_SCANNED_CH) { + netdev_err(vif->ndev, "Requested scanned channels over\n"); + return -EINVAL; + } + + priv->scan_req = request; + priv->cfg_scanning = true; + for (i = 0; i < request->n_channels; i++) { + u16 freq = request->channels[i]->center_freq; + + scan_ch_list[i] = ieee80211_frequency_to_channel(freq); + } + + if (request->n_ssids) + scan_type = WILC_FW_ACTIVE_SCAN; + else + scan_type = WILC_FW_PASSIVE_SCAN; + + ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list, + request->n_channels, cfg_scan_result, (void *)priv, + request); + + if (ret) { + priv->scan_req = NULL; + priv->cfg_scanning = false; + } + + return ret; +} + +static int connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *wfi_drv = priv->hif_drv; + int ret; + u32 i; + u8 security = WILC_FW_SEC_NO; + enum authtype auth_type = WILC_FW_AUTH_ANY; + u32 cipher_group; + struct cfg80211_bss *bss; + void *join_params; + u8 ch; + + vif->connecting = true; + + memset(priv->wep_key, 0, sizeof(priv->wep_key)); + memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); + + cipher_group = sme->crypto.cipher_group; + if (cipher_group != 0) { + if (cipher_group == WLAN_CIPHER_SUITE_WEP40) { + security = WILC_FW_SEC_WEP; + + priv->wep_key_len[sme->key_idx] = sme->key_len; + memcpy(priv->wep_key[sme->key_idx], sme->key, + sme->key_len); + + wilc_set_wep_default_keyid(vif, sme->key_idx); + wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len, + sme->key_idx); + } else if (cipher_group == WLAN_CIPHER_SUITE_WEP104) { + security = WILC_FW_SEC_WEP_EXTENDED; + + priv->wep_key_len[sme->key_idx] = sme->key_len; + memcpy(priv->wep_key[sme->key_idx], sme->key, + sme->key_len); + + wilc_set_wep_default_keyid(vif, sme->key_idx); + wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len, + sme->key_idx); + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) { + if (cipher_group == WLAN_CIPHER_SUITE_TKIP) + security = WILC_FW_SEC_WPA2_TKIP; + else + security = WILC_FW_SEC_WPA2_AES; + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) { + if (cipher_group == WLAN_CIPHER_SUITE_TKIP) + security = WILC_FW_SEC_WPA_TKIP; + else + security = WILC_FW_SEC_WPA_AES; + } else { + ret = -ENOTSUPP; + netdev_err(dev, "%s: Unsupported cipher\n", + __func__); + goto out_error; + } + } + + if ((sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) || + (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { + for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++) { + u32 ciphers_pairwise = sme->crypto.ciphers_pairwise[i]; + + if (ciphers_pairwise == WLAN_CIPHER_SUITE_TKIP) + security |= WILC_FW_TKIP; + else + security |= WILC_FW_AES; + } + } + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + auth_type = WILC_FW_AUTH_OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + auth_type = WILC_FW_AUTH_SHARED_KEY; + break; + + default: + break; + } + + if (sme->crypto.n_akm_suites) { + if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X) + auth_type = WILC_FW_AUTH_IEEE8021; + } + + if (wfi_drv->usr_scan_req.scan_result) { + netdev_err(vif->ndev, "%s: Scan in progress\n", __func__); + ret = -EBUSY; + goto out_error; + } + + bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid, sme->ssid, + sme->ssid_len, IEEE80211_BSS_TYPE_ANY, + IEEE80211_PRIVACY(sme->privacy)); + if (!bss) { + ret = -EINVAL; + goto out_error; + } + + if (ether_addr_equal_unaligned(vif->bssid, bss->bssid)) { + ret = -EALREADY; + goto out_put_bss; + } + + join_params = wilc_parse_join_bss_param(bss, &sme->crypto); + if (!join_params) { + netdev_err(dev, "%s: failed to construct join param\n", + __func__); + ret = -EINVAL; + goto out_put_bss; + } + + ch = ieee80211_frequency_to_channel(bss->channel->center_freq); + vif->wilc->op_ch = ch; + if (vif->iftype != WILC_CLIENT_MODE) + vif->wilc->sta_ch = ch; + + wilc_wlan_set_bssid(dev, bss->bssid, WILC_STATION_MODE); + + wfi_drv->conn_info.security = security; + wfi_drv->conn_info.auth_type = auth_type; + wfi_drv->conn_info.ch = ch; + wfi_drv->conn_info.conn_result = cfg_connect_result; + wfi_drv->conn_info.arg = priv; + wfi_drv->conn_info.param = join_params; + + ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len); + if (ret) { + netdev_err(dev, "wilc_set_join_req(): Error\n"); + ret = -ENOENT; + if (vif->iftype != WILC_CLIENT_MODE) + vif->wilc->sta_ch = WILC_INVALID_CHANNEL; + wilc_wlan_set_bssid(dev, NULL, WILC_STATION_MODE); + wfi_drv->conn_info.conn_result = NULL; + kfree(join_params); + goto out_put_bss; + } + kfree(join_params); + vif->bss = bss; + cfg80211_put_bss(wiphy, bss); + return 0; + +out_put_bss: + cfg80211_put_bss(wiphy, bss); + +out_error: + vif->connecting = false; + return ret; +} + +static int disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + struct wilc *wilc = vif->wilc; + int ret; + + vif->connecting = false; + + if (!wilc) + return -EIO; + + if (wilc->close) { + /* already disconnected done */ + cfg80211_disconnected(dev, 0, NULL, 0, true, GFP_KERNEL); + return 0; + } + + if (vif->iftype != WILC_CLIENT_MODE) + wilc->sta_ch = WILC_INVALID_CHANNEL; + wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE); + + priv->hif_drv->p2p_timeout = 0; + + ret = wilc_disconnect(vif); + if (ret != 0) { + netdev_err(priv->dev, "Error in disconnecting\n"); + ret = -EINVAL; + } + + vif->bss = NULL; + + return ret; +} + +static inline void wilc_wfi_cfg_copy_wep_info(struct wilc_priv *priv, + u8 key_index, + struct key_params *params) +{ + priv->wep_key_len[key_index] = params->key_len; + memcpy(priv->wep_key[key_index], params->key, params->key_len); +} + +static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx) +{ + if (!priv->wilc_gtk[idx]) { + priv->wilc_gtk[idx] = kzalloc(sizeof(*priv->wilc_gtk[idx]), + GFP_KERNEL); + if (!priv->wilc_gtk[idx]) + return -ENOMEM; + } + + if (!priv->wilc_ptk[idx]) { + priv->wilc_ptk[idx] = kzalloc(sizeof(*priv->wilc_ptk[idx]), + GFP_KERNEL); + if (!priv->wilc_ptk[idx]) + return -ENOMEM; + } + + return 0; +} + +static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info, + struct key_params *params) +{ + kfree(key_info->key); + + key_info->key = kmemdup(params->key, params->key_len, GFP_KERNEL); + if (!key_info->key) + return -ENOMEM; + + kfree(key_info->seq); + + if (params->seq_len > 0) { + key_info->seq = kmemdup(params->seq, params->seq_len, + GFP_KERNEL); + if (!key_info->seq) + return -ENOMEM; + } + + key_info->cipher = params->cipher; + key_info->key_len = params->key_len; + key_info->seq_len = params->seq_len; + + return 0; +} + +static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr, struct key_params *params) + +{ + int ret = 0, keylen = params->key_len; + const u8 *rx_mic = NULL; + const u8 *tx_mic = NULL; + u8 mode = WILC_FW_SEC_NO; + u8 op_mode; + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if (priv->wdev.iftype == NL80211_IFTYPE_AP) { + wilc_wfi_cfg_copy_wep_info(priv, key_index, params); + + if (params->cipher == WLAN_CIPHER_SUITE_WEP40) + mode = WILC_FW_SEC_WEP; + else + mode = WILC_FW_SEC_WEP_EXTENDED; + + ret = wilc_add_wep_key_bss_ap(vif, params->key, + params->key_len, + key_index, mode, + WILC_FW_AUTH_OPEN_SYSTEM); + break; + } + if (memcmp(params->key, priv->wep_key[key_index], + params->key_len)) { + wilc_wfi_cfg_copy_wep_info(priv, key_index, params); + + ret = wilc_add_wep_key_bss_sta(vif, params->key, + params->key_len, + key_index); + } + + break; + + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + if (priv->wdev.iftype == NL80211_IFTYPE_AP || + priv->wdev.iftype == NL80211_IFTYPE_P2P_GO) { + struct wilc_wfi_key *key; + + ret = wilc_wfi_cfg_allocate_wpa_entry(priv, key_index); + if (ret) + return -ENOMEM; + + if (params->key_len > 16 && + params->cipher == WLAN_CIPHER_SUITE_TKIP) { + tx_mic = params->key + 24; + rx_mic = params->key + 16; + keylen = params->key_len - 16; + } + + if (!pairwise) { + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) + mode = WILC_FW_SEC_WPA_TKIP; + else + mode = WILC_FW_SEC_WPA2_AES; + + priv->wilc_groupkey = mode; + + key = priv->wilc_gtk[key_index]; + } else { + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) + mode = WILC_FW_SEC_WPA_TKIP; + else + mode = priv->wilc_groupkey | WILC_FW_AES; + + key = priv->wilc_ptk[key_index]; + } + ret = wilc_wfi_cfg_copy_wpa_info(key, params); + if (ret) + return -ENOMEM; + + op_mode = WILC_AP_MODE; + } else { + if (params->key_len > 16 && + params->cipher == WLAN_CIPHER_SUITE_TKIP) { + rx_mic = params->key + 24; + tx_mic = params->key + 16; + keylen = params->key_len - 16; + } + + op_mode = WILC_STATION_MODE; + } + + if (!pairwise) + ret = wilc_add_rx_gtk(vif, params->key, keylen, + key_index, params->seq_len, + params->seq, rx_mic, tx_mic, + op_mode, mode); + else + ret = wilc_add_ptk(vif, params->key, keylen, mac_addr, + rx_mic, tx_mic, op_mode, mode, + key_index); + + break; + + default: + netdev_err(netdev, "%s: Unsupported cipher\n", __func__); + ret = -ENOTSUPP; + } + + return ret; +} + +static int del_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, + bool pairwise, + const u8 *mac_addr) +{ + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; + + if (priv->wilc_gtk[key_index]) { + kfree(priv->wilc_gtk[key_index]->key); + priv->wilc_gtk[key_index]->key = NULL; + kfree(priv->wilc_gtk[key_index]->seq); + priv->wilc_gtk[key_index]->seq = NULL; + + kfree(priv->wilc_gtk[key_index]); + priv->wilc_gtk[key_index] = NULL; + } + + if (priv->wilc_ptk[key_index]) { + kfree(priv->wilc_ptk[key_index]->key); + priv->wilc_ptk[key_index]->key = NULL; + kfree(priv->wilc_ptk[key_index]->seq); + priv->wilc_ptk[key_index]->seq = NULL; + kfree(priv->wilc_ptk[key_index]); + priv->wilc_ptk[key_index] = NULL; + } + + if (key_index <= 3 && priv->wep_key_len[key_index]) { + memset(priv->wep_key[key_index], 0, + priv->wep_key_len[key_index]); + priv->wep_key_len[key_index] = 0; + wilc_remove_wep_key(vif, key_index); + } + + return 0; +} + +static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, + bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params *)) +{ + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; + struct key_params key_params; + + if (!pairwise) { + key_params.key = priv->wilc_gtk[key_index]->key; + key_params.cipher = priv->wilc_gtk[key_index]->cipher; + key_params.key_len = priv->wilc_gtk[key_index]->key_len; + key_params.seq = priv->wilc_gtk[key_index]->seq; + key_params.seq_len = priv->wilc_gtk[key_index]->seq_len; + } else { + key_params.key = priv->wilc_ptk[key_index]->key; + key_params.cipher = priv->wilc_ptk[key_index]->cipher; + key_params.key_len = priv->wilc_ptk[key_index]->key_len; + key_params.seq = priv->wilc_ptk[key_index]->seq; + key_params.seq_len = priv->wilc_ptk[key_index]->seq_len; + } + + callback(cookie, &key_params); + + return 0; +} + +static int set_default_key(struct wiphy *wiphy, struct net_device *netdev, + u8 key_index, bool unicast, bool multicast) +{ + struct wilc_vif *vif = netdev_priv(netdev); + + wilc_set_wep_default_keyid(vif, key_index); + + return 0; +} + +static int get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + u32 i = 0; + u32 associatedsta = ~0; + u32 inactive_time = 0; + + if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) { + for (i = 0; i < NUM_STA_ASSOCIATED; i++) { + if (!(memcmp(mac, + priv->assoc_stainfo.sta_associated_bss[i], + ETH_ALEN))) { + associatedsta = i; + break; + } + } + + if (associatedsta == ~0) { + netdev_err(dev, "sta required is not associated\n"); + return -ENOENT; + } + + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_INACTIVE_TIME); + + wilc_get_inactive_time(vif, mac, &inactive_time); + sinfo->inactive_time = 1000 * inactive_time; + } else if (vif->iftype == WILC_STATION_MODE) { + struct rf_info stats; + + wilc_get_statistics(vif, &stats); + + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL) | + BIT_ULL(NL80211_STA_INFO_RX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_FAILED) | + BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + + sinfo->signal = stats.rssi; + sinfo->rx_packets = stats.rx_cnt; + sinfo->tx_packets = stats.tx_cnt + stats.tx_fail_cnt; + sinfo->tx_failed = stats.tx_fail_cnt; + sinfo->txrate.legacy = stats.link_speed * 10; + + if (stats.link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH && + stats.link_speed != DEFAULT_LINK_SPEED) + wilc_enable_tcp_ack_filter(vif, true); + else if (stats.link_speed != DEFAULT_LINK_SPEED) + wilc_enable_tcp_ack_filter(vif, false); + } + return 0; +} + +static int change_bss(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params) +{ + return 0; +} + +static int set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + int ret = -EINVAL; + struct cfg_param_attr cfg_param_val; + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + struct wilc_priv *priv; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) + goto out; + + priv = &vif->priv; + cfg_param_val.flag = 0; + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + netdev_dbg(vif->ndev, + "Setting WIPHY_PARAM_RETRY_SHORT %d\n", + wiphy->retry_short); + cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_SHORT; + cfg_param_val.short_retry_limit = wiphy->retry_short; + } + if (changed & WIPHY_PARAM_RETRY_LONG) { + netdev_dbg(vif->ndev, + "Setting WIPHY_PARAM_RETRY_LONG %d\n", + wiphy->retry_long); + cfg_param_val.flag |= WILC_CFG_PARAM_RETRY_LONG; + cfg_param_val.long_retry_limit = wiphy->retry_long; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + if (wiphy->frag_threshold > 255 && + wiphy->frag_threshold < 7937) { + netdev_dbg(vif->ndev, + "Setting WIPHY_PARAM_FRAG_THRESHOLD %d\n", + wiphy->frag_threshold); + cfg_param_val.flag |= WILC_CFG_PARAM_FRAG_THRESHOLD; + cfg_param_val.frag_threshold = wiphy->frag_threshold; + } else { + netdev_err(vif->ndev, + "Fragmentation threshold out of range\n"); + goto out; + } + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + if (wiphy->rts_threshold > 255) { + netdev_dbg(vif->ndev, + "Setting WIPHY_PARAM_RTS_THRESHOLD %d\n", + wiphy->rts_threshold); + cfg_param_val.flag |= WILC_CFG_PARAM_RTS_THRESHOLD; + cfg_param_val.rts_threshold = wiphy->rts_threshold; + } else { + netdev_err(vif->ndev, "RTS threshold out of range\n"); + goto out; + } + } + + ret = wilc_hif_set_cfg(vif, &cfg_param_val); + if (ret) + netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n"); + +out: + srcu_read_unlock(&wl->srcu, srcu_idx); + return ret; +} + +static int set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; + u32 i; + int ret = 0; + u8 flag = 0; + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + flag = PMKID_FOUND; + break; + } + } + if (i < WILC_MAX_NUM_PMKIDS) { + memcpy(priv->pmkid_list.pmkidlist[i].bssid, pmksa->bssid, + ETH_ALEN); + memcpy(priv->pmkid_list.pmkidlist[i].pmkid, pmksa->pmkid, + WLAN_PMKID_LEN); + if (!(flag == PMKID_FOUND)) + priv->pmkid_list.numpmkid++; + } else { + netdev_err(netdev, "Invalid PMKID index\n"); + ret = -EINVAL; + } + + if (!ret) + ret = wilc_set_pmkid_info(vif, &priv->pmkid_list); + + return ret; +} + +static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + u32 i; + struct wilc_vif *vif = netdev_priv(netdev); + struct wilc_priv *priv = &vif->priv; + + for (i = 0; i < priv->pmkid_list.numpmkid; i++) { + if (!memcmp(pmksa->bssid, priv->pmkid_list.pmkidlist[i].bssid, + ETH_ALEN)) { + memset(&priv->pmkid_list.pmkidlist[i], 0, + sizeof(struct wilc_pmkid)); + break; + } + } + + if (i == priv->pmkid_list.numpmkid) + return -EINVAL; + + for (; i < (priv->pmkid_list.numpmkid - 1); i++) { + memcpy(priv->pmkid_list.pmkidlist[i].bssid, + priv->pmkid_list.pmkidlist[i + 1].bssid, + ETH_ALEN); + memcpy(priv->pmkid_list.pmkidlist[i].pmkid, + priv->pmkid_list.pmkidlist[i + 1].pmkid, + WLAN_PMKID_LEN); + } + priv->pmkid_list.numpmkid--; + + return 0; +} + +static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) +{ + struct wilc_vif *vif = netdev_priv(netdev); + + memset(&vif->priv.pmkid_list, 0, sizeof(struct wilc_pmkid_attr)); + + return 0; +} + +static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch) +{ + struct wilc_attr_entry *e; + struct wilc_attr_ch_list *ch_list; + struct wilc_attr_oper_ch *op_ch; + u32 index = 0; + u8 ch_list_idx = 0; + u8 op_ch_idx = 0; + + if (sta_ch == WILC_INVALID_CHANNEL) + return; + + while (index + sizeof(*e) <= len) { + e = (struct wilc_attr_entry *)&buf[index]; + if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST) + ch_list_idx = index; + else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL) + op_ch_idx = index; + if (ch_list_idx && op_ch_idx) + break; + index += le16_to_cpu(e->attr_len) + sizeof(*e); + } + + if (ch_list_idx) { + u16 attr_size; + struct wilc_ch_list_elem *e; + int i; + + ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx]; + attr_size = le16_to_cpu(ch_list->attr_len); + for (i = 0; i < attr_size;) { + e = (struct wilc_ch_list_elem *)(ch_list->elem + i); + if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) { + memset(e->ch_list, sta_ch, e->no_of_channels); + break; + } + i += e->no_of_channels; + } + } + + if (op_ch_idx) { + op_ch = (struct wilc_attr_oper_ch *)&buf[op_ch_idx]; + op_ch->op_class = WILC_WLAN_OPERATING_CLASS_2_4GHZ; + op_ch->op_channel = sta_ch; + } +} + +void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size) +{ + struct wilc *wl = vif->wilc; + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *wfi_drv = priv->hif_drv; + struct ieee80211_mgmt *mgmt; + struct wilc_vendor_specific_ie *p; + struct wilc_p2p_pub_act_frame *d; + int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d); + const u8 *vendor_ie; + u32 header, pkt_offset; + s32 freq; + + header = get_unaligned_le32(buff - HOST_HDR_OFFSET); + pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header); + + if (pkt_offset & IS_MANAGMEMENT_CALLBACK) { + bool ack = false; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buff; + + if (ieee80211_is_probe_resp(hdr->frame_control) || + pkt_offset & IS_MGMT_STATUS_SUCCES) + ack = true; + + cfg80211_mgmt_tx_status(&priv->wdev, priv->tx_cookie, buff, + size, ack, GFP_KERNEL); + return; + } + + freq = ieee80211_channel_to_frequency(wl->op_ch, NL80211_BAND_2GHZ); + + mgmt = (struct ieee80211_mgmt *)buff; + if (!ieee80211_is_action(mgmt->frame_control)) + goto out_rx_mgmt; + + if (priv->cfg_scanning && + time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) { + netdev_dbg(vif->ndev, "Receiving action wrong ch\n"); + return; + } + + if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size)) + goto out_rx_mgmt; + + d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action); + if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP && + d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP) + goto out_rx_mgmt; + + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + buff + ie_offset, size - ie_offset); + if (!vendor_ie) + goto out_rx_mgmt; + + p = (struct wilc_vendor_specific_ie *)vendor_ie; + wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch); + +out_rx_mgmt: + cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0); +} + +static void wilc_wfi_mgmt_tx_complete(void *priv, int status) +{ + struct wilc_p2p_mgmt_data *pv_data = priv; + + kfree(pv_data->buff); + kfree(pv_data); +} + +static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie) +{ + struct wilc_vif *vif = data; + struct wilc_priv *priv = &vif->priv; + struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params; + + if (cookie != params->listen_cookie) + return; + + priv->p2p_listen_state = false; + + cfg80211_remain_on_channel_expired(&priv->wdev, params->listen_cookie, + params->listen_ch, GFP_KERNEL); +} + +static int remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + int ret = 0; + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; + u64 id; + + if (wdev->iftype == NL80211_IFTYPE_AP) { + netdev_dbg(vif->ndev, "Required while in AP mode\n"); + return ret; + } + + id = ++priv->inc_roc_cookie; + if (id == 0) + id = ++priv->inc_roc_cookie; + + ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value, + wilc_wfi_remain_on_channel_expired, + (void *)vif); + if (ret) + return ret; + + vif->wilc->op_ch = chan->hw_value; + + priv->remain_on_ch_params.listen_ch = chan; + priv->remain_on_ch_params.listen_cookie = id; + *cookie = id; + priv->p2p_listen_state = true; + priv->remain_on_ch_params.listen_duration = duration; + + cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL); + mod_timer(&vif->hif_drv->remain_on_ch_timer, + jiffies + msecs_to_jiffies(duration + 1000)); + + return ret; +} + +static int cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; + + if (cookie != priv->remain_on_ch_params.listen_cookie) + return -ENOENT; + + return wilc_listen_state_expired(vif, cookie); +} + +static int mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + struct ieee80211_channel *chan = params->chan; + unsigned int wait = params->wait; + const u8 *buf = params->buf; + size_t len = params->len; + const struct ieee80211_mgmt *mgmt; + struct wilc_p2p_mgmt_data *mgmt_tx; + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *wfi_drv = priv->hif_drv; + struct wilc_vendor_specific_ie *p; + struct wilc_p2p_pub_act_frame *d; + int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d); + const u8 *vendor_ie; + int ret = 0; + + *cookie = prandom_u32(); + priv->tx_cookie = *cookie; + mgmt = (const struct ieee80211_mgmt *)buf; + + if (!ieee80211_is_mgmt(mgmt->frame_control)) + goto out; + + mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_KERNEL); + if (!mgmt_tx) { + ret = -ENOMEM; + goto out; + } + + mgmt_tx->buff = kmemdup(buf, len, GFP_KERNEL); + if (!mgmt_tx->buff) { + ret = -ENOMEM; + kfree(mgmt_tx); + goto out; + } + + mgmt_tx->size = len; + + if (ieee80211_is_probe_resp(mgmt->frame_control)) { + wilc_set_mac_chnl_num(vif, chan->hw_value); + vif->wilc->op_ch = chan->hw_value; + goto out_txq_add_pkt; + } + + if (!ieee80211_is_public_action((struct ieee80211_hdr *)buf, len)) + goto out_set_timeout; + + d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action); + if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P || + d->oui_subtype != GO_NEG_CONF) { + wilc_set_mac_chnl_num(vif, chan->hw_value); + vif->wilc->op_ch = chan->hw_value; + } + + if (d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP) + goto out_set_timeout; + + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt_tx->buff + ie_offset, + len - ie_offset); + if (!vendor_ie) + goto out_set_timeout; + + p = (struct wilc_vendor_specific_ie *)vendor_ie; + wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch); + +out_set_timeout: + wfi_drv->p2p_timeout = (jiffies + msecs_to_jiffies(wait)); + +out_txq_add_pkt: + + wilc_wlan_txq_add_mgmt_pkt(wdev->netdev, mgmt_tx, + mgmt_tx->buff, mgmt_tx->size, + wilc_wfi_mgmt_tx_complete); + +out: + + return ret; +} + +static int mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *wfi_drv = priv->hif_drv; + + wfi_drv->p2p_timeout = jiffies; + + if (!priv->p2p_listen_state) { + struct wilc_wfi_p2p_listen_params *params; + + params = &priv->remain_on_ch_params; + + cfg80211_remain_on_channel_expired(wdev, + params->listen_cookie, + params->listen_ch, + GFP_KERNEL); + } + + return 0; +} + +void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd) +{ + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif = netdev_priv(wdev->netdev); + u32 presp_bit = BIT(IEEE80211_STYPE_PROBE_REQ >> 4); + u32 action_bit = BIT(IEEE80211_STYPE_ACTION >> 4); + + if (wl->initialized) { + bool prev = vif->mgmt_reg_stypes & presp_bit; + bool now = upd->interface_stypes & presp_bit; + + if (now != prev) + wilc_frame_register(vif, IEEE80211_STYPE_PROBE_REQ, now); + + prev = vif->mgmt_reg_stypes & action_bit; + now = upd->interface_stypes & action_bit; + + if (now != prev) + wilc_frame_register(vif, IEEE80211_STYPE_ACTION, now); + } + + vif->mgmt_reg_stypes = + upd->interface_stypes & (presp_bit | action_bit); +} + +static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst) +{ + return 0; +} + +static int dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct wilc_vif *vif = netdev_priv(dev); + int ret; + + if (idx != 0) + return -ENOENT; + + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); + + ret = wilc_get_rssi(vif, &sinfo->signal); + if (ret) + return ret; + + memcpy(mac, vif->priv.associated_bss, ETH_ALEN); + return 0; +} + +static int set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, + bool enabled, int timeout) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + + if (!priv->hif_drv) + return -EIO; + + wilc_set_power_mgmt(vif, enabled, timeout); + + return 0; +} + +static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + + switch (type) { + case NL80211_IFTYPE_STATION: + vif->connecting = false; + dev->ieee80211_ptr->iftype = type; + priv->wdev.iftype = type; + vif->monitor_flag = 0; + if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) + wilc_wfi_deinit_mon_interface(wl, true); + vif->iftype = WILC_STATION_MODE; + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); + + memset(priv->assoc_stainfo.sta_associated_bss, 0, + WILC_MAX_NUM_STA * ETH_ALEN); + break; + + case NL80211_IFTYPE_P2P_CLIENT: + vif->connecting = false; + dev->ieee80211_ptr->iftype = type; + priv->wdev.iftype = type; + vif->monitor_flag = 0; + vif->iftype = WILC_CLIENT_MODE; + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); + break; + + case NL80211_IFTYPE_AP: + dev->ieee80211_ptr->iftype = type; + priv->wdev.iftype = type; + vif->iftype = WILC_AP_MODE; + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_AP_MODE, vif->idx); + break; + + case NL80211_IFTYPE_P2P_GO: + dev->ieee80211_ptr->iftype = type; + priv->wdev.iftype = type; + vif->iftype = WILC_GO_MODE; + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_AP_MODE, vif->idx); + break; + + default: + netdev_err(dev, "Unknown interface type= %d\n", type); + return -EINVAL; + } + + return 0; +} + +static int start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + struct wilc_vif *vif = netdev_priv(dev); + int ret; + + ret = set_channel(wiphy, &settings->chandef); + if (ret != 0) + netdev_err(dev, "Error in setting channel\n"); + + wilc_wlan_set_bssid(dev, dev->dev_addr, WILC_AP_MODE); + + return wilc_add_beacon(vif, settings->beacon_interval, + settings->dtim_period, &settings->beacon); +} + +static int change_beacon(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_beacon_data *beacon) +{ + struct wilc_vif *vif = netdev_priv(dev); + + return wilc_add_beacon(vif, 0, 0, beacon); +} + +static int stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + int ret; + struct wilc_vif *vif = netdev_priv(dev); + + wilc_wlan_set_bssid(dev, NULL, WILC_AP_MODE); + + ret = wilc_del_beacon(vif); + + if (ret) + netdev_err(dev, "Host delete beacon fail\n"); + + return ret; +} + +static int add_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + int ret = 0; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + + if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) { + memcpy(priv->assoc_stainfo.sta_associated_bss[params->aid], mac, + ETH_ALEN); + + ret = wilc_add_station(vif, mac, params); + if (ret) + netdev_err(dev, "Host add station fail\n"); + } + + return ret; +} + +static int del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + const u8 *mac = params->mac; + int ret = 0; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc_priv *priv = &vif->priv; + struct sta_info *info; + + if (!(vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE)) + return ret; + + info = &priv->assoc_stainfo; + + if (!mac) + ret = wilc_del_allstation(vif, info->sta_associated_bss); + + ret = wilc_del_station(vif, mac); + if (ret) + netdev_err(dev, "Host delete station fail\n"); + return ret; +} + +static int change_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_parameters *params) +{ + int ret = 0; + struct wilc_vif *vif = netdev_priv(dev); + + if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) { + ret = wilc_edit_station(vif, mac, params); + if (ret) + netdev_err(dev, "Host edit station fail\n"); + } + return ret; +} + +static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type) +{ + struct wilc_vif *vif; + + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->iftype == type) + return vif; + } + + return NULL; +} + +static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params) +{ + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + struct wireless_dev *wdev; + int iftype; + + if (type == NL80211_IFTYPE_MONITOR) { + struct net_device *ndev; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_vif_from_type(wl, WILC_AP_MODE); + if (!vif) { + vif = wilc_get_vif_from_type(wl, WILC_GO_MODE); + if (!vif) { + srcu_read_unlock(&wl->srcu, srcu_idx); + goto validate_interface; + } + } + + if (vif->monitor_flag) { + srcu_read_unlock(&wl->srcu, srcu_idx); + goto validate_interface; + } + + ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev); + if (ndev) { + vif->monitor_flag = 1; + } else { + srcu_read_unlock(&wl->srcu, srcu_idx); + return ERR_PTR(-EINVAL); + } + + wdev = &vif->priv.wdev; + srcu_read_unlock(&wl->srcu, srcu_idx); + return wdev; + } + +validate_interface: + mutex_lock(&wl->vif_mutex); + if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) { + pr_err("Reached maximum number of interface\n"); + mutex_unlock(&wl->vif_mutex); + return ERR_PTR(-EINVAL); + } + mutex_unlock(&wl->vif_mutex); + + switch (type) { + case NL80211_IFTYPE_STATION: + iftype = WILC_STATION_MODE; + break; + case NL80211_IFTYPE_AP: + iftype = WILC_AP_MODE; + break; + default: + return ERR_PTR(-EOPNOTSUPP); + } + + vif = wilc_netdev_ifc_init(wl, name, iftype, type, true); + if (IS_ERR(vif)) + return ERR_CAST(vif); + + return &vif->priv.wdev; +} + +static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + + if (wdev->iftype == NL80211_IFTYPE_AP || + wdev->iftype == NL80211_IFTYPE_P2P_GO) + wilc_wfi_deinit_mon_interface(wl, true); + vif = netdev_priv(wdev->netdev); + cfg80211_stop_iface(wiphy, wdev, GFP_KERNEL); + unregister_netdevice(vif->ndev); + vif->monitor_flag = 0; + + wilc_set_operation_mode(vif, 0, 0, 0); + mutex_lock(&wl->vif_mutex); + list_del_rcu(&vif->list); + wl->vif_num--; + mutex_unlock(&wl->vif_mutex); + synchronize_srcu(&wl->srcu); + return 0; +} + +static int wilc_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) +{ + struct wilc *wl = wiphy_priv(wiphy); + + if (!wow && wilc_wlan_get_num_conn_ifcs(wl)) + wl->suspend_event = true; + else + wl->suspend_event = false; + + return 0; +} + +static int wilc_resume(struct wiphy *wiphy) +{ + return 0; +} + +static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled) +{ + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return; + } + + netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled); + srcu_read_unlock(&wl->srcu, srcu_idx); +} + +static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + int ret; + int srcu_idx; + s32 tx_power = MBM_TO_DBM(mbm); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + + if (!wl->initialized) + return -EIO; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return -EINVAL; + } + + netdev_info(vif->ndev, "Setting tx power %d\n", tx_power); + if (tx_power < 0) + tx_power = 0; + else if (tx_power > 18) + tx_power = 18; + ret = wilc_set_tx_power(vif, tx_power); + if (ret) + netdev_err(vif->ndev, "Failed to set tx power\n"); + srcu_read_unlock(&wl->srcu, srcu_idx); + + return ret; +} + +static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + int *dbm) +{ + int ret; + struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc *wl = vif->wilc; + + /* If firmware is not started, return. */ + if (!wl->initialized) + return -EIO; + + ret = wilc_get_tx_power(vif, (u8 *)dbm); + if (ret) + netdev_err(vif->ndev, "Failed to get tx power\n"); + + return ret; +} + +static const struct cfg80211_ops wilc_cfg80211_ops = { + .set_monitor_channel = set_channel, + .scan = scan, + .connect = connect, + .disconnect = disconnect, + .add_key = add_key, + .del_key = del_key, + .get_key = get_key, + .set_default_key = set_default_key, + .add_virtual_intf = add_virtual_intf, + .del_virtual_intf = del_virtual_intf, + .change_virtual_intf = change_virtual_intf, + + .start_ap = start_ap, + .change_beacon = change_beacon, + .stop_ap = stop_ap, + .add_station = add_station, + .del_station = del_station, + .change_station = change_station, + .get_station = get_station, + .dump_station = dump_station, + .change_bss = change_bss, + .set_wiphy_params = set_wiphy_params, + + .set_pmksa = set_pmksa, + .del_pmksa = del_pmksa, + .flush_pmksa = flush_pmksa, + .remain_on_channel = remain_on_channel, + .cancel_remain_on_channel = cancel_remain_on_channel, + .mgmt_tx_cancel_wait = mgmt_tx_cancel_wait, + .mgmt_tx = mgmt_tx, + .update_mgmt_frame_registrations = wilc_update_mgmt_frame_registrations, + .set_power_mgmt = set_power_mgmt, + .set_cqm_rssi_config = set_cqm_rssi_config, + + .suspend = wilc_suspend, + .resume = wilc_resume, + .set_wakeup = wilc_set_wakeup, + .set_tx_power = set_tx_power, + .get_tx_power = get_tx_power, + +}; + +static void wlan_init_locks(struct wilc *wl) +{ + mutex_init(&wl->hif_cs); + mutex_init(&wl->rxq_cs); + mutex_init(&wl->cfg_cmd_lock); + mutex_init(&wl->vif_mutex); + + spin_lock_init(&wl->txq_spinlock); + mutex_init(&wl->txq_add_to_head_cs); + + init_completion(&wl->txq_event); + init_completion(&wl->cfg_event); + init_completion(&wl->sync_event); + init_completion(&wl->txq_thread_started); + init_srcu_struct(&wl->srcu); +} + +void wlan_deinit_locks(struct wilc *wilc) +{ + mutex_destroy(&wilc->hif_cs); + mutex_destroy(&wilc->rxq_cs); + mutex_destroy(&wilc->cfg_cmd_lock); + mutex_destroy(&wilc->txq_add_to_head_cs); + mutex_destroy(&wilc->vif_mutex); + cleanup_srcu_struct(&wilc->srcu); +} + +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops) +{ + struct wilc *wl; + struct wilc_vif *vif; + int ret; + + wl = wilc_create_wiphy(dev); + if (!wl) + return -EINVAL; + + wlan_init_locks(wl); + + ret = wilc_wlan_cfg_init(wl); + if (ret) + goto free_wl; + + *wilc = wl; + wl->io_type = io_type; + wl->hif_func = ops; + wl->chip_ps_state = WILC_CHIP_WAKEDUP; + INIT_LIST_HEAD(&wl->txq_head.list); + INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); + + wl->hif_workqueue = create_singlethread_workqueue("WILC_wq"); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_cfg; + } + vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, + NL80211_IFTYPE_STATION, false); + if (IS_ERR(vif)) { + ret = PTR_ERR(vif); + goto free_hq; + } + + return 0; + +free_hq: + destroy_workqueue(wl->hif_workqueue); + +free_cfg: + wilc_wlan_cfg_deinit(wl); + +free_wl: + wlan_deinit_locks(wl); + wiphy_unregister(wl->wiphy); + wiphy_free(wl->wiphy); + return ret; +} +EXPORT_SYMBOL_GPL(wilc_cfg80211_init); + +struct wilc *wilc_create_wiphy(struct device *dev) +{ + struct wiphy *wiphy; + struct wilc *wl; + int ret; + + wiphy = wiphy_new(&wilc_cfg80211_ops, sizeof(*wl)); + if (!wiphy) + return NULL; + + wl = wiphy_priv(wiphy); + + memcpy(wl->bitrates, wilc_bitrates, sizeof(wilc_bitrates)); + memcpy(wl->channels, wilc_2ghz_channels, sizeof(wilc_2ghz_channels)); + wl->band.bitrates = wl->bitrates; + wl->band.n_bitrates = ARRAY_SIZE(wl->bitrates); + wl->band.channels = wl->channels; + wl->band.n_channels = ARRAY_SIZE(wilc_2ghz_channels); + + wl->band.ht_cap.ht_supported = 1; + wl->band.ht_cap.cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + wl->band.ht_cap.mcs.rx_mask[0] = 0xff; + wl->band.ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K; + wl->band.ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; + + wiphy->bands[NL80211_BAND_2GHZ] = &wl->band; + + wiphy->max_scan_ssids = WILC_MAX_NUM_PROBED_SSID; +#ifdef CONFIG_PM + wiphy->wowlan = &wowlan_support; +#endif + wiphy->max_num_pmkids = WILC_MAX_NUM_PMKIDS; + wiphy->max_scan_ie_len = 1000; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + memcpy(wl->cipher_suites, wilc_cipher_suites, + sizeof(wilc_cipher_suites)); + wiphy->cipher_suites = wl->cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(wilc_cipher_suites); + wiphy->mgmt_stypes = wilc_wfi_cfg80211_mgmt_types; + + wiphy->max_remain_on_channel_duration = 500; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MONITOR) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); + wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + + set_wiphy_dev(wiphy, dev); + wl->wiphy = wiphy; + ret = wiphy_register(wiphy); + if (ret) { + wiphy_free(wiphy); + return NULL; + } + return wl; +} + +int wilc_init_host_int(struct net_device *net) +{ + int ret; + struct wilc_vif *vif = netdev_priv(net); + struct wilc_priv *priv = &vif->priv; + + priv->p2p_listen_state = false; + + mutex_init(&priv->scan_req_lock); + ret = wilc_init(net, &priv->hif_drv); + if (ret) + netdev_err(net, "Error while initializing hostinterface\n"); + + return ret; +} + +void wilc_deinit_host_int(struct net_device *net) +{ + int ret; + struct wilc_vif *vif = netdev_priv(net); + struct wilc_priv *priv = &vif->priv; + + priv->p2p_listen_state = false; + + flush_workqueue(vif->wilc->hif_workqueue); + mutex_destroy(&priv->scan_req_lock); + ret = wilc_deinit(vif); + + if (ret) + netdev_err(net, "Error while deinitializing host interface\n"); +} + diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.h b/drivers/net/wireless/microchip/wilc1000/cfg80211.h new file mode 100644 index 000000000000..37b294cb3b37 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef WILC_CFG80211_H +#define WILC_CFG80211_H +#include "netdev.h" + +struct wiphy *wilc_cfg_alloc(void); +int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, + const struct wilc_hif_func *ops); +struct wilc *wilc_create_wiphy(struct device *dev); +void wilc_deinit_host_int(struct net_device *net); +int wilc_init_host_int(struct net_device *net); +void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size); +struct wilc_vif *wilc_netdev_interface(struct wilc *wl, const char *name, + enum nl80211_iftype type); +void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked); +struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, + const char *name, + struct net_device *real_dev); +void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd); +struct wilc_vif *wilc_get_interface(struct wilc *wl); +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl); +void wlan_deinit_locks(struct wilc *wilc); +#endif diff --git a/drivers/net/wireless/microchip/wilc1000/fw.h b/drivers/net/wireless/microchip/wilc1000/fw.h new file mode 100644 index 000000000000..a76e1dea4345 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/fw.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef WILC_FW_H +#define WILC_FW_H + +#include <linux/ieee80211.h> + +#define WILC_MAX_NUM_STA 9 +#define WILC_MAX_RATES_SUPPORTED 12 +#define WILC_MAX_NUM_PMKIDS 16 +#define WILC_MAX_NUM_SCANNED_CH 14 + +struct wilc_assoc_resp { + __le16 capab_info; + __le16 status_code; + __le16 aid; +} __packed; + +struct wilc_pmkid { + u8 bssid[ETH_ALEN]; + u8 pmkid[WLAN_PMKID_LEN]; +} __packed; + +struct wilc_pmkid_attr { + u8 numpmkid; + struct wilc_pmkid pmkidlist[WILC_MAX_NUM_PMKIDS]; +} __packed; + +struct wilc_reg_frame { + u8 reg; + u8 reg_id; + __le16 frame_type; +} __packed; + +struct wilc_drv_handler { + __le32 handler; + u8 mode; +} __packed; + +struct wilc_wep_key { + u8 index; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_sta_wpa_ptk { + u8 mac_addr[ETH_ALEN]; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_ap_wpa_ptk { + u8 mac_addr[ETH_ALEN]; + u8 index; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_gtk_key { + u8 mac_addr[ETH_ALEN]; + u8 rsc[8]; + u8 index; + u8 key_len; + u8 key[0]; +} __packed; + +struct wilc_op_mode { + __le32 mode; +} __packed; + +struct wilc_noa_opp_enable { + u8 ct_window; + u8 cnt; + __le32 duration; + __le32 interval; + __le32 start_time; +} __packed; + +struct wilc_noa_opp_disable { + u8 cnt; + __le32 duration; + __le32 interval; + __le32 start_time; +} __packed; + +struct wilc_join_bss_param { + char ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_terminator; + u8 bss_type; + u8 ch; + __le16 cap_info; + u8 sa[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + __le16 beacon_period; + u8 dtim_period; + u8 supp_rates[WILC_MAX_RATES_SUPPORTED + 1]; + u8 wmm_cap; + u8 uapsd_cap; + u8 ht_capable; + u8 rsn_found; + u8 rsn_grp_policy; + u8 mode_802_11i; + u8 p_suites[3]; + u8 akm_suites[3]; + u8 rsn_cap[2]; + u8 noa_enabled; + __le32 tsf_lo; + u8 idx; + u8 opp_enabled; + union { + struct wilc_noa_opp_disable opp_dis; + struct wilc_noa_opp_enable opp_en; + }; +} __packed; +#endif diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c new file mode 100644 index 000000000000..d025a3093015 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -0,0 +1,1961 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include "netdev.h" + +#define WILC_HIF_SCAN_TIMEOUT_MS 5000 +#define WILC_HIF_CONNECT_TIMEOUT_MS 9500 + +#define WILC_FALSE_FRMWR_CHANNEL 100 + +#define WILC_SCAN_WID_LIST_SIZE 6 + +struct wilc_rcvd_mac_info { + u8 status; +}; + +struct wilc_set_multicast { + u32 enabled; + u32 cnt; + u8 *mc_list; +}; + +struct wilc_del_all_sta { + u8 assoc_sta; + u8 mac[WILC_MAX_NUM_STA][ETH_ALEN]; +}; + +union wilc_message_body { + struct wilc_rcvd_net_info net_info; + struct wilc_rcvd_mac_info mac_info; + struct wilc_set_multicast mc_info; + struct wilc_remain_ch remain_on_ch; + char *data; +}; + +struct host_if_msg { + union wilc_message_body body; + struct wilc_vif *vif; + struct work_struct work; + void (*fn)(struct work_struct *ws); + struct completion work_comp; + bool is_sync; +}; + +/* 'msg' should be free by the caller for syc */ +static struct host_if_msg* +wilc_alloc_work(struct wilc_vif *vif, void (*work_fun)(struct work_struct *), + bool is_sync) +{ + struct host_if_msg *msg; + + if (!work_fun) + return ERR_PTR(-EINVAL); + + msg = kzalloc(sizeof(*msg), GFP_ATOMIC); + if (!msg) + return ERR_PTR(-ENOMEM); + msg->fn = work_fun; + msg->vif = vif; + msg->is_sync = is_sync; + if (is_sync) + init_completion(&msg->work_comp); + + return msg; +} + +static int wilc_enqueue_work(struct host_if_msg *msg) +{ + INIT_WORK(&msg->work, msg->fn); + + if (!msg->vif || !msg->vif->wilc || !msg->vif->wilc->hif_workqueue) + return -EINVAL; + + if (!queue_work(msg->vif->wilc->hif_workqueue, &msg->work)) + return -EINVAL; + + return 0; +} + +/* The idx starts from 0 to (NUM_CONCURRENT_IFC - 1), but 0 index used as + * special purpose in wilc device, so we add 1 to the index to starts from 1. + * As a result, the returned index will be 1 to NUM_CONCURRENT_IFC. + */ +int wilc_get_vif_idx(struct wilc_vif *vif) +{ + return vif->idx + 1; +} + +/* We need to minus 1 from idx which is from wilc device to get real index + * of wilc->vif[], because we add 1 when pass to wilc device in the function + * wilc_get_vif_idx. + * As a result, the index should be between 0 and (NUM_CONCURRENT_IFC - 1). + */ +static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx) +{ + int index = idx - 1; + struct wilc_vif *vif; + + if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC) + return NULL; + + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->idx == index) + return vif; + } + + return NULL; +} + +static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) +{ + int result = 0; + u8 abort_running_scan; + struct wid wid; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_user_scan_req *scan_req; + + if (evt == SCAN_EVENT_ABORTED) { + abort_running_scan = 1; + wid.id = WID_ABORT_RUNNING_SCAN; + wid.type = WID_CHAR; + wid.val = (s8 *)&abort_running_scan; + wid.size = sizeof(char); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) { + netdev_err(vif->ndev, "Failed to set abort running\n"); + result = -EFAULT; + } + } + + if (!hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); + return result; + } + + scan_req = &hif_drv->usr_scan_req; + if (scan_req->scan_result) { + scan_req->scan_result(evt, NULL, scan_req->arg); + scan_req->scan_result = NULL; + } + + return result; +} + +int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, + u8 *ch_freq_list, u8 ch_list_len, + void (*scan_result_fn)(enum scan_event, + struct wilc_rcvd_net_info *, void *), + void *user_arg, struct cfg80211_scan_request *request) +{ + int result = 0; + struct wid wid_list[WILC_SCAN_WID_LIST_SIZE]; + u32 index = 0; + u32 i, scan_timeout; + u8 *buffer; + u8 valuesize = 0; + u8 *search_ssid_vals = NULL; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (hif_drv->hif_state >= HOST_IF_SCANNING && + hif_drv->hif_state < HOST_IF_CONNECTED) { + netdev_err(vif->ndev, "Already scan\n"); + result = -EBUSY; + goto error; + } + + if (vif->connecting) { + netdev_err(vif->ndev, "Don't do obss scan\n"); + result = -EBUSY; + goto error; + } + + hif_drv->usr_scan_req.ch_cnt = 0; + + if (request->n_ssids) { + for (i = 0; i < request->n_ssids; i++) + valuesize += ((request->ssids[i].ssid_len) + 1); + search_ssid_vals = kmalloc(valuesize + 1, GFP_KERNEL); + if (search_ssid_vals) { + wid_list[index].id = WID_SSID_PROBE_REQ; + wid_list[index].type = WID_STR; + wid_list[index].val = search_ssid_vals; + buffer = wid_list[index].val; + + *buffer++ = request->n_ssids; + + for (i = 0; i < request->n_ssids; i++) { + *buffer++ = request->ssids[i].ssid_len; + memcpy(buffer, request->ssids[i].ssid, + request->ssids[i].ssid_len); + buffer += request->ssids[i].ssid_len; + } + wid_list[index].size = (s32)(valuesize + 1); + index++; + } + } + + wid_list[index].id = WID_INFO_ELEMENT_PROBE; + wid_list[index].type = WID_BIN_DATA; + wid_list[index].val = (s8 *)request->ie; + wid_list[index].size = request->ie_len; + index++; + + wid_list[index].id = WID_SCAN_TYPE; + wid_list[index].type = WID_CHAR; + wid_list[index].size = sizeof(char); + wid_list[index].val = (s8 *)&scan_type; + index++; + + if (scan_type == WILC_FW_PASSIVE_SCAN && request->duration) { + wid_list[index].id = WID_PASSIVE_SCAN_TIME; + wid_list[index].type = WID_SHORT; + wid_list[index].size = sizeof(u16); + wid_list[index].val = (s8 *)&request->duration; + index++; + + scan_timeout = (request->duration * ch_list_len) + 500; + } else { + scan_timeout = WILC_HIF_SCAN_TIMEOUT_MS; + } + + wid_list[index].id = WID_SCAN_CHANNEL_LIST; + wid_list[index].type = WID_BIN_DATA; + + if (ch_freq_list && ch_list_len > 0) { + for (i = 0; i < ch_list_len; i++) { + if (ch_freq_list[i] > 0) + ch_freq_list[i] -= 1; + } + } + + wid_list[index].val = ch_freq_list; + wid_list[index].size = ch_list_len; + index++; + + wid_list[index].id = WID_START_SCAN_REQ; + wid_list[index].type = WID_CHAR; + wid_list[index].size = sizeof(char); + wid_list[index].val = (s8 *)&scan_source; + index++; + + hif_drv->usr_scan_req.scan_result = scan_result_fn; + hif_drv->usr_scan_req.arg = user_arg; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index); + if (result) { + netdev_err(vif->ndev, "Failed to send scan parameters\n"); + goto error; + } + + hif_drv->scan_timer_vif = vif; + mod_timer(&hif_drv->scan_timer, + jiffies + msecs_to_jiffies(scan_timeout)); + +error: + + kfree(search_ssid_vals); + + return result; +} + +static int wilc_send_connect_wid(struct wilc_vif *vif) +{ + int result = 0; + struct wid wid_list[4]; + u32 wid_cnt = 0; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_conn_info *conn_attr = &hif_drv->conn_info; + struct wilc_join_bss_param *bss_param = conn_attr->param; + + wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE; + wid_list[wid_cnt].type = WID_BIN_DATA; + wid_list[wid_cnt].val = conn_attr->req_ies; + wid_list[wid_cnt].size = conn_attr->req_ies_len; + wid_cnt++; + + wid_list[wid_cnt].id = WID_11I_MODE; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&conn_attr->security; + wid_cnt++; + + wid_list[wid_cnt].id = WID_AUTH_TYPE; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&conn_attr->auth_type; + wid_cnt++; + + wid_list[wid_cnt].id = WID_JOIN_REQ_EXTENDED; + wid_list[wid_cnt].type = WID_STR; + wid_list[wid_cnt].size = sizeof(*bss_param); + wid_list[wid_cnt].val = (u8 *)bss_param; + wid_cnt++; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, wid_cnt); + if (result) { + netdev_err(vif->ndev, "failed to send config packet\n"); + goto error; + } else { + hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP; + } + + return 0; + +error: + + kfree(conn_attr->req_ies); + conn_attr->req_ies = NULL; + + return result; +} + +static void handle_connect_timeout(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + int result; + struct wid wid; + u16 dummy_reason_code = 0; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); + goto out; + } + + hif_drv->hif_state = HOST_IF_IDLE; + + if (hif_drv->conn_info.conn_result) { + hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP, + WILC_MAC_STATUS_DISCONNECTED, + hif_drv->conn_info.arg); + + } else { + netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); + } + + wid.id = WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&dummy_reason_code; + wid.size = sizeof(char); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send disconnect\n"); + + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; + +out: + kfree(msg); +} + +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto) +{ + struct wilc_join_bss_param *param; + struct ieee80211_p2p_noa_attr noa_attr; + u8 rates_len = 0; + const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; + int ret; + const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + return NULL; + + param->beacon_period = cpu_to_le16(bss->beacon_interval); + param->cap_info = cpu_to_le16(bss->capability); + param->bss_type = WILC_FW_BSS_TYPE_INFRA; + param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); + ether_addr_copy(param->bssid, bss->bssid); + + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + if (ssid_elm) { + if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) + memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); + } + + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + if (tim_elm && tim_elm[1] >= 2) + param->dtim_period = tim_elm[3]; + + memset(param->p_suites, 0xFF, 3); + memset(param->akm_suites, 0xFF, 3); + + rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); + if (rates_ie) { + rates_len = rates_ie[1]; + if (rates_len > WILC_MAX_RATES_SUPPORTED) + rates_len = WILC_MAX_RATES_SUPPORTED; + param->supp_rates[0] = rates_len; + memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len); + } + + if (rates_len < WILC_MAX_RATES_SUPPORTED) { + supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, + ies->data, ies->len); + if (supp_rates_ie) { + u8 ext_rates = supp_rates_ie[1]; + + if (ext_rates > (WILC_MAX_RATES_SUPPORTED - rates_len)) + param->supp_rates[0] = WILC_MAX_RATES_SUPPORTED; + else + param->supp_rates[0] += ext_rates; + + memcpy(¶m->supp_rates[rates_len + 1], + supp_rates_ie + 2, + (param->supp_rates[0] - rates_len)); + } + } + + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); + if (ht_ie) + param->ht_capable = true; + + ret = cfg80211_get_p2p_attr(ies->data, ies->len, + IEEE80211_P2P_ATTR_ABSENCE_NOTICE, + (u8 *)&noa_attr, sizeof(noa_attr)); + if (ret > 0) { + param->tsf_lo = cpu_to_le32(ies->tsf); + param->noa_enabled = 1; + param->idx = noa_attr.index; + if (noa_attr.oppps_ctwindow & IEEE80211_P2P_OPPPS_ENABLE_BIT) { + param->opp_enabled = 1; + param->opp_en.ct_window = noa_attr.oppps_ctwindow; + param->opp_en.cnt = noa_attr.desc[0].count; + param->opp_en.duration = noa_attr.desc[0].duration; + param->opp_en.interval = noa_attr.desc[0].interval; + param->opp_en.start_time = noa_attr.desc[0].start_time; + } else { + param->opp_enabled = 0; + param->opp_dis.cnt = noa_attr.desc[0].count; + param->opp_dis.duration = noa_attr.desc[0].duration; + param->opp_dis.interval = noa_attr.desc[0].interval; + param->opp_dis.start_time = noa_attr.desc[0].start_time; + } + } + wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WMM, + ies->data, ies->len); + if (wmm_ie) { + struct ieee80211_wmm_param_ie *ie; + + ie = (struct ieee80211_wmm_param_ie *)wmm_ie; + if ((ie->oui_subtype == 0 || ie->oui_subtype == 1) && + ie->version == 1) { + param->wmm_cap = true; + if (ie->qos_info & BIT(7)) + param->uapsd_cap = true; + } + } + + wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + ies->data, ies->len); + if (wpa_ie) { + param->mode_802_11i = 1; + param->rsn_found = true; + } + + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); + if (rsn_ie) { + int offset = 8; + + param->mode_802_11i = 2; + param->rsn_found = true; + /* extract RSN capabilities */ + offset += (rsn_ie[offset] * 4) + 2; + offset += (rsn_ie[offset] * 4) + 2; + memcpy(param->rsn_cap, &rsn_ie[offset], 2); + } + + if (param->rsn_found) { + int i; + + param->rsn_grp_policy = crypto->cipher_group & 0xFF; + for (i = 0; i < crypto->n_ciphers_pairwise && i < 3; i++) + param->p_suites[i] = crypto->ciphers_pairwise[i] & 0xFF; + + for (i = 0; i < crypto->n_akm_suites && i < 3; i++) + param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; + } + + return (void *)param; +} + +static void handle_rcvd_ntwrk_info(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_rcvd_net_info *rcvd_info = &msg->body.net_info; + struct wilc_user_scan_req *scan_req = &msg->vif->hif_drv->usr_scan_req; + const u8 *ch_elm; + u8 *ies; + int ies_len; + size_t offset; + + if (ieee80211_is_probe_resp(rcvd_info->mgmt->frame_control)) + offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + else if (ieee80211_is_beacon(rcvd_info->mgmt->frame_control)) + offset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + else + goto done; + + ies = rcvd_info->mgmt->u.beacon.variable; + ies_len = rcvd_info->frame_len - offset; + if (ies_len <= 0) + goto done; + + ch_elm = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ies, ies_len); + if (ch_elm && ch_elm[1] > 0) + rcvd_info->ch = ch_elm[2]; + + if (scan_req->scan_result) + scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info, + scan_req->arg); + +done: + kfree(rcvd_info->mgmt); + kfree(msg); +} + +static void host_int_get_assoc_res_info(struct wilc_vif *vif, + u8 *assoc_resp_info, + u32 max_assoc_resp_info_len, + u32 *rcvd_assoc_resp_info_len) +{ + int result; + struct wid wid; + + wid.id = WID_ASSOC_RES_INFO; + wid.type = WID_STR; + wid.val = assoc_resp_info; + wid.size = max_assoc_resp_info_len; + + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) { + *rcvd_assoc_resp_info_len = 0; + netdev_err(vif->ndev, "Failed to send association response\n"); + return; + } + + *rcvd_assoc_resp_info_len = wid.size; +} + +static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len, + struct wilc_conn_info *ret_conn_info) +{ + u8 *ies; + u16 ies_len; + struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer; + + ret_conn_info->status = le16_to_cpu(res->status_code); + if (ret_conn_info->status == WLAN_STATUS_SUCCESS) { + ies = &buffer[sizeof(*res)]; + ies_len = buffer_len - sizeof(*res); + + ret_conn_info->resp_ies = kmemdup(ies, ies_len, GFP_KERNEL); + if (!ret_conn_info->resp_ies) + return -ENOMEM; + + ret_conn_info->resp_ies_len = ies_len; + } + + return 0; +} + +static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif, + u8 mac_status) +{ + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_conn_info *conn_info = &hif_drv->conn_info; + + if (mac_status == WILC_MAC_STATUS_CONNECTED) { + u32 assoc_resp_info_len; + + memset(hif_drv->assoc_resp, 0, WILC_MAX_ASSOC_RESP_FRAME_SIZE); + + host_int_get_assoc_res_info(vif, hif_drv->assoc_resp, + WILC_MAX_ASSOC_RESP_FRAME_SIZE, + &assoc_resp_info_len); + + if (assoc_resp_info_len != 0) { + s32 err = 0; + + err = wilc_parse_assoc_resp_info(hif_drv->assoc_resp, + assoc_resp_info_len, + conn_info); + if (err) + netdev_err(vif->ndev, + "wilc_parse_assoc_resp_info() returned error %d\n", + err); + } + } + + del_timer(&hif_drv->connect_timer); + conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status, + hif_drv->conn_info.arg); + + if (mac_status == WILC_MAC_STATUS_CONNECTED && + conn_info->status == WLAN_STATUS_SUCCESS) { + ether_addr_copy(hif_drv->assoc_bssid, conn_info->bssid); + hif_drv->hif_state = HOST_IF_CONNECTED; + } else { + hif_drv->hif_state = HOST_IF_IDLE; + } + + kfree(conn_info->resp_ies); + conn_info->resp_ies = NULL; + conn_info->resp_ies_len = 0; + + kfree(conn_info->req_ies); + conn_info->req_ies = NULL; + conn_info->req_ies_len = 0; +} + +static inline void host_int_handle_disconnect(struct wilc_vif *vif) +{ + struct host_if_drv *hif_drv = vif->hif_drv; + + if (hif_drv->usr_scan_req.scan_result) { + del_timer(&hif_drv->scan_timer); + handle_scan_done(vif, SCAN_EVENT_ABORTED); + } + + if (hif_drv->conn_info.conn_result) + hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, + 0, hif_drv->conn_info.arg); + else + netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); + + eth_zero_addr(hif_drv->assoc_bssid); + + hif_drv->conn_info.req_ies_len = 0; + kfree(hif_drv->conn_info.req_ies); + hif_drv->conn_info.req_ies = NULL; + hif_drv->hif_state = HOST_IF_IDLE; +} + +static void handle_rcvd_gnrl_async_info(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct wilc_rcvd_mac_info *mac_info = &msg->body.mac_info; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL\n", __func__); + goto free_msg; + } + + if (!hif_drv->conn_info.conn_result) { + netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); + goto free_msg; + } + + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) { + host_int_parse_assoc_resp_info(vif, mac_info->status); + } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) { + if (hif_drv->hif_state == HOST_IF_CONNECTED) { + host_int_handle_disconnect(vif); + } else if (hif_drv->usr_scan_req.scan_result) { + del_timer(&hif_drv->scan_timer); + handle_scan_done(vif, SCAN_EVENT_ABORTED); + } + } + +free_msg: + kfree(msg); +} + +int wilc_disconnect(struct wilc_vif *vif) +{ + struct wid wid; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_user_scan_req *scan_req; + struct wilc_conn_info *conn_info; + int result; + u16 dummy_reason_code = 0; + + wid.id = WID_DISCONNECT; + wid.type = WID_CHAR; + wid.val = (s8 *)&dummy_reason_code; + wid.size = sizeof(char); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) { + netdev_err(vif->ndev, "Failed to send disconnect\n"); + return result; + } + + scan_req = &hif_drv->usr_scan_req; + conn_info = &hif_drv->conn_info; + + if (scan_req->scan_result) { + del_timer(&hif_drv->scan_timer); + scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg); + scan_req->scan_result = NULL; + } + + if (conn_info->conn_result) { + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) + del_timer(&hif_drv->connect_timer); + + conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0, + conn_info->arg); + } else { + netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); + } + + hif_drv->hif_state = HOST_IF_IDLE; + + eth_zero_addr(hif_drv->assoc_bssid); + + conn_info->req_ies_len = 0; + kfree(conn_info->req_ies); + conn_info->req_ies = NULL; + + return 0; +} + +int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats) +{ + struct wid wid_list[5]; + u32 wid_cnt = 0, result; + + wid_list[wid_cnt].id = WID_LINKSPEED; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&stats->link_speed; + wid_cnt++; + + wid_list[wid_cnt].id = WID_RSSI; + wid_list[wid_cnt].type = WID_CHAR; + wid_list[wid_cnt].size = sizeof(char); + wid_list[wid_cnt].val = (s8 *)&stats->rssi; + wid_cnt++; + + wid_list[wid_cnt].id = WID_SUCCESS_FRAME_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->tx_cnt; + wid_cnt++; + + wid_list[wid_cnt].id = WID_RECEIVED_FRAGMENT_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->rx_cnt; + wid_cnt++; + + wid_list[wid_cnt].id = WID_FAILED_COUNT; + wid_list[wid_cnt].type = WID_INT; + wid_list[wid_cnt].size = sizeof(u32); + wid_list[wid_cnt].val = (s8 *)&stats->tx_fail_cnt; + wid_cnt++; + + result = wilc_send_config_pkt(vif, WILC_GET_CFG, wid_list, wid_cnt); + if (result) { + netdev_err(vif->ndev, "Failed to send scan parameters\n"); + return result; + } + + if (stats->link_speed > TCP_ACK_FILTER_LINK_SPEED_THRESH && + stats->link_speed != DEFAULT_LINK_SPEED) + wilc_enable_tcp_ack_filter(vif, true); + else if (stats->link_speed != DEFAULT_LINK_SPEED) + wilc_enable_tcp_ack_filter(vif, false); + + return result; +} + +static void handle_get_statistics(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct rf_info *stats = (struct rf_info *)msg->body.data; + + wilc_get_statistics(vif, stats); + + kfree(msg); +} + +static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac, + struct station_parameters *params) +{ + ether_addr_copy(cur_byte, mac); + cur_byte += ETH_ALEN; + + put_unaligned_le16(params->aid, cur_byte); + cur_byte += 2; + + *cur_byte++ = params->supported_rates_len; + if (params->supported_rates_len > 0) + memcpy(cur_byte, params->supported_rates, + params->supported_rates_len); + cur_byte += params->supported_rates_len; + + if (params->ht_capa) { + *cur_byte++ = true; + memcpy(cur_byte, params->ht_capa, + sizeof(struct ieee80211_ht_cap)); + } else { + *cur_byte++ = false; + } + cur_byte += sizeof(struct ieee80211_ht_cap); + + put_unaligned_le16(params->sta_flags_mask, cur_byte); + cur_byte += 2; + put_unaligned_le16(params->sta_flags_set, cur_byte); +} + +static int handle_remain_on_chan(struct wilc_vif *vif, + struct wilc_remain_ch *hif_remain_ch) +{ + int result; + u8 remain_on_chan_flag; + struct wid wid; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (hif_drv->usr_scan_req.scan_result) + return -EBUSY; + + if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) + return -EBUSY; + + if (vif->connecting) + return -EBUSY; + + remain_on_chan_flag = true; + wid.id = WID_REMAIN_ON_CHAN; + wid.type = WID_STR; + wid.size = 2; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + wid.val[0] = remain_on_chan_flag; + wid.val[1] = (s8)hif_remain_ch->ch; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(wid.val); + if (result) + return -EBUSY; + + hif_drv->remain_on_ch.arg = hif_remain_ch->arg; + hif_drv->remain_on_ch.expired = hif_remain_ch->expired; + hif_drv->remain_on_ch.ch = hif_remain_ch->ch; + hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie; + hif_drv->remain_on_ch_timer_vif = vif; + + return 0; +} + +static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie) +{ + u8 remain_on_chan_flag; + struct wid wid; + int result; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (vif->priv.p2p_listen_state) { + remain_on_chan_flag = false; + wid.id = WID_REMAIN_ON_CHAN; + wid.type = WID_STR; + wid.size = 2; + + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + wid.val[0] = remain_on_chan_flag; + wid.val[1] = WILC_FALSE_FRMWR_CHANNEL; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(wid.val); + if (result != 0) { + netdev_err(vif->ndev, "Failed to set remain channel\n"); + return -EINVAL; + } + + if (hif_drv->remain_on_ch.expired) { + hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg, + cookie); + } + } else { + netdev_dbg(vif->ndev, "Not in listen state\n"); + } + + return 0; +} + +static void wilc_handle_listen_state_expired(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + + wilc_handle_roc_expired(msg->vif, msg->body.remain_on_ch.cookie); + kfree(msg); +} + +static void listen_timer_cb(struct timer_list *t) +{ + struct host_if_drv *hif_drv = from_timer(hif_drv, t, + remain_on_ch_timer); + struct wilc_vif *vif = hif_drv->remain_on_ch_timer_vif; + int result; + struct host_if_msg *msg; + + del_timer(&vif->hif_drv->remain_on_ch_timer); + + msg = wilc_alloc_work(vif, wilc_handle_listen_state_expired, false); + if (IS_ERR(msg)) + return; + + msg->body.remain_on_ch.cookie = vif->hif_drv->remain_on_ch.cookie; + + result = wilc_enqueue_work(msg); + if (result) { + netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); + kfree(msg); + } +} + +static void handle_set_mcast_filter(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + struct wilc_vif *vif = msg->vif; + struct wilc_set_multicast *set_mc = &msg->body.mc_info; + int result; + struct wid wid; + u8 *cur_byte; + + wid.id = WID_SETUP_MULTICAST_FILTER; + wid.type = WID_BIN; + wid.size = sizeof(struct wilc_set_multicast) + (set_mc->cnt * ETH_ALEN); + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + goto error; + + cur_byte = wid.val; + put_unaligned_le32(set_mc->enabled, cur_byte); + cur_byte += 4; + + put_unaligned_le32(set_mc->cnt, cur_byte); + cur_byte += 4; + + if (set_mc->cnt > 0 && set_mc->mc_list) + memcpy(cur_byte, set_mc->mc_list, set_mc->cnt * ETH_ALEN); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send setup multicast\n"); + +error: + kfree(set_mc->mc_list); + kfree(wid.val); + kfree(msg); +} + +static void handle_scan_timer(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + + handle_scan_done(msg->vif, SCAN_EVENT_ABORTED); + kfree(msg); +} + +static void handle_scan_complete(struct work_struct *work) +{ + struct host_if_msg *msg = container_of(work, struct host_if_msg, work); + + del_timer(&msg->vif->hif_drv->scan_timer); + + handle_scan_done(msg->vif, SCAN_EVENT_DONE); + + kfree(msg); +} + +static void timer_scan_cb(struct timer_list *t) +{ + struct host_if_drv *hif_drv = from_timer(hif_drv, t, scan_timer); + struct wilc_vif *vif = hif_drv->scan_timer_vif; + struct host_if_msg *msg; + int result; + + msg = wilc_alloc_work(vif, handle_scan_timer, false); + if (IS_ERR(msg)) + return; + + result = wilc_enqueue_work(msg); + if (result) + kfree(msg); +} + +static void timer_connect_cb(struct timer_list *t) +{ + struct host_if_drv *hif_drv = from_timer(hif_drv, t, + connect_timer); + struct wilc_vif *vif = hif_drv->connect_timer_vif; + struct host_if_msg *msg; + int result; + + msg = wilc_alloc_work(vif, handle_connect_timeout, false); + if (IS_ERR(msg)) + return; + + result = wilc_enqueue_work(msg); + if (result) + kfree(msg); +} + +int wilc_remove_wep_key(struct wilc_vif *vif, u8 index) +{ + struct wid wid; + int result; + + wid.id = WID_REMOVE_WEP_KEY; + wid.type = WID_STR; + wid.size = sizeof(char); + wid.val = &index; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, + "Failed to send remove wep key config packet\n"); + return result; +} + +int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index) +{ + struct wid wid; + int result; + + wid.id = WID_KEY_ID; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &index; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, + "Failed to send wep default key config packet\n"); + + return result; +} + +int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index) +{ + struct wid wid; + int result; + struct wilc_wep_key *wep_key; + + wid.id = WID_ADD_WEP_KEY; + wid.type = WID_STR; + wid.size = sizeof(*wep_key) + len; + wep_key = kzalloc(wid.size, GFP_KERNEL); + if (!wep_key) + return -ENOMEM; + + wid.val = (u8 *)wep_key; + + wep_key->index = index; + wep_key->key_len = len; + memcpy(wep_key->key, key, len); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, + "Failed to add wep key config packet\n"); + + kfree(wep_key); + return result; +} + +int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index, u8 mode, enum authtype auth_type) +{ + struct wid wid_list[3]; + int result; + struct wilc_wep_key *wep_key; + + wid_list[0].id = WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = &mode; + + wid_list[1].id = WID_AUTH_TYPE; + wid_list[1].type = WID_CHAR; + wid_list[1].size = sizeof(char); + wid_list[1].val = (s8 *)&auth_type; + + wid_list[2].id = WID_WEP_KEY_VALUE; + wid_list[2].type = WID_STR; + wid_list[2].size = sizeof(*wep_key) + len; + wep_key = kzalloc(wid_list[2].size, GFP_KERNEL); + if (!wep_key) + return -ENOMEM; + + wid_list[2].val = (u8 *)wep_key; + + wep_key->index = index; + wep_key->key_len = len; + memcpy(wep_key->key, key, len); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, + ARRAY_SIZE(wid_list)); + if (result) + netdev_err(vif->ndev, + "Failed to add wep ap key config packet\n"); + + kfree(wep_key); + return result; +} + +int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, + const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, + u8 mode, u8 cipher_mode, u8 index) +{ + int result = 0; + u8 t_key_len = ptk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN; + + if (mode == WILC_AP_MODE) { + struct wid wid_list[2]; + struct wilc_ap_wpa_ptk *key_buf; + + wid_list[0].id = WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&cipher_mode; + + key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL); + if (!key_buf) + return -ENOMEM; + + ether_addr_copy(key_buf->mac_addr, mac_addr); + key_buf->index = index; + key_buf->key_len = t_key_len; + memcpy(&key_buf->key[0], ptk, ptk_key_len); + + if (rx_mic) + memcpy(&key_buf->key[ptk_key_len], rx_mic, + WILC_RX_MIC_KEY_LEN); + + if (tx_mic) + memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN], + tx_mic, WILC_TX_MIC_KEY_LEN); + + wid_list[1].id = WID_ADD_PTK; + wid_list[1].type = WID_STR; + wid_list[1].size = sizeof(*key_buf) + t_key_len; + wid_list[1].val = (u8 *)key_buf; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, + ARRAY_SIZE(wid_list)); + kfree(key_buf); + } else if (mode == WILC_STATION_MODE) { + struct wid wid; + struct wilc_sta_wpa_ptk *key_buf; + + key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL); + if (!key_buf) + return -ENOMEM; + + ether_addr_copy(key_buf->mac_addr, mac_addr); + key_buf->key_len = t_key_len; + memcpy(&key_buf->key[0], ptk, ptk_key_len); + + if (rx_mic) + memcpy(&key_buf->key[ptk_key_len], rx_mic, + WILC_RX_MIC_KEY_LEN); + + if (tx_mic) + memcpy(&key_buf->key[ptk_key_len + WILC_RX_MIC_KEY_LEN], + tx_mic, WILC_TX_MIC_KEY_LEN); + + wid.id = WID_ADD_PTK; + wid.type = WID_STR; + wid.size = sizeof(*key_buf) + t_key_len; + wid.val = (s8 *)key_buf; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(key_buf); + } + + return result; +} + +int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, + u8 index, u32 key_rsc_len, const u8 *key_rsc, + const u8 *rx_mic, const u8 *tx_mic, u8 mode, + u8 cipher_mode) +{ + int result = 0; + struct wilc_gtk_key *gtk_key; + int t_key_len = gtk_key_len + WILC_RX_MIC_KEY_LEN + WILC_TX_MIC_KEY_LEN; + + gtk_key = kzalloc(sizeof(*gtk_key) + t_key_len, GFP_KERNEL); + if (!gtk_key) + return -ENOMEM; + + /* fill bssid value only in station mode */ + if (mode == WILC_STATION_MODE && + vif->hif_drv->hif_state == HOST_IF_CONNECTED) + memcpy(gtk_key->mac_addr, vif->hif_drv->assoc_bssid, ETH_ALEN); + + if (key_rsc) + memcpy(gtk_key->rsc, key_rsc, 8); + gtk_key->index = index; + gtk_key->key_len = t_key_len; + memcpy(>k_key->key[0], rx_gtk, gtk_key_len); + + if (rx_mic) + memcpy(>k_key->key[gtk_key_len], rx_mic, WILC_RX_MIC_KEY_LEN); + + if (tx_mic) + memcpy(>k_key->key[gtk_key_len + WILC_RX_MIC_KEY_LEN], + tx_mic, WILC_TX_MIC_KEY_LEN); + + if (mode == WILC_AP_MODE) { + struct wid wid_list[2]; + + wid_list[0].id = WID_11I_MODE; + wid_list[0].type = WID_CHAR; + wid_list[0].size = sizeof(char); + wid_list[0].val = (s8 *)&cipher_mode; + + wid_list[1].id = WID_ADD_RX_GTK; + wid_list[1].type = WID_STR; + wid_list[1].size = sizeof(*gtk_key) + t_key_len; + wid_list[1].val = (u8 *)gtk_key; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, + ARRAY_SIZE(wid_list)); + } else if (mode == WILC_STATION_MODE) { + struct wid wid; + + wid.id = WID_ADD_RX_GTK; + wid.type = WID_STR; + wid.size = sizeof(*gtk_key) + t_key_len; + wid.val = (u8 *)gtk_key; + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + } + + kfree(gtk_key); + return result; +} + +int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid) +{ + struct wid wid; + + wid.id = WID_PMKID_INFO; + wid.type = WID_STR; + wid.size = (pmkid->numpmkid * sizeof(struct wilc_pmkid)) + 1; + wid.val = (u8 *)pmkid; + + return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); +} + +int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr) +{ + int result; + struct wid wid; + + wid.id = WID_MAC_ADDR; + wid.type = WID_STR; + wid.size = ETH_ALEN; + wid.val = mac_addr; + + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to get mac address\n"); + + return result; +} + +int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, + size_t ies_len) +{ + int result; + struct host_if_drv *hif_drv = vif->hif_drv; + struct wilc_conn_info *conn_info = &hif_drv->conn_info; + + if (bssid) + ether_addr_copy(conn_info->bssid, bssid); + + if (ies) { + conn_info->req_ies_len = ies_len; + conn_info->req_ies = kmemdup(ies, ies_len, GFP_KERNEL); + if (!conn_info->req_ies) + return -ENOMEM; + } + + result = wilc_send_connect_wid(vif); + if (result) + goto free_ies; + + hif_drv->connect_timer_vif = vif; + mod_timer(&hif_drv->connect_timer, + jiffies + msecs_to_jiffies(WILC_HIF_CONNECT_TIMEOUT_MS)); + + return 0; + +free_ies: + kfree(conn_info->req_ies); + + return result; +} + +int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel) +{ + struct wid wid; + int result; + + wid.id = WID_CURRENT_CHANNEL; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &channel; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to set channel\n"); + + return result; +} + +int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, + u8 ifc_id) +{ + struct wid wid; + int result; + struct wilc_drv_handler drv; + + wid.id = WID_SET_OPERATION_MODE; + wid.type = WID_STR; + wid.size = sizeof(drv); + wid.val = (u8 *)&drv; + + drv.handler = cpu_to_le32(index); + drv.mode = (ifc_id | (mode << 1)); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to set driver handler\n"); + + return result; +} + +s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, u32 *out_val) +{ + struct wid wid; + s32 result; + + wid.id = WID_SET_STA_MAC_INACTIVE_TIME; + wid.type = WID_STR; + wid.size = ETH_ALEN; + wid.val = kzalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + ether_addr_copy(wid.val, mac); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + kfree(wid.val); + if (result) { + netdev_err(vif->ndev, "Failed to set inactive mac\n"); + return result; + } + + wid.id = WID_GET_INACTIVE_TIME; + wid.type = WID_INT; + wid.val = (s8 *)out_val; + wid.size = sizeof(u32); + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to get inactive time\n"); + + return result; +} + +int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level) +{ + struct wid wid; + int result; + + if (!rssi_level) { + netdev_err(vif->ndev, "%s: RSSI level is NULL\n", __func__); + return -EFAULT; + } + + wid.id = WID_RSSI; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = rssi_level; + result = wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to get RSSI value\n"); + + return result; +} + +static int wilc_get_stats_async(struct wilc_vif *vif, struct rf_info *stats) +{ + int result; + struct host_if_msg *msg; + + msg = wilc_alloc_work(vif, handle_get_statistics, false); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msg->body.data = (char *)stats; + + result = wilc_enqueue_work(msg); + if (result) { + netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); + kfree(msg); + return result; + } + + return result; +} + +int wilc_hif_set_cfg(struct wilc_vif *vif, struct cfg_param_attr *param) +{ + struct wid wid_list[4]; + int i = 0; + + if (param->flag & WILC_CFG_PARAM_RETRY_SHORT) { + wid_list[i].id = WID_SHORT_RETRY_LIMIT; + wid_list[i].val = (s8 *)¶m->short_retry_limit; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + if (param->flag & WILC_CFG_PARAM_RETRY_LONG) { + wid_list[i].id = WID_LONG_RETRY_LIMIT; + wid_list[i].val = (s8 *)¶m->long_retry_limit; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + if (param->flag & WILC_CFG_PARAM_FRAG_THRESHOLD) { + wid_list[i].id = WID_FRAG_THRESHOLD; + wid_list[i].val = (s8 *)¶m->frag_threshold; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + if (param->flag & WILC_CFG_PARAM_RTS_THRESHOLD) { + wid_list[i].id = WID_RTS_THRESHOLD; + wid_list[i].val = (s8 *)¶m->rts_threshold; + wid_list[i].type = WID_SHORT; + wid_list[i].size = sizeof(u16); + i++; + } + + return wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, i); +} + +static void get_periodic_rssi(struct timer_list *t) +{ + struct wilc_vif *vif = from_timer(vif, t, periodic_rssi); + + if (!vif->hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); + return; + } + + if (vif->hif_drv->hif_state == HOST_IF_CONNECTED) + wilc_get_stats_async(vif, &vif->periodic_stat); + + mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000)); +} + +int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler) +{ + struct host_if_drv *hif_drv; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + hif_drv = kzalloc(sizeof(*hif_drv), GFP_KERNEL); + if (!hif_drv) + return -ENOMEM; + + *hif_drv_handler = hif_drv; + + vif->hif_drv = hif_drv; + + if (wilc->clients_count == 0) + mutex_init(&wilc->deinit_lock); + + timer_setup(&vif->periodic_rssi, get_periodic_rssi, 0); + mod_timer(&vif->periodic_rssi, jiffies + msecs_to_jiffies(5000)); + + timer_setup(&hif_drv->scan_timer, timer_scan_cb, 0); + timer_setup(&hif_drv->connect_timer, timer_connect_cb, 0); + timer_setup(&hif_drv->remain_on_ch_timer, listen_timer_cb, 0); + + hif_drv->hif_state = HOST_IF_IDLE; + + hif_drv->p2p_timeout = 0; + + wilc->clients_count++; + + return 0; +} + +int wilc_deinit(struct wilc_vif *vif) +{ + int result = 0; + struct host_if_drv *hif_drv = vif->hif_drv; + + if (!hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); + return -EFAULT; + } + + mutex_lock(&vif->wilc->deinit_lock); + + del_timer_sync(&hif_drv->scan_timer); + del_timer_sync(&hif_drv->connect_timer); + del_timer_sync(&vif->periodic_rssi); + del_timer_sync(&hif_drv->remain_on_ch_timer); + + if (hif_drv->usr_scan_req.scan_result) { + hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL, + hif_drv->usr_scan_req.arg); + hif_drv->usr_scan_req.scan_result = NULL; + } + + hif_drv->hif_state = HOST_IF_IDLE; + + kfree(hif_drv); + vif->hif_drv = NULL; + vif->wilc->clients_count--; + mutex_unlock(&vif->wilc->deinit_lock); + return result; +} + +void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length) +{ + int result; + struct host_if_msg *msg; + int id; + struct host_if_drv *hif_drv; + struct wilc_vif *vif; + + id = get_unaligned_le32(&buffer[length - 4]); + vif = wilc_get_vif_from_idx(wilc, id); + if (!vif) + return; + hif_drv = vif->hif_drv; + + if (!hif_drv) { + netdev_err(vif->ndev, "driver not init[%p]\n", hif_drv); + return; + } + + msg = wilc_alloc_work(vif, handle_rcvd_ntwrk_info, false); + if (IS_ERR(msg)) + return; + + msg->body.net_info.frame_len = get_unaligned_le16(&buffer[6]) - 1; + msg->body.net_info.rssi = buffer[8]; + msg->body.net_info.mgmt = kmemdup(&buffer[9], + msg->body.net_info.frame_len, + GFP_KERNEL); + if (!msg->body.net_info.mgmt) { + kfree(msg); + return; + } + + result = wilc_enqueue_work(msg); + if (result) { + netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); + kfree(msg->body.net_info.mgmt); + kfree(msg); + } +} + +void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length) +{ + int result; + struct host_if_msg *msg; + int id; + struct host_if_drv *hif_drv; + struct wilc_vif *vif; + + mutex_lock(&wilc->deinit_lock); + + id = get_unaligned_le32(&buffer[length - 4]); + vif = wilc_get_vif_from_idx(wilc, id); + if (!vif) { + mutex_unlock(&wilc->deinit_lock); + return; + } + + hif_drv = vif->hif_drv; + + if (!hif_drv) { + mutex_unlock(&wilc->deinit_lock); + return; + } + + if (!hif_drv->conn_info.conn_result) { + netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__); + mutex_unlock(&wilc->deinit_lock); + return; + } + + msg = wilc_alloc_work(vif, handle_rcvd_gnrl_async_info, false); + if (IS_ERR(msg)) { + mutex_unlock(&wilc->deinit_lock); + return; + } + + msg->body.mac_info.status = buffer[7]; + result = wilc_enqueue_work(msg); + if (result) { + netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); + kfree(msg); + } + + mutex_unlock(&wilc->deinit_lock); +} + +void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length) +{ + int result; + int id; + struct host_if_drv *hif_drv; + struct wilc_vif *vif; + + id = get_unaligned_le32(&buffer[length - 4]); + vif = wilc_get_vif_from_idx(wilc, id); + if (!vif) + return; + hif_drv = vif->hif_drv; + + if (!hif_drv) + return; + + if (hif_drv->usr_scan_req.scan_result) { + struct host_if_msg *msg; + + msg = wilc_alloc_work(vif, handle_scan_complete, false); + if (IS_ERR(msg)) + return; + + result = wilc_enqueue_work(msg); + if (result) { + netdev_err(vif->ndev, "%s: enqueue work failed\n", + __func__); + kfree(msg); + } + } +} + +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, + u32 duration, u16 chan, + void (*expired)(void *, u64), + void *user_arg) +{ + struct wilc_remain_ch roc; + int result; + + roc.ch = chan; + roc.expired = expired; + roc.arg = user_arg; + roc.duration = duration; + roc.cookie = cookie; + result = handle_remain_on_chan(vif, &roc); + if (result) + netdev_err(vif->ndev, "%s: failed to set remain on channel\n", + __func__); + + return result; +} + +int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie) +{ + if (!vif->hif_drv) { + netdev_err(vif->ndev, "%s: hif driver is NULL", __func__); + return -EFAULT; + } + + del_timer(&vif->hif_drv->remain_on_ch_timer); + + return wilc_handle_roc_expired(vif, cookie); +} + +void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg) +{ + struct wid wid; + int result; + struct wilc_reg_frame reg_frame; + + wid.id = WID_REGISTER_FRAME; + wid.type = WID_STR; + wid.size = sizeof(reg_frame); + wid.val = (u8 *)®_frame; + + memset(®_frame, 0x0, sizeof(reg_frame)); + + if (reg) + reg_frame.reg = 1; + + switch (frame_type) { + case IEEE80211_STYPE_ACTION: + reg_frame.reg_id = WILC_FW_ACTION_FRM_IDX; + break; + + case IEEE80211_STYPE_PROBE_REQ: + reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX; + break; + + default: + break; + } + reg_frame.frame_type = cpu_to_le16(frame_type); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to frame register\n"); +} + +int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, + struct cfg80211_beacon_data *params) +{ + struct wid wid; + int result; + u8 *cur_byte; + + wid.id = WID_ADD_BEACON; + wid.type = WID_BIN; + wid.size = params->head_len + params->tail_len + 16; + wid.val = kzalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + cur_byte = wid.val; + put_unaligned_le32(interval, cur_byte); + cur_byte += 4; + put_unaligned_le32(dtim_period, cur_byte); + cur_byte += 4; + put_unaligned_le32(params->head_len, cur_byte); + cur_byte += 4; + + if (params->head_len > 0) + memcpy(cur_byte, params->head, params->head_len); + cur_byte += params->head_len; + + put_unaligned_le32(params->tail_len, cur_byte); + cur_byte += 4; + + if (params->tail_len > 0) + memcpy(cur_byte, params->tail, params->tail_len); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send add beacon\n"); + + kfree(wid.val); + + return result; +} + +int wilc_del_beacon(struct wilc_vif *vif) +{ + int result; + struct wid wid; + u8 del_beacon = 0; + + wid.id = WID_DEL_BEACON; + wid.type = WID_CHAR; + wid.size = sizeof(char); + wid.val = &del_beacon; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send delete beacon\n"); + + return result; +} + +int wilc_add_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params) +{ + struct wid wid; + int result; + u8 *cur_byte; + + wid.id = WID_ADD_STA; + wid.type = WID_BIN; + wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + cur_byte = wid.val; + wilc_hif_pack_sta_param(cur_byte, mac, params); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result != 0) + netdev_err(vif->ndev, "Failed to send add station\n"); + + kfree(wid.val); + + return result; +} + +int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr) +{ + struct wid wid; + int result; + + wid.id = WID_REMOVE_STA; + wid.type = WID_BIN; + wid.size = ETH_ALEN; + wid.val = kzalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + if (!mac_addr) + eth_broadcast_addr(wid.val); + else + ether_addr_copy(wid.val, mac_addr); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to del station\n"); + + kfree(wid.val); + + return result; +} + +int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]) +{ + struct wid wid; + int result; + int i; + u8 assoc_sta = 0; + struct wilc_del_all_sta del_sta; + + memset(&del_sta, 0x0, sizeof(del_sta)); + for (i = 0; i < WILC_MAX_NUM_STA; i++) { + if (!is_zero_ether_addr(mac_addr[i])) { + assoc_sta++; + ether_addr_copy(del_sta.mac[i], mac_addr[i]); + } + } + + if (!assoc_sta) + return 0; + + del_sta.assoc_sta = assoc_sta; + + wid.id = WID_DEL_ALL_STA; + wid.type = WID_STR; + wid.size = (assoc_sta * ETH_ALEN) + 1; + wid.val = (u8 *)&del_sta; + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send delete all station\n"); + + return result; +} + +int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params) +{ + struct wid wid; + int result; + u8 *cur_byte; + + wid.id = WID_EDIT_STA; + wid.type = WID_BIN; + wid.size = WILC_ADD_STA_LENGTH + params->supported_rates_len; + wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; + + cur_byte = wid.val; + wilc_hif_pack_sta_param(cur_byte, mac, params); + + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send edit station\n"); + + kfree(wid.val); + return result; +} + +int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout) +{ + struct wid wid; + int result; + s8 power_mode; + + if (enabled) + power_mode = WILC_FW_MIN_FAST_PS; + else + power_mode = WILC_FW_NO_POWERSAVE; + + wid.id = WID_POWER_MANAGEMENT; + wid.val = &power_mode; + wid.size = sizeof(char); + result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); + if (result) + netdev_err(vif->ndev, "Failed to send power management\n"); + + return result; +} + +int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, + u8 *mc_list) +{ + int result; + struct host_if_msg *msg; + + msg = wilc_alloc_work(vif, handle_set_mcast_filter, false); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msg->body.mc_info.enabled = enabled; + msg->body.mc_info.cnt = count; + msg->body.mc_info.mc_list = mc_list; + + result = wilc_enqueue_work(msg); + if (result) { + netdev_err(vif->ndev, "%s: enqueue work failed\n", __func__); + kfree(msg); + } + return result; +} + +int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power) +{ + struct wid wid; + + wid.id = WID_TX_POWER; + wid.type = WID_CHAR; + wid.val = &tx_power; + wid.size = sizeof(char); + + return wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1); +} + +int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power) +{ + struct wid wid; + + wid.id = WID_TX_POWER; + wid.type = WID_CHAR; + wid.val = tx_power; + wid.size = sizeof(char); + + return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1); +} diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h new file mode 100644 index 000000000000..db9179171f05 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/hif.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries + * All rights reserved. + */ + +#ifndef WILC_HIF_H +#define WILC_HIF_H +#include <linux/ieee80211.h> +#include "wlan_if.h" + +enum { + WILC_IDLE_MODE = 0x0, + WILC_AP_MODE = 0x1, + WILC_STATION_MODE = 0x2, + WILC_GO_MODE = 0x3, + WILC_CLIENT_MODE = 0x4 +}; + +#define WILC_MAX_NUM_PROBED_SSID 10 + +#define WILC_TX_MIC_KEY_LEN 8 +#define WILC_RX_MIC_KEY_LEN 8 + +#define WILC_ADD_STA_LENGTH 40 +#define WILC_NUM_CONCURRENT_IFC 2 + +enum { + WILC_SET_CFG = 0, + WILC_GET_CFG +}; + +#define WILC_MAX_ASSOC_RESP_FRAME_SIZE 256 + +struct rf_info { + u8 link_speed; + s8 rssi; + u32 tx_cnt; + u32 rx_cnt; + u32 tx_fail_cnt; +}; + +enum host_if_state { + HOST_IF_IDLE = 0, + HOST_IF_SCANNING = 1, + HOST_IF_CONNECTING = 2, + HOST_IF_WAITING_CONN_RESP = 3, + HOST_IF_CONNECTED = 4, + HOST_IF_P2P_LISTEN = 5, + HOST_IF_FORCE_32BIT = 0xFFFFFFFF +}; + +struct cfg_param_attr { + u32 flag; + u16 short_retry_limit; + u16 long_retry_limit; + u16 frag_threshold; + u16 rts_threshold; +}; + +enum cfg_param { + WILC_CFG_PARAM_RETRY_SHORT = BIT(0), + WILC_CFG_PARAM_RETRY_LONG = BIT(1), + WILC_CFG_PARAM_FRAG_THRESHOLD = BIT(2), + WILC_CFG_PARAM_RTS_THRESHOLD = BIT(3) +}; + +enum scan_event { + SCAN_EVENT_NETWORK_FOUND = 0, + SCAN_EVENT_DONE = 1, + SCAN_EVENT_ABORTED = 2, + SCAN_EVENT_FORCE_32BIT = 0xFFFFFFFF +}; + +enum conn_event { + CONN_DISCONN_EVENT_CONN_RESP = 0, + CONN_DISCONN_EVENT_DISCONN_NOTIF = 1, + CONN_DISCONN_EVENT_FORCE_32BIT = 0xFFFFFFFF +}; + +enum { + WILC_HIF_SDIO = 0, + WILC_HIF_SPI = BIT(0) +}; + +enum { + WILC_MAC_STATUS_INIT = -1, + WILC_MAC_STATUS_DISCONNECTED = 0, + WILC_MAC_STATUS_CONNECTED = 1 +}; + +struct wilc_rcvd_net_info { + s8 rssi; + u8 ch; + u16 frame_len; + struct ieee80211_mgmt *mgmt; +}; + +struct wilc_user_scan_req { + void (*scan_result)(enum scan_event evt, + struct wilc_rcvd_net_info *info, void *priv); + void *arg; + u32 ch_cnt; +}; + +struct wilc_conn_info { + u8 bssid[ETH_ALEN]; + u8 security; + enum authtype auth_type; + u8 ch; + u8 *req_ies; + size_t req_ies_len; + u8 *resp_ies; + u16 resp_ies_len; + u16 status; + void (*conn_result)(enum conn_event evt, u8 status, void *priv_data); + void *arg; + void *param; +}; + +struct wilc_remain_ch { + u16 ch; + u32 duration; + void (*expired)(void *priv, u64 cookie); + void *arg; + u32 cookie; +}; + +struct wilc; +struct host_if_drv { + struct wilc_user_scan_req usr_scan_req; + struct wilc_conn_info conn_info; + struct wilc_remain_ch remain_on_ch; + u64 p2p_timeout; + + enum host_if_state hif_state; + + u8 assoc_bssid[ETH_ALEN]; + + struct timer_list scan_timer; + struct wilc_vif *scan_timer_vif; + + struct timer_list connect_timer; + struct wilc_vif *connect_timer_vif; + + struct timer_list remain_on_ch_timer; + struct wilc_vif *remain_on_ch_timer_vif; + + bool ifc_up; + u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; +}; + +struct wilc_vif; +int wilc_remove_wep_key(struct wilc_vif *vif, u8 index); +int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index); +int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index); +int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len, + u8 index, u8 mode, enum authtype auth_type); +int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len, + const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic, + u8 mode, u8 cipher_mode, u8 index); +s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac, + u32 *out_val); +int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len, + u8 index, u32 key_rsc_len, const u8 *key_rsc, + const u8 *rx_mic, const u8 *tx_mic, u8 mode, + u8 cipher_mode); +int wilc_set_pmkid_info(struct wilc_vif *vif, struct wilc_pmkid_attr *pmkid); +int wilc_get_mac_address(struct wilc_vif *vif, u8 *mac_addr); +int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies, + size_t ies_len); +int wilc_disconnect(struct wilc_vif *vif); +int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel); +int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level); +int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type, + u8 *ch_freq_list, u8 ch_list_len, + void (*scan_result_fn)(enum scan_event, + struct wilc_rcvd_net_info *, void *), + void *user_arg, struct cfg80211_scan_request *request); +int wilc_hif_set_cfg(struct wilc_vif *vif, + struct cfg_param_attr *cfg_param); +int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler); +int wilc_deinit(struct wilc_vif *vif); +int wilc_add_beacon(struct wilc_vif *vif, u32 interval, u32 dtim_period, + struct cfg80211_beacon_data *params); +int wilc_del_beacon(struct wilc_vif *vif); +int wilc_add_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params); +int wilc_del_allstation(struct wilc_vif *vif, u8 mac_addr[][ETH_ALEN]); +int wilc_del_station(struct wilc_vif *vif, const u8 *mac_addr); +int wilc_edit_station(struct wilc_vif *vif, const u8 *mac, + struct station_parameters *params); +int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout); +int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count, + u8 *mc_list); +int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, + u32 duration, u16 chan, + void (*expired)(void *, u64), + void *user_arg); +int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie); +void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg); +int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode, + u8 ifc_id); +int wilc_get_statistics(struct wilc_vif *vif, struct rf_info *stats); +int wilc_get_vif_idx(struct wilc_vif *vif); +int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power); +int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power); +void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length); +void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length); +void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length); +void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, + struct cfg80211_crypto_settings *crypto); +#endif diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c new file mode 100644 index 000000000000..358ac8601333 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/mon.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include "cfg80211.h" + +struct wilc_wfi_radiotap_hdr { + struct ieee80211_radiotap_header hdr; + u8 rate; +} __packed; + +struct wilc_wfi_radiotap_cb_hdr { + struct ieee80211_radiotap_header hdr; + u8 rate; + u8 dump; + u16 tx_flags; +} __packed; + +#define TX_RADIOTAP_PRESENT ((1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_TX_FLAGS)) + +void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size) +{ + u32 header, pkt_offset; + struct sk_buff *skb = NULL; + struct wilc_wfi_radiotap_hdr *hdr; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + + if (!mon_dev) + return; + + if (!netif_running(mon_dev)) + return; + + /* Get WILC header */ + header = get_unaligned_le32(buff - HOST_HDR_OFFSET); + /* + * The packet offset field contain info about what type of management + * the frame we are dealing with and ack status + */ + pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header); + + if (pkt_offset & IS_MANAGMEMENT_CALLBACK) { + /* hostapd callback mgmt frame */ + + skb = dev_alloc_skb(size + sizeof(*cb_hdr)); + if (!skb) + return; + + skb_put_data(skb, buff, size); + + cb_hdr = skb_push(skb, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(*cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(*cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32(TX_RADIOTAP_PRESENT); + + cb_hdr->rate = 5; + + if (pkt_offset & IS_MGMT_STATUS_SUCCES) { + /* success */ + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_RTS; + } else { + cb_hdr->tx_flags = IEEE80211_RADIOTAP_F_TX_FAIL; + } + + } else { + skb = dev_alloc_skb(size + sizeof(*hdr)); + + if (!skb) + return; + + skb_put_data(skb, buff, size); + hdr = skb_push(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(struct wilc_wfi_radiotap_hdr)); + hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + hdr->hdr.it_len = cpu_to_le16(sizeof(*hdr)); + hdr->hdr.it_present = cpu_to_le32 + (1 << IEEE80211_RADIOTAP_RATE); + hdr->rate = 5; + } + + skb->dev = mon_dev; + skb_reset_mac_header(skb); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + + netif_rx(skb); +} + +struct tx_complete_mon_data { + int size; + void *buff; +}; + +static void mgmt_tx_complete(void *priv, int status) +{ + struct tx_complete_mon_data *pv_data = priv; + /* + * in case of fully hosting mode, the freeing will be done + * in response to the cfg packet + */ + kfree(pv_data->buff); + + kfree(pv_data); +} + +static int mon_mgmt_tx(struct net_device *dev, const u8 *buf, size_t len) +{ + struct tx_complete_mon_data *mgmt_tx = NULL; + + if (!dev) + return -EFAULT; + + netif_stop_queue(dev); + mgmt_tx = kmalloc(sizeof(*mgmt_tx), GFP_ATOMIC); + if (!mgmt_tx) + return -ENOMEM; + + mgmt_tx->buff = kmemdup(buf, len, GFP_ATOMIC); + if (!mgmt_tx->buff) { + kfree(mgmt_tx); + return -ENOMEM; + } + + mgmt_tx->size = len; + + wilc_wlan_txq_add_mgmt_pkt(dev, mgmt_tx, mgmt_tx->buff, mgmt_tx->size, + mgmt_tx_complete); + + netif_wake_queue(dev); + return 0; +} + +static netdev_tx_t wilc_wfi_mon_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + u32 rtap_len, ret = 0; + struct wilc_wfi_mon_priv *mon_priv; + struct sk_buff *skb2; + struct wilc_wfi_radiotap_cb_hdr *cb_hdr; + u8 srcadd[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + + mon_priv = netdev_priv(dev); + if (!mon_priv) + return -EFAULT; + + rtap_len = ieee80211_get_radiotap_len(skb->data); + if (skb->len < rtap_len) + return -1; + + skb_pull(skb, rtap_len); + + if (skb->data[0] == 0xc0 && is_broadcast_ether_addr(&skb->data[4])) { + skb2 = dev_alloc_skb(skb->len + sizeof(*cb_hdr)); + if (!skb2) + return -ENOMEM; + + skb_put_data(skb2, skb->data, skb->len); + + cb_hdr = skb_push(skb2, sizeof(*cb_hdr)); + memset(cb_hdr, 0, sizeof(struct wilc_wfi_radiotap_cb_hdr)); + + cb_hdr->hdr.it_version = 0; /* PKTHDR_RADIOTAP_VERSION; */ + + cb_hdr->hdr.it_len = cpu_to_le16(sizeof(*cb_hdr)); + + cb_hdr->hdr.it_present = cpu_to_le32(TX_RADIOTAP_PRESENT); + + cb_hdr->rate = 5; + cb_hdr->tx_flags = 0x0004; + + skb2->dev = dev; + skb_reset_mac_header(skb2); + skb2->ip_summed = CHECKSUM_UNNECESSARY; + skb2->pkt_type = PACKET_OTHERHOST; + skb2->protocol = htons(ETH_P_802_2); + memset(skb2->cb, 0, sizeof(skb2->cb)); + + netif_rx(skb2); + + return 0; + } + skb->dev = mon_priv->real_ndev; + + ether_addr_copy(srcadd, &skb->data[10]); + ether_addr_copy(bssid, &skb->data[16]); + /* + * Identify if data or mgmt packet, if source address and bssid + * fields are equal send it to mgmt frames handler + */ + if (!(memcmp(srcadd, bssid, 6))) { + ret = mon_mgmt_tx(mon_priv->real_ndev, skb->data, skb->len); + if (ret) + netdev_err(dev, "fail to mgmt tx\n"); + dev_kfree_skb(skb); + } else { + ret = wilc_mac_xmit(skb, mon_priv->real_ndev); + } + + return ret; +} + +static const struct net_device_ops wilc_wfi_netdev_ops = { + .ndo_start_xmit = wilc_wfi_mon_xmit, + +}; + +struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, + const char *name, + struct net_device *real_dev) +{ + struct wilc_wfi_mon_priv *priv; + + /* If monitor interface is already initialized, return it */ + if (wl->monitor_dev) + return wl->monitor_dev; + + wl->monitor_dev = alloc_etherdev(sizeof(struct wilc_wfi_mon_priv)); + if (!wl->monitor_dev) + return NULL; + + wl->monitor_dev->type = ARPHRD_IEEE80211_RADIOTAP; + strlcpy(wl->monitor_dev->name, name, IFNAMSIZ); + wl->monitor_dev->netdev_ops = &wilc_wfi_netdev_ops; + wl->monitor_dev->needs_free_netdev = true; + + if (register_netdevice(wl->monitor_dev)) { + netdev_err(real_dev, "register_netdevice failed\n"); + return NULL; + } + priv = netdev_priv(wl->monitor_dev); + if (!priv) + return NULL; + + priv->real_ndev = real_dev; + + return wl->monitor_dev; +} + +void wilc_wfi_deinit_mon_interface(struct wilc *wl, bool rtnl_locked) +{ + if (!wl->monitor_dev) + return; + + if (rtnl_locked) + unregister_netdevice(wl->monitor_dev); + else + unregister_netdev(wl->monitor_dev); + wl->monitor_dev = NULL; +} diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c new file mode 100644 index 000000000000..20615c7ec168 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -0,0 +1,938 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include <linux/irq.h> +#include <linux/kthread.h> +#include <linux/firmware.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> + +#include "cfg80211.h" +#include "wlan_cfg.h" + +#define WILC_MULTICAST_TABLE_SIZE 8 + +/* latest API version supported */ +#define WILC1000_API_VER 1 + +#define WILC1000_FW_PREFIX "atmel/wilc1000_wifi_firmware-" +#define __WILC1000_FW(api) WILC1000_FW_PREFIX #api ".bin" +#define WILC1000_FW(api) __WILC1000_FW(api) + +static irqreturn_t isr_uh_routine(int irq, void *user_data) +{ + struct net_device *dev = user_data; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + if (wilc->close) { + netdev_err(dev, "Can't handle UH interrupt\n"); + return IRQ_HANDLED; + } + return IRQ_WAKE_THREAD; +} + +static irqreturn_t isr_bh_routine(int irq, void *userdata) +{ + struct net_device *dev = userdata; + struct wilc_vif *vif = netdev_priv(userdata); + struct wilc *wilc = vif->wilc; + + if (wilc->close) { + netdev_err(dev, "Can't handle BH interrupt\n"); + return IRQ_HANDLED; + } + + wilc_handle_isr(wilc); + + return IRQ_HANDLED; +} + +static int init_irq(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wl = vif->wilc; + int ret; + + ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine, + isr_bh_routine, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "WILC_IRQ", dev); + if (ret) { + netdev_err(dev, "Failed to request IRQ [%d]\n", ret); + return ret; + } + netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n", wl->dev_irq_num); + + return 0; +} + +static void deinit_irq(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + /* Deinitialize IRQ */ + if (wilc->dev_irq_num) + free_irq(wilc->dev_irq_num, wilc); +} + +void wilc_mac_indicate(struct wilc *wilc) +{ + s8 status; + + wilc_wlan_cfg_get_val(wilc, WID_STATUS, &status, 1); + if (wilc->mac_status == WILC_MAC_STATUS_INIT) { + wilc->mac_status = status; + complete(&wilc->sync_event); + } else { + wilc->mac_status = status; + } +} + +static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) +{ + struct net_device *ndev = NULL; + struct wilc_vif *vif; + struct ieee80211_hdr *h = (struct ieee80211_hdr *)mac_header; + + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->mode == WILC_STATION_MODE) + if (ether_addr_equal_unaligned(h->addr2, vif->bssid)) { + ndev = vif->ndev; + goto out; + } + if (vif->mode == WILC_AP_MODE) + if (ether_addr_equal_unaligned(h->addr1, vif->bssid)) { + ndev = vif->ndev; + goto out; + } + } +out: + return ndev; +} + +void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) +{ + struct wilc_vif *vif = netdev_priv(wilc_netdev); + + if (bssid) + ether_addr_copy(vif->bssid, bssid); + else + eth_zero_addr(vif->bssid); + + vif->mode = mode; +} + +int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) +{ + int srcu_idx; + u8 ret_val = 0; + struct wilc_vif *vif; + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (!is_zero_ether_addr(vif->bssid)) + ret_val++; + } + srcu_read_unlock(&wilc->srcu, srcu_idx); + return ret_val; +} + +static int wilc_txq_task(void *vp) +{ + int ret; + u32 txq_count; + struct wilc *wl = vp; + + complete(&wl->txq_thread_started); + while (1) { + wait_for_completion(&wl->txq_event); + + if (wl->close) { + complete(&wl->txq_thread_started); + + while (!kthread_should_stop()) + schedule(); + break; + } + do { + ret = wilc_wlan_handle_txq(wl, &txq_count); + if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { + int srcu_idx; + struct wilc_vif *ifc; + + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(ifc, &wl->vif_list, + list) { + if (ifc->mac_opened && ifc->ndev) + netif_wake_queue(ifc->ndev); + } + srcu_read_unlock(&wl->srcu, srcu_idx); + } + } while (ret == WILC_VMM_ENTRY_FULL_RETRY && !wl->close); + } + return 0; +} + +static int wilc_wlan_get_firmware(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + int chip_id; + const struct firmware *wilc_fw; + int ret; + + chip_id = wilc_get_chipid(wilc, false); + + netdev_info(dev, "ChipID [%x] loading firmware [%s]\n", chip_id, + WILC1000_FW(WILC1000_API_VER)); + + ret = request_firmware(&wilc_fw, WILC1000_FW(WILC1000_API_VER), + wilc->dev); + if (ret != 0) { + netdev_err(dev, "%s - firmware not available\n", + WILC1000_FW(WILC1000_API_VER)); + return -EINVAL; + } + wilc->firmware = wilc_fw; + + return 0; +} + +static int wilc_start_firmware(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + int ret = 0; + + ret = wilc_wlan_start(wilc); + if (ret) + return ret; + + if (!wait_for_completion_timeout(&wilc->sync_event, + msecs_to_jiffies(5000))) + return -ETIME; + + return 0; +} + +static int wilc1000_firmware_download(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + int ret = 0; + + if (!wilc->firmware) { + netdev_err(dev, "Firmware buffer is NULL\n"); + return -ENOBUFS; + } + + ret = wilc_wlan_firmware_download(wilc, wilc->firmware->data, + wilc->firmware->size); + if (ret) + return ret; + + release_firmware(wilc->firmware); + wilc->firmware = NULL; + + netdev_dbg(dev, "Download Succeeded\n"); + + return 0; +} + +static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) +{ + struct wilc_priv *priv = &vif->priv; + struct host_if_drv *hif_drv; + u8 b; + u16 hw; + u32 w; + + netdev_dbg(dev, "Start configuring Firmware\n"); + hif_drv = (struct host_if_drv *)priv->hif_drv; + netdev_dbg(dev, "Host = %p\n", hif_drv); + + w = vif->iftype; + cpu_to_le32s(&w); + if (!wilc_wlan_cfg_set(vif, 1, WID_SET_OPERATION_MODE, (u8 *)&w, 4, + 0, 0)) + goto fail; + + b = WILC_FW_BSS_TYPE_INFRA; + if (!wilc_wlan_cfg_set(vif, 0, WID_BSS_TYPE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_TX_RATE_AUTO; + if (!wilc_wlan_cfg_set(vif, 0, WID_CURRENT_TX_RATE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_OPER_MODE_G_MIXED_11B_2; + if (!wilc_wlan_cfg_set(vif, 0, WID_11G_OPERATING_MODE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_PREAMBLE_SHORT; + if (!wilc_wlan_cfg_set(vif, 0, WID_PREAMBLE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_11N_PROT_AUTO; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_PROT_MECH, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_ACTIVE_SCAN; + if (!wilc_wlan_cfg_set(vif, 0, WID_SCAN_TYPE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_SITE_SURVEY_OFF; + if (!wilc_wlan_cfg_set(vif, 0, WID_SITE_SURVEY, &b, 1, 0, 0)) + goto fail; + + hw = 0xffff; + cpu_to_le16s(&hw); + if (!wilc_wlan_cfg_set(vif, 0, WID_RTS_THRESHOLD, (u8 *)&hw, 2, 0, 0)) + goto fail; + + hw = 2346; + cpu_to_le16s(&hw); + if (!wilc_wlan_cfg_set(vif, 0, WID_FRAG_THRESHOLD, (u8 *)&hw, 2, 0, 0)) + goto fail; + + b = 0; + if (!wilc_wlan_cfg_set(vif, 0, WID_BCAST_SSID, &b, 1, 0, 0)) + goto fail; + + b = 1; + if (!wilc_wlan_cfg_set(vif, 0, WID_QOS_ENABLE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_NO_POWERSAVE; + if (!wilc_wlan_cfg_set(vif, 0, WID_POWER_MANAGEMENT, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_SEC_NO; + if (!wilc_wlan_cfg_set(vif, 0, WID_11I_MODE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_AUTH_OPEN_SYSTEM; + if (!wilc_wlan_cfg_set(vif, 0, WID_AUTH_TYPE, &b, 1, 0, 0)) + goto fail; + + b = 3; + if (!wilc_wlan_cfg_set(vif, 0, WID_LISTEN_INTERVAL, &b, 1, 0, 0)) + goto fail; + + b = 3; + if (!wilc_wlan_cfg_set(vif, 0, WID_DTIM_PERIOD, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_ACK_POLICY_NORMAL; + if (!wilc_wlan_cfg_set(vif, 0, WID_ACK_POLICY, &b, 1, 0, 0)) + goto fail; + + b = 0; + if (!wilc_wlan_cfg_set(vif, 0, WID_USER_CONTROL_ON_TX_POWER, &b, 1, + 0, 0)) + goto fail; + + b = 48; + if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11A, &b, 1, 0, 0)) + goto fail; + + b = 28; + if (!wilc_wlan_cfg_set(vif, 0, WID_TX_POWER_LEVEL_11B, &b, 1, 0, 0)) + goto fail; + + hw = 100; + cpu_to_le16s(&hw); + if (!wilc_wlan_cfg_set(vif, 0, WID_BEACON_INTERVAL, (u8 *)&hw, 2, 0, 0)) + goto fail; + + b = WILC_FW_REKEY_POLICY_DISABLE; + if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_POLICY, &b, 1, 0, 0)) + goto fail; + + w = 84600; + cpu_to_le32s(&w); + if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PERIOD, (u8 *)&w, 4, 0, 0)) + goto fail; + + w = 500; + cpu_to_le32s(&w); + if (!wilc_wlan_cfg_set(vif, 0, WID_REKEY_PACKET_COUNT, (u8 *)&w, 4, 0, + 0)) + goto fail; + + b = 1; + if (!wilc_wlan_cfg_set(vif, 0, WID_SHORT_SLOT_ALLOWED, &b, 1, 0, + 0)) + goto fail; + + b = WILC_FW_ERP_PROT_SELF_CTS; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ERP_PROT_TYPE, &b, 1, 0, 0)) + goto fail; + + b = 1; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_ENABLE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_11N_OP_MODE_HT_MIXED; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OPERATING_MODE, &b, 1, 0, 0)) + goto fail; + + b = 1; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_TXOP_PROT_DISABLE, &b, 1, 0, 0)) + goto fail; + + b = WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_OBSS_NONHT_DETECTION, &b, 1, + 0, 0)) + goto fail; + + b = WILC_FW_HT_PROT_RTS_CTS_NONHT; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_HT_PROT_TYPE, &b, 1, 0, 0)) + goto fail; + + b = 0; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_RIFS_PROT_ENABLE, &b, 1, 0, + 0)) + goto fail; + + b = 7; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_CURRENT_TX_MCS, &b, 1, 0, 0)) + goto fail; + + b = 1; + if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1, + 1, 1)) + goto fail; + + return 0; + +fail: + return -EINVAL; +} + +static void wlan_deinitialize_threads(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wl = vif->wilc; + + wl->close = 1; + + complete(&wl->txq_event); + + if (wl->txq_thread) { + kthread_stop(wl->txq_thread); + wl->txq_thread = NULL; + } +} + +static void wilc_wlan_deinitialize(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wl = vif->wilc; + + if (!wl) { + netdev_err(dev, "wl is NULL\n"); + return; + } + + if (wl->initialized) { + netdev_info(dev, "Deinitializing wilc1000...\n"); + + if (!wl->dev_irq_num && + wl->hif_func->disable_interrupt) { + mutex_lock(&wl->hif_cs); + wl->hif_func->disable_interrupt(wl); + mutex_unlock(&wl->hif_cs); + } + complete(&wl->txq_event); + + wlan_deinitialize_threads(dev); + deinit_irq(dev); + + wilc_wlan_stop(wl, vif); + wilc_wlan_cleanup(dev); + + wl->initialized = false; + + netdev_dbg(dev, "wilc1000 deinitialization Done\n"); + } else { + netdev_dbg(dev, "wilc1000 is not initialized\n"); + } +} + +static int wlan_initialize_threads(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + wilc->txq_thread = kthread_run(wilc_txq_task, (void *)wilc, + "K_TXQ_TASK"); + if (IS_ERR(wilc->txq_thread)) { + netdev_err(dev, "couldn't create TXQ thread\n"); + wilc->close = 0; + return PTR_ERR(wilc->txq_thread); + } + wait_for_completion(&wilc->txq_thread_started); + + return 0; +} + +static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif) +{ + int ret = 0; + struct wilc *wl = vif->wilc; + + if (!wl->initialized) { + wl->mac_status = WILC_MAC_STATUS_INIT; + wl->close = 0; + + ret = wilc_wlan_init(dev); + if (ret) + return ret; + + ret = wlan_initialize_threads(dev); + if (ret) + goto fail_wilc_wlan; + + if (wl->dev_irq_num && init_irq(dev)) { + ret = -EIO; + goto fail_threads; + } + + if (!wl->dev_irq_num && + wl->hif_func->enable_interrupt && + wl->hif_func->enable_interrupt(wl)) { + ret = -EIO; + goto fail_irq_init; + } + + ret = wilc_wlan_get_firmware(dev); + if (ret) + goto fail_irq_enable; + + ret = wilc1000_firmware_download(dev); + if (ret) + goto fail_irq_enable; + + ret = wilc_start_firmware(dev); + if (ret) + goto fail_irq_enable; + + if (wilc_wlan_cfg_get(vif, 1, WID_FIRMWARE_VERSION, 1, 0)) { + int size; + char firmware_ver[20]; + + size = wilc_wlan_cfg_get_val(wl, WID_FIRMWARE_VERSION, + firmware_ver, + sizeof(firmware_ver)); + firmware_ver[size] = '\0'; + netdev_dbg(dev, "Firmware Ver = %s\n", firmware_ver); + } + + ret = wilc_init_fw_config(dev, vif); + if (ret) { + netdev_err(dev, "Failed to configure firmware\n"); + goto fail_fw_start; + } + wl->initialized = true; + return 0; + +fail_fw_start: + wilc_wlan_stop(wl, vif); + +fail_irq_enable: + if (!wl->dev_irq_num && + wl->hif_func->disable_interrupt) + wl->hif_func->disable_interrupt(wl); +fail_irq_init: + if (wl->dev_irq_num) + deinit_irq(dev); +fail_threads: + wlan_deinitialize_threads(dev); +fail_wilc_wlan: + wilc_wlan_cleanup(dev); + netdev_err(dev, "WLAN initialization FAILED\n"); + } else { + netdev_dbg(dev, "wilc1000 already initialized\n"); + } + return ret; +} + +static int mac_init_fn(struct net_device *ndev) +{ + netif_start_queue(ndev); + netif_stop_queue(ndev); + + return 0; +} + +static int wilc_mac_open(struct net_device *ndev) +{ + struct wilc_vif *vif = netdev_priv(ndev); + struct wilc *wl = vif->wilc; + unsigned char mac_add[ETH_ALEN] = {0}; + int ret = 0; + struct mgmt_frame_regs mgmt_regs = {}; + + if (!wl || !wl->dev) { + netdev_err(ndev, "device not ready\n"); + return -ENODEV; + } + + netdev_dbg(ndev, "MAC OPEN[%p]\n", ndev); + + ret = wilc_init_host_int(ndev); + if (ret) + return ret; + + ret = wilc_wlan_initialize(ndev, vif); + if (ret) { + wilc_deinit_host_int(ndev); + return ret; + } + + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), vif->iftype, + vif->idx); + wilc_get_mac_address(vif, mac_add); + netdev_dbg(ndev, "Mac address: %pM\n", mac_add); + ether_addr_copy(ndev->dev_addr, mac_add); + + if (!is_valid_ether_addr(ndev->dev_addr)) { + netdev_err(ndev, "Wrong MAC address\n"); + wilc_deinit_host_int(ndev); + wilc_wlan_deinitialize(ndev); + return -EINVAL; + } + + mgmt_regs.interface_stypes = vif->mgmt_reg_stypes; + /* so we detect a change */ + vif->mgmt_reg_stypes = 0; + wilc_update_mgmt_frame_registrations(vif->ndev->ieee80211_ptr->wiphy, + vif->ndev->ieee80211_ptr, + &mgmt_regs); + netif_wake_queue(ndev); + wl->open_ifcs++; + vif->mac_opened = 1; + return 0; +} + +static struct net_device_stats *mac_stats(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + + return &vif->netstats; +} + +static void wilc_set_multicast_list(struct net_device *dev) +{ + struct netdev_hw_addr *ha; + struct wilc_vif *vif = netdev_priv(dev); + int i; + u8 *mc_list; + u8 *cur_mc; + + if (dev->flags & IFF_PROMISC) + return; + + if (dev->flags & IFF_ALLMULTI || + dev->mc.count > WILC_MULTICAST_TABLE_SIZE) { + wilc_setup_multicast_filter(vif, 0, 0, NULL); + return; + } + + if (dev->mc.count == 0) { + wilc_setup_multicast_filter(vif, 1, 0, NULL); + return; + } + + mc_list = kmalloc_array(dev->mc.count, ETH_ALEN, GFP_ATOMIC); + if (!mc_list) + return; + + cur_mc = mc_list; + i = 0; + netdev_for_each_mc_addr(ha, dev) { + memcpy(cur_mc, ha->addr, ETH_ALEN); + netdev_dbg(dev, "Entry[%d]: %pM\n", i, cur_mc); + i++; + cur_mc += ETH_ALEN; + } + + if (wilc_setup_multicast_filter(vif, 1, dev->mc.count, mc_list)) + kfree(mc_list); +} + +static void wilc_tx_complete(void *priv, int status) +{ + struct tx_complete_data *pv_data = priv; + + dev_kfree_skb(pv_data->skb); + kfree(pv_data); +} + +netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct wilc_vif *vif = netdev_priv(ndev); + struct wilc *wilc = vif->wilc; + struct tx_complete_data *tx_data = NULL; + int queue_count; + + if (skb->dev != ndev) { + netdev_err(ndev, "Packet not destined to this device\n"); + return NETDEV_TX_OK; + } + + tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC); + if (!tx_data) { + dev_kfree_skb(skb); + netif_wake_queue(ndev); + return NETDEV_TX_OK; + } + + tx_data->buff = skb->data; + tx_data->size = skb->len; + tx_data->skb = skb; + + vif->netstats.tx_packets++; + vif->netstats.tx_bytes += tx_data->size; + queue_count = wilc_wlan_txq_add_net_pkt(ndev, (void *)tx_data, + tx_data->buff, tx_data->size, + wilc_tx_complete); + + if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) { + int srcu_idx; + struct wilc_vif *vif; + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->mac_opened) + netif_stop_queue(vif->ndev); + } + srcu_read_unlock(&wilc->srcu, srcu_idx); + } + + return NETDEV_TX_OK; +} + +static int wilc_mac_close(struct net_device *ndev) +{ + struct wilc_vif *vif = netdev_priv(ndev); + struct wilc *wl = vif->wilc; + + netdev_dbg(ndev, "Mac close\n"); + + if (wl->open_ifcs > 0) + wl->open_ifcs--; + else + return 0; + + if (vif->ndev) { + netif_stop_queue(vif->ndev); + + wilc_deinit_host_int(vif->ndev); + } + + if (wl->open_ifcs == 0) { + netdev_dbg(ndev, "Deinitializing wilc1000\n"); + wl->close = 1; + wilc_wlan_deinitialize(ndev); + } + + vif->mac_opened = 0; + + return 0; +} + +void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, + u32 pkt_offset) +{ + unsigned int frame_len = 0; + int stats; + unsigned char *buff_to_send = NULL; + struct sk_buff *skb; + struct net_device *wilc_netdev; + struct wilc_vif *vif; + + if (!wilc) + return; + + wilc_netdev = get_if_handler(wilc, buff); + if (!wilc_netdev) + return; + + buff += pkt_offset; + vif = netdev_priv(wilc_netdev); + + if (size > 0) { + frame_len = size; + buff_to_send = buff; + + skb = dev_alloc_skb(frame_len); + if (!skb) + return; + + skb->dev = wilc_netdev; + + skb_put_data(skb, buff_to_send, frame_len); + + skb->protocol = eth_type_trans(skb, wilc_netdev); + vif->netstats.rx_packets++; + vif->netstats.rx_bytes += frame_len; + skb->ip_summed = CHECKSUM_UNNECESSARY; + stats = netif_rx(skb); + netdev_dbg(wilc_netdev, "netif_rx ret value is: %d\n", stats); + } +} + +void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) +{ + int srcu_idx; + struct wilc_vif *vif; + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + u16 type = le16_to_cpup((__le16 *)buff); + u32 type_bit = BIT(type >> 4); + + if (vif->priv.p2p_listen_state && + vif->mgmt_reg_stypes & type_bit) + wilc_wfi_p2p_rx(vif, buff, size); + + if (vif->monitor_flag) + wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size); + } + srcu_read_unlock(&wilc->srcu, srcu_idx); +} + +static const struct net_device_ops wilc_netdev_ops = { + .ndo_init = mac_init_fn, + .ndo_open = wilc_mac_open, + .ndo_stop = wilc_mac_close, + .ndo_start_xmit = wilc_mac_xmit, + .ndo_get_stats = mac_stats, + .ndo_set_rx_mode = wilc_set_multicast_list, +}; + +void wilc_netdev_cleanup(struct wilc *wilc) +{ + struct wilc_vif *vif; + int srcu_idx, ifc_cnt = 0; + + if (!wilc) + return; + + if (wilc->firmware) { + release_firmware(wilc->firmware); + wilc->firmware = NULL; + } + + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->ndev) + unregister_netdev(vif->ndev); + } + srcu_read_unlock(&wilc->srcu, srcu_idx); + + wilc_wfi_deinit_mon_interface(wilc, false); + flush_workqueue(wilc->hif_workqueue); + destroy_workqueue(wilc->hif_workqueue); + + while (ifc_cnt < WILC_NUM_CONCURRENT_IFC) { + mutex_lock(&wilc->vif_mutex); + if (wilc->vif_num <= 0) { + mutex_unlock(&wilc->vif_mutex); + break; + } + vif = wilc_get_wl_to_vif(wilc); + if (!IS_ERR(vif)) + list_del_rcu(&vif->list); + + wilc->vif_num--; + mutex_unlock(&wilc->vif_mutex); + synchronize_srcu(&wilc->srcu); + ifc_cnt++; + } + + wilc_wlan_cfg_deinit(wilc); + wlan_deinit_locks(wilc); + kfree(wilc->bus_data); + wiphy_unregister(wilc->wiphy); + wiphy_free(wilc->wiphy); +} +EXPORT_SYMBOL_GPL(wilc_netdev_cleanup); + +static u8 wilc_get_available_idx(struct wilc *wl) +{ + int idx = 0; + struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->idx == 0) + idx = 1; + else + idx = 0; + } + srcu_read_unlock(&wl->srcu, srcu_idx); + return idx; +} + +struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, + int vif_type, enum nl80211_iftype type, + bool rtnl_locked) +{ + struct net_device *ndev; + struct wilc_vif *vif; + int ret; + + ndev = alloc_etherdev(sizeof(*vif)); + if (!ndev) + return ERR_PTR(-ENOMEM); + + vif = netdev_priv(ndev); + ndev->ieee80211_ptr = &vif->priv.wdev; + strcpy(ndev->name, name); + vif->wilc = wl; + vif->ndev = ndev; + ndev->ml_priv = vif; + + ndev->netdev_ops = &wilc_netdev_ops; + + SET_NETDEV_DEV(ndev, wiphy_dev(wl->wiphy)); + + vif->priv.wdev.wiphy = wl->wiphy; + vif->priv.wdev.netdev = ndev; + vif->priv.wdev.iftype = type; + vif->priv.dev = ndev; + + if (rtnl_locked) + ret = register_netdevice(ndev); + else + ret = register_netdev(ndev); + + if (ret) { + free_netdev(ndev); + return ERR_PTR(-EFAULT); + } + + ndev->needs_free_netdev = true; + vif->iftype = vif_type; + vif->idx = wilc_get_available_idx(wl); + vif->mac_opened = 0; + mutex_lock(&wl->vif_mutex); + list_add_tail_rcu(&vif->list, &wl->vif_list); + wl->vif_num += 1; + mutex_unlock(&wl->vif_mutex); + synchronize_srcu(&wl->srcu); + + return vif; +} + +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER)); diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.h b/drivers/net/wireless/microchip/wilc1000/netdev.h new file mode 100644 index 000000000000..d0a006b68d08 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/netdev.h @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef WILC_NETDEV_H +#define WILC_NETDEV_H + +#include <linux/tcp.h> +#include <linux/ieee80211.h> +#include <net/cfg80211.h> +#include <net/ieee80211_radiotap.h> +#include <linux/if_arp.h> +#include <linux/gpio/consumer.h> + +#include "hif.h" +#include "wlan.h" +#include "wlan_cfg.h" + +#define FLOW_CONTROL_LOWER_THRESHOLD 128 +#define FLOW_CONTROL_UPPER_THRESHOLD 256 + +#define PMKID_FOUND 1 +#define NUM_STA_ASSOCIATED 8 + +#define TCP_ACK_FILTER_LINK_SPEED_THRESH 54 +#define DEFAULT_LINK_SPEED 72 + +struct wilc_wfi_stats { + unsigned long rx_packets; + unsigned long tx_packets; + unsigned long rx_bytes; + unsigned long tx_bytes; + u64 rx_time; + u64 tx_time; + +}; + +struct wilc_wfi_key { + u8 *key; + u8 *seq; + int key_len; + int seq_len; + u32 cipher; +}; + +struct wilc_wfi_wep_key { + u8 *key; + u8 key_len; + u8 key_idx; +}; + +struct sta_info { + u8 sta_associated_bss[WILC_MAX_NUM_STA][ETH_ALEN]; +}; + +/* Parameters needed for host interface for remaining on channel */ +struct wilc_wfi_p2p_listen_params { + struct ieee80211_channel *listen_ch; + u32 listen_duration; + u64 listen_cookie; +}; + +static const u32 wilc_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC +}; + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static const struct ieee80211_channel wilc_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0) +}; + +#define RATETAB_ENT(_rate, _hw_value, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_hw_value), \ + .flags = (_flags), \ +} + +static struct ieee80211_rate wilc_bitrates[] = { + RATETAB_ENT(10, 0, 0), + RATETAB_ENT(20, 1, 0), + RATETAB_ENT(55, 2, 0), + RATETAB_ENT(110, 3, 0), + RATETAB_ENT(60, 9, 0), + RATETAB_ENT(90, 6, 0), + RATETAB_ENT(120, 7, 0), + RATETAB_ENT(180, 8, 0), + RATETAB_ENT(240, 9, 0), + RATETAB_ENT(360, 10, 0), + RATETAB_ENT(480, 11, 0), + RATETAB_ENT(540, 12, 0) +}; + +struct wilc_priv { + struct wireless_dev wdev; + struct cfg80211_scan_request *scan_req; + + struct wilc_wfi_p2p_listen_params remain_on_ch_params; + u64 tx_cookie; + + bool cfg_scanning; + + u8 associated_bss[ETH_ALEN]; + struct sta_info assoc_stainfo; + struct sk_buff *skb; + struct net_device *dev; + struct host_if_drv *hif_drv; + struct wilc_pmkid_attr pmkid_list; + u8 wep_key[4][WLAN_KEY_LEN_WEP104]; + u8 wep_key_len[4]; + + /* The real interface that the monitor is on */ + struct net_device *real_ndev; + struct wilc_wfi_key *wilc_gtk[WILC_MAX_NUM_STA]; + struct wilc_wfi_key *wilc_ptk[WILC_MAX_NUM_STA]; + u8 wilc_groupkey; + + /* mutexes */ + struct mutex scan_req_lock; + bool p2p_listen_state; + int scanned_cnt; + + u64 inc_roc_cookie; +}; + +#define MAX_TCP_SESSION 25 +#define MAX_PENDING_ACKS 256 + +struct ack_session_info { + u32 seq_num; + u32 bigger_ack_num; + u16 src_port; + u16 dst_port; + u16 status; +}; + +struct pending_acks { + u32 ack_num; + u32 session_index; + struct txq_entry_t *txqe; +}; + +struct tcp_ack_filter { + struct ack_session_info ack_session_info[2 * MAX_TCP_SESSION]; + struct pending_acks pending_acks[MAX_PENDING_ACKS]; + u32 pending_base; + u32 tcp_session; + u32 pending_acks_idx; + bool enabled; +}; + +struct wilc_vif { + u8 idx; + u8 iftype; + int monitor_flag; + int mac_opened; + u32 mgmt_reg_stypes; + struct net_device_stats netstats; + struct wilc *wilc; + u8 bssid[ETH_ALEN]; + struct host_if_drv *hif_drv; + struct net_device *ndev; + u8 mode; + struct timer_list during_ip_timer; + struct timer_list periodic_rssi; + struct rf_info periodic_stat; + struct tcp_ack_filter ack_filter; + bool connecting; + struct wilc_priv priv; + struct list_head list; + struct cfg80211_bss *bss; +}; + +struct wilc { + struct wiphy *wiphy; + const struct wilc_hif_func *hif_func; + int io_type; + s8 mac_status; + struct clk *rtc_clk; + bool initialized; + int dev_irq_num; + int close; + u8 vif_num; + struct list_head vif_list; + + /* protect vif list */ + struct mutex vif_mutex; + struct srcu_struct srcu; + u8 open_ifcs; + + /* protect head of transmit queue */ + struct mutex txq_add_to_head_cs; + + /* protect txq_entry_t transmit queue */ + spinlock_t txq_spinlock; + + /* protect rxq_entry_t receiver queue */ + struct mutex rxq_cs; + + /* lock to protect hif access */ + struct mutex hif_cs; + + struct completion cfg_event; + struct completion sync_event; + struct completion txq_event; + struct completion txq_thread_started; + + struct task_struct *txq_thread; + + int quit; + + /* lock to protect issue of wid command to firmware */ + struct mutex cfg_cmd_lock; + struct wilc_cfg_frame cfg_frame; + u32 cfg_frame_offset; + u8 cfg_seq_no; + + u8 *rx_buffer; + u32 rx_buffer_offset; + u8 *tx_buffer; + + struct txq_entry_t txq_head; + int txq_entries; + + struct rxq_entry_t rxq_head; + + const struct firmware *firmware; + + struct device *dev; + bool suspend_event; + + int clients_count; + struct workqueue_struct *hif_workqueue; + enum chip_ps_states chip_ps_state; + struct wilc_cfg cfg; + void *bus_data; + struct net_device *monitor_dev; + + /* deinit lock */ + struct mutex deinit_lock; + u8 sta_ch; + u8 op_ch; + struct ieee80211_channel channels[ARRAY_SIZE(wilc_2ghz_channels)]; + struct ieee80211_rate bitrates[ARRAY_SIZE(wilc_bitrates)]; + struct ieee80211_supported_band band; + u32 cipher_suites[ARRAY_SIZE(wilc_cipher_suites)]; +}; + +struct wilc_wfi_mon_priv { + struct net_device *real_ndev; +}; + +void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset); +void wilc_mac_indicate(struct wilc *wilc); +void wilc_netdev_cleanup(struct wilc *wilc); +void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size); +void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode); +struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, + int vif_type, enum nl80211_iftype type, + bool rtnl_locked); +#endif diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c new file mode 100644 index 000000000000..3ece7b0b0392 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/sdio.c @@ -0,0 +1,1021 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> +#include <linux/of_irq.h> + +#include "netdev.h" +#include "cfg80211.h" + +#define SDIO_MODALIAS "wilc1000_sdio" + +static const struct sdio_device_id wilc_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_MICROCHIP_WILC, SDIO_DEVICE_ID_MICROCHIP_WILC1000) }, + { }, +}; + +#define WILC_SDIO_BLOCK_SIZE 512 + +struct wilc_sdio { + bool irq_gpio; + u32 block_size; + int has_thrpt_enh3; +}; + +struct sdio_cmd52 { + u32 read_write: 1; + u32 function: 3; + u32 raw: 1; + u32 address: 17; + u32 data: 8; +}; + +struct sdio_cmd53 { + u32 read_write: 1; + u32 function: 3; + u32 block_mode: 1; + u32 increment: 1; + u32 address: 17; + u32 count: 9; + u8 *buffer; + u32 block_size; +}; + +static const struct wilc_hif_func wilc_hif_sdio; + +static void wilc_sdio_interrupt(struct sdio_func *func) +{ + sdio_release_host(func); + wilc_handle_isr(sdio_get_drvdata(func)); + sdio_claim_host(func); +} + +static int wilc_sdio_cmd52(struct wilc *wilc, struct sdio_cmd52 *cmd) +{ + struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev); + int ret; + u8 data; + + sdio_claim_host(func); + + func->num = cmd->function; + if (cmd->read_write) { /* write */ + if (cmd->raw) { + sdio_writeb(func, cmd->data, cmd->address, &ret); + data = sdio_readb(func, cmd->address, &ret); + cmd->data = data; + } else { + sdio_writeb(func, cmd->data, cmd->address, &ret); + } + } else { /* read */ + data = sdio_readb(func, cmd->address, &ret); + cmd->data = data; + } + + sdio_release_host(func); + + if (ret) + dev_err(&func->dev, "%s..failed, err(%d)\n", __func__, ret); + return ret; +} + +static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd) +{ + struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev); + int size, ret; + + sdio_claim_host(func); + + func->num = cmd->function; + func->cur_blksize = cmd->block_size; + if (cmd->block_mode) + size = cmd->count * cmd->block_size; + else + size = cmd->count; + + if (cmd->read_write) { /* write */ + ret = sdio_memcpy_toio(func, cmd->address, + (void *)cmd->buffer, size); + } else { /* read */ + ret = sdio_memcpy_fromio(func, (void *)cmd->buffer, + cmd->address, size); + } + + sdio_release_host(func); + + if (ret) + dev_err(&func->dev, "%s..failed, err(%d)\n", __func__, ret); + + return ret; +} + +static int wilc_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct wilc *wilc; + int ret; + struct wilc_sdio *sdio_priv; + + sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL); + if (!sdio_priv) + return -ENOMEM; + + ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO, + &wilc_hif_sdio); + if (ret) { + kfree(sdio_priv); + return ret; + } + + if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) { + struct device_node *np = func->card->dev.of_node; + int irq_num = of_irq_get(np, 0); + + if (irq_num > 0) { + wilc->dev_irq_num = irq_num; + sdio_priv->irq_gpio = true; + } + } + + sdio_set_drvdata(func, wilc); + wilc->bus_data = sdio_priv; + wilc->dev = &func->dev; + + wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc"); + if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (!IS_ERR(wilc->rtc_clk)) + clk_prepare_enable(wilc->rtc_clk); + + dev_info(&func->dev, "Driver Initializing success\n"); + return 0; +} + +static void wilc_sdio_remove(struct sdio_func *func) +{ + struct wilc *wilc = sdio_get_drvdata(func); + + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + + wilc_netdev_cleanup(wilc); +} + +static int wilc_sdio_reset(struct wilc *wilc) +{ + struct sdio_cmd52 cmd; + int ret; + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = SDIO_CCCR_ABORT; + cmd.data = WILC_SDIO_CCCR_ABORT_RESET; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Fail cmd 52, reset cmd ...\n"); + return ret; + } + return 0; +} + +static int wilc_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct wilc *wilc = sdio_get_drvdata(func); + int ret; + + dev_info(dev, "sdio suspend\n"); + chip_wakeup(wilc); + + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + + if (wilc->suspend_event) { + host_sleep_notify(wilc); + chip_allow_sleep(wilc); + } + + ret = wilc_sdio_reset(wilc); + if (ret) { + dev_err(&func->dev, "Fail reset sdio\n"); + return ret; + } + sdio_claim_host(func); + + return 0; +} + +static int wilc_sdio_enable_interrupt(struct wilc *dev) +{ + struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev); + int ret = 0; + + sdio_claim_host(func); + ret = sdio_claim_irq(func, wilc_sdio_interrupt); + sdio_release_host(func); + + if (ret < 0) { + dev_err(&func->dev, "can't claim sdio_irq, err(%d)\n", ret); + ret = -EIO; + } + return ret; +} + +static void wilc_sdio_disable_interrupt(struct wilc *dev) +{ + struct sdio_func *func = container_of(dev->dev, struct sdio_func, dev); + int ret; + + sdio_claim_host(func); + ret = sdio_release_irq(func); + if (ret < 0) + dev_err(&func->dev, "can't release sdio_irq, err(%d)\n", ret); + sdio_release_host(func); +} + +/******************************************** + * + * Function 0 + * + ********************************************/ + +static int wilc_sdio_set_func0_csa_address(struct wilc *wilc, u32 adr) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct sdio_cmd52 cmd; + int ret; + + /** + * Review: BIG ENDIAN + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC_SDIO_FBR_CSA_REG; + cmd.data = (u8)adr; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; + } + + cmd.address = WILC_SDIO_FBR_CSA_REG + 1; + cmd.data = (u8)(adr >> 8); + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; + } + + cmd.address = WILC_SDIO_FBR_CSA_REG + 2; + cmd.data = (u8)(adr >> 16); + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; + } + + return 0; +} + +static int wilc_sdio_set_block_size(struct wilc *wilc, u8 func_num, + u32 block_size) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct sdio_cmd52 cmd; + int ret; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE; + cmd.data = (u8)block_size; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; + } + + cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE + 1; + cmd.data = (u8)(block_size >> 8); + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Failed cmd52, set %04x data...\n", + cmd.address); + return ret; + } + + return 0; +} + +/******************************************** + * + * Sdio interfaces + * + ********************************************/ +static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + int ret; + + cpu_to_le32s(&data); + + if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */ + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + cmd.data = data; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) + dev_err(&func->dev, + "Failed cmd 52, read reg (%08x) ...\n", addr); + } else { + struct sdio_cmd53 cmd; + + /** + * set the AHB address + **/ + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + + cmd.read_write = 1; + cmd.function = 0; + cmd.address = WILC_SDIO_FBR_DATA_REG; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = 4; + cmd.buffer = (u8 *)&data; + cmd.block_size = sdio_priv->block_size; + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) + dev_err(&func->dev, + "Failed cmd53, write reg (%08x)...\n", addr); + } + + return ret; +} + +static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 block_size = sdio_priv->block_size; + struct sdio_cmd53 cmd; + int nblk, nleft, ret; + + cmd.read_write = 1; + if (addr > 0) { + /** + * func 0 access + **/ + cmd.function = 0; + cmd.address = WILC_SDIO_FBR_DATA_REG; + } else { + /** + * func 1 access + **/ + cmd.function = 1; + cmd.address = WILC_SDIO_F1_DATA_REG; + } + + size = ALIGN(size, 4); + nblk = size / block_size; + nleft = size % block_size; + + if (nblk > 0) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = nblk; + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + } + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd53 [%x], block send...\n", addr); + return ret; + } + if (addr > 0) + addr += nblk * block_size; + buf += nblk * block_size; + } + + if (nleft > 0) { + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = nleft; + cmd.buffer = buf; + + cmd.block_size = block_size; + + if (addr > 0) { + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + } + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd53 [%x], bytes send...\n", addr); + return ret; + } + } + + return 0; +} + +static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + int ret; + + if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */ + struct sdio_cmd52 cmd; + + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = addr; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd 52, read reg (%08x) ...\n", addr); + return ret; + } + *data = cmd.data; + } else { + struct sdio_cmd53 cmd; + + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + + cmd.read_write = 0; + cmd.function = 0; + cmd.address = WILC_SDIO_FBR_DATA_REG; + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = 4; + cmd.buffer = (u8 *)data; + + cmd.block_size = sdio_priv->block_size; + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd53, read reg (%08x)...\n", addr); + return ret; + } + } + + le32_to_cpus(data); + return 0; +} + +static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 block_size = sdio_priv->block_size; + struct sdio_cmd53 cmd; + int nblk, nleft, ret; + + cmd.read_write = 0; + if (addr > 0) { + /** + * func 0 access + **/ + cmd.function = 0; + cmd.address = WILC_SDIO_FBR_DATA_REG; + } else { + /** + * func 1 access + **/ + cmd.function = 1; + cmd.address = WILC_SDIO_F1_DATA_REG; + } + + size = ALIGN(size, 4); + nblk = size / block_size; + nleft = size % block_size; + + if (nblk > 0) { + cmd.block_mode = 1; + cmd.increment = 1; + cmd.count = nblk; + cmd.buffer = buf; + cmd.block_size = block_size; + if (addr > 0) { + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + } + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd53 [%x], block read...\n", addr); + return ret; + } + if (addr > 0) + addr += nblk * block_size; + buf += nblk * block_size; + } /* if (nblk > 0) */ + + if (nleft > 0) { + cmd.block_mode = 0; + cmd.increment = 1; + cmd.count = nleft; + cmd.buffer = buf; + + cmd.block_size = block_size; + + if (addr > 0) { + ret = wilc_sdio_set_func0_csa_address(wilc, addr); + if (ret) + return ret; + } + ret = wilc_sdio_cmd53(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd53 [%x], bytes read...\n", addr); + return ret; + } + } + + return 0; +} + +/******************************************** + * + * Bus interfaces + * + ********************************************/ + +static int wilc_sdio_deinit(struct wilc *wilc) +{ + return 0; +} + +static int wilc_sdio_init(struct wilc *wilc, bool resume) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + struct sdio_cmd52 cmd; + int loop, ret; + u32 chipid; + + /** + * function 0 csa enable + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = SDIO_FBR_BASE(func->num); + cmd.data = SDIO_FBR_ENABLE_CSA; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Fail cmd 52, enable csa...\n"); + return ret; + } + + /** + * function 0 block size + **/ + ret = wilc_sdio_set_block_size(wilc, 0, WILC_SDIO_BLOCK_SIZE); + if (ret) { + dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n"); + return ret; + } + sdio_priv->block_size = WILC_SDIO_BLOCK_SIZE; + + /** + * enable func1 IO + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = SDIO_CCCR_IOEx; + cmd.data = WILC_SDIO_CCCR_IO_EN_FUNC1; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Fail cmd 52, set IOE register...\n"); + return ret; + } + + /** + * make sure func 1 is up + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = SDIO_CCCR_IORx; + loop = 3; + do { + cmd.data = 0; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Fail cmd 52, get IOR register...\n"); + return ret; + } + if (cmd.data == WILC_SDIO_CCCR_IO_EN_FUNC1) + break; + } while (loop--); + + if (loop <= 0) { + dev_err(&func->dev, "Fail func 1 is not ready...\n"); + return -EINVAL; + } + + /** + * func 1 is ready, set func 1 block size + **/ + ret = wilc_sdio_set_block_size(wilc, 1, WILC_SDIO_BLOCK_SIZE); + if (ret) { + dev_err(&func->dev, "Fail set func 1 block size...\n"); + return ret; + } + + /** + * func 1 interrupt enable + **/ + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 1; + cmd.address = SDIO_CCCR_IENx; + cmd.data = WILC_SDIO_CCCR_IEN_MASTER | WILC_SDIO_CCCR_IEN_FUNC1; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, "Fail cmd 52, set IEN register...\n"); + return ret; + } + + /** + * make sure can read back chip id correctly + **/ + if (!resume) { + int rev; + + ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid); + if (ret) { + dev_err(&func->dev, "Fail cmd read chip id...\n"); + return ret; + } + dev_err(&func->dev, "chipid (%08x)\n", chipid); + rev = FIELD_GET(WILC_CHIP_REV_FIELD, chipid); + if (rev > FIELD_GET(WILC_CHIP_REV_FIELD, WILC_1000_BASE_ID_2A)) + sdio_priv->has_thrpt_enh3 = 1; + else + sdio_priv->has_thrpt_enh3 = 0; + dev_info(&func->dev, "has_thrpt_enh3 = %d...\n", + sdio_priv->has_thrpt_enh3); + } + + return 0; +} + +static int wilc_sdio_read_size(struct wilc *wilc, u32 *size) +{ + u32 tmp; + struct sdio_cmd52 cmd; + + /** + * Read DMA count in words + **/ + cmd.read_write = 0; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG; + cmd.data = 0; + wilc_sdio_cmd52(wilc, &cmd); + tmp = cmd.data; + + cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG + 1; + cmd.data = 0; + wilc_sdio_cmd52(wilc, &cmd); + tmp |= (cmd.data << 8); + + *size = tmp; + return 0; +} + +static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 tmp; + u8 irq_flags; + struct sdio_cmd52 cmd; + + wilc_sdio_read_size(wilc, &tmp); + + /** + * Read IRQ flags + **/ + if (!sdio_priv->irq_gpio) { + cmd.function = 1; + cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG; + } else { + cmd.function = 0; + cmd.address = WILC_SDIO_IRQ_FLAG_REG; + } + cmd.raw = 0; + cmd.read_write = 0; + cmd.data = 0; + wilc_sdio_cmd52(wilc, &cmd); + irq_flags = cmd.data; + tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data); + + if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)) + dev_err(&func->dev, "Unexpected interrupt (1) int=%lx\n", + FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags)); + + *int_status = tmp; + + return 0; +} + +static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + int ret; + int vmm_ctl; + + if (sdio_priv->has_thrpt_enh3) { + u32 reg = 0; + + if (sdio_priv->irq_gpio) + reg = val & (BIT(MAX_NUM_INT) - 1); + + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + reg |= BIT(5); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + reg |= BIT(6); + /* enable VMM */ + if (val & EN_VMM) + reg |= BIT(7); + if (reg) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.data = reg; + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set (%02x) data (%d) ...\n", + cmd.address, __LINE__); + return ret; + } + } + return 0; + } + if (sdio_priv->irq_gpio) { + /* has_thrpt_enh2 uses register 0xf8 to clear interrupts. */ + /* + * Cannot clear multiple interrupts. + * Must clear each interrupt individually. + */ + u32 flags; + int i; + + flags = val & (BIT(MAX_NUM_INT) - 1); + for (i = 0; i < NUM_INT_EXT && flags; i++) { + if (flags & BIT(i)) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG; + cmd.data = BIT(i); + + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set (%02x) data (%d) ...\n", + cmd.address, __LINE__); + return ret; + } + flags &= ~BIT(i); + } + } + + for (i = NUM_INT_EXT; i < MAX_NUM_INT && flags; i++) { + if (flags & BIT(i)) { + dev_err(&func->dev, + "Unexpected interrupt cleared %d...\n", + i); + flags &= ~BIT(i); + } + } + } + + vmm_ctl = 0; + /* select VMM table 0 */ + if (val & SEL_VMM_TBL0) + vmm_ctl |= BIT(0); + /* select VMM table 1 */ + if (val & SEL_VMM_TBL1) + vmm_ctl |= BIT(1); + /* enable VMM */ + if (val & EN_VMM) + vmm_ctl |= BIT(2); + + if (vmm_ctl) { + struct sdio_cmd52 cmd; + + cmd.read_write = 1; + cmd.function = 0; + cmd.raw = 0; + cmd.address = WILC_SDIO_VMM_TBL_CTRL_REG; + cmd.data = vmm_ctl; + ret = wilc_sdio_cmd52(wilc, &cmd); + if (ret) { + dev_err(&func->dev, + "Failed cmd52, set (%02x) data (%d) ...\n", + cmd.address, __LINE__); + return ret; + } + } + return 0; +} + +static int wilc_sdio_sync_ext(struct wilc *wilc, int nint) +{ + struct sdio_func *func = dev_to_sdio_func(wilc->dev); + struct wilc_sdio *sdio_priv = wilc->bus_data; + u32 reg; + + if (nint > MAX_NUM_INT) { + dev_err(&func->dev, "Too many interrupts (%d)...\n", nint); + return -EINVAL; + } + + /** + * Disable power sequencer + **/ + if (wilc_sdio_read_reg(wilc, WILC_MISC, ®)) { + dev_err(&func->dev, "Failed read misc reg...\n"); + return -EINVAL; + } + + reg &= ~BIT(8); + if (wilc_sdio_write_reg(wilc, WILC_MISC, reg)) { + dev_err(&func->dev, "Failed write misc reg...\n"); + return -EINVAL; + } + + if (sdio_priv->irq_gpio) { + u32 reg; + int ret, i; + + /** + * interrupt pin mux select + **/ + ret = wilc_sdio_read_reg(wilc, WILC_PIN_MUX_0, ®); + if (ret) { + dev_err(&func->dev, "Failed read reg (%08x)...\n", + WILC_PIN_MUX_0); + return ret; + } + reg |= BIT(8); + ret = wilc_sdio_write_reg(wilc, WILC_PIN_MUX_0, reg); + if (ret) { + dev_err(&func->dev, "Failed write reg (%08x)...\n", + WILC_PIN_MUX_0); + return ret; + } + + /** + * interrupt enable + **/ + ret = wilc_sdio_read_reg(wilc, WILC_INTR_ENABLE, ®); + if (ret) { + dev_err(&func->dev, "Failed read reg (%08x)...\n", + WILC_INTR_ENABLE); + return ret; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) + reg |= BIT((27 + i)); + ret = wilc_sdio_write_reg(wilc, WILC_INTR_ENABLE, reg); + if (ret) { + dev_err(&func->dev, "Failed write reg (%08x)...\n", + WILC_INTR_ENABLE); + return ret; + } + if (nint) { + ret = wilc_sdio_read_reg(wilc, WILC_INTR2_ENABLE, ®); + if (ret) { + dev_err(&func->dev, + "Failed read reg (%08x)...\n", + WILC_INTR2_ENABLE); + return ret; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) + reg |= BIT(i); + + ret = wilc_sdio_read_reg(wilc, WILC_INTR2_ENABLE, ®); + if (ret) { + dev_err(&func->dev, + "Failed write reg (%08x)...\n", + WILC_INTR2_ENABLE); + return ret; + } + } + } + return 0; +} + +/* Global sdio HIF function table */ +static const struct wilc_hif_func wilc_hif_sdio = { + .hif_init = wilc_sdio_init, + .hif_deinit = wilc_sdio_deinit, + .hif_read_reg = wilc_sdio_read_reg, + .hif_write_reg = wilc_sdio_write_reg, + .hif_block_rx = wilc_sdio_read, + .hif_block_tx = wilc_sdio_write, + .hif_read_int = wilc_sdio_read_int, + .hif_clear_int_ext = wilc_sdio_clear_int_ext, + .hif_read_size = wilc_sdio_read_size, + .hif_block_tx_ext = wilc_sdio_write, + .hif_block_rx_ext = wilc_sdio_read, + .hif_sync_ext = wilc_sdio_sync_ext, + .enable_interrupt = wilc_sdio_enable_interrupt, + .disable_interrupt = wilc_sdio_disable_interrupt, +}; + +static int wilc_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct wilc *wilc = sdio_get_drvdata(func); + + dev_info(dev, "sdio resume\n"); + sdio_release_host(func); + chip_wakeup(wilc); + wilc_sdio_init(wilc, true); + + if (wilc->suspend_event) + host_wakeup_notify(wilc); + + chip_allow_sleep(wilc); + + return 0; +} + +static const struct of_device_id wilc_of_match[] = { + { .compatible = "microchip,wilc1000", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, wilc_of_match); + +static const struct dev_pm_ops wilc_sdio_pm_ops = { + .suspend = wilc_sdio_suspend, + .resume = wilc_sdio_resume, +}; + +static struct sdio_driver wilc_sdio_driver = { + .name = SDIO_MODALIAS, + .id_table = wilc_sdio_ids, + .probe = wilc_sdio_probe, + .remove = wilc_sdio_remove, + .drv = { + .pm = &wilc_sdio_pm_ops, + .of_match_table = wilc_of_match, + } +}; +module_driver(wilc_sdio_driver, + sdio_register_driver, + sdio_unregister_driver); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c new file mode 100644 index 000000000000..3f19e3f38a39 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/spi.c @@ -0,0 +1,945 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/spi/spi.h> +#include <linux/crc7.h> + +#include "netdev.h" +#include "cfg80211.h" + +struct wilc_spi { + int crc_off; +}; + +static const struct wilc_hif_func wilc_hif_spi; + +/******************************************** + * + * Spi protocol Function + * + ********************************************/ + +#define CMD_DMA_WRITE 0xc1 +#define CMD_DMA_READ 0xc2 +#define CMD_INTERNAL_WRITE 0xc3 +#define CMD_INTERNAL_READ 0xc4 +#define CMD_TERMINATE 0xc5 +#define CMD_REPEAT 0xc6 +#define CMD_DMA_EXT_WRITE 0xc7 +#define CMD_DMA_EXT_READ 0xc8 +#define CMD_SINGLE_WRITE 0xc9 +#define CMD_SINGLE_READ 0xca +#define CMD_RESET 0xcf + +#define DATA_PKT_SZ_256 256 +#define DATA_PKT_SZ_512 512 +#define DATA_PKT_SZ_1K 1024 +#define DATA_PKT_SZ_4K (4 * 1024) +#define DATA_PKT_SZ_8K (8 * 1024) +#define DATA_PKT_SZ DATA_PKT_SZ_8K + +#define USE_SPI_DMA 0 + +#define WILC_SPI_COMMAND_STAT_SUCCESS 0 +#define WILC_GET_RESP_HDR_START(h) (((h) >> 4) & 0xf) + +struct wilc_spi_cmd { + u8 cmd_type; + union { + struct { + u8 addr[3]; + u8 crc[]; + } __packed simple_cmd; + struct { + u8 addr[3]; + u8 size[2]; + u8 crc[]; + } __packed dma_cmd; + struct { + u8 addr[3]; + u8 size[3]; + u8 crc[]; + } __packed dma_cmd_ext; + struct { + u8 addr[2]; + __be32 data; + u8 crc[]; + } __packed internal_w_cmd; + struct { + u8 addr[3]; + __be32 data; + u8 crc[]; + } __packed w_cmd; + } u; +} __packed; + +struct wilc_spi_read_rsp_data { + u8 rsp_cmd_type; + u8 status; + u8 resp_header; + u8 resp_data[4]; + u8 crc[]; +} __packed; + +struct wilc_spi_rsp_data { + u8 rsp_cmd_type; + u8 status; +} __packed; + +static int wilc_bus_probe(struct spi_device *spi) +{ + int ret; + struct wilc *wilc; + struct wilc_spi *spi_priv; + + spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL); + if (!spi_priv) + return -ENOMEM; + + ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi); + if (ret) { + kfree(spi_priv); + return ret; + } + + spi_set_drvdata(spi, wilc); + wilc->dev = &spi->dev; + wilc->bus_data = spi_priv; + wilc->dev_irq_num = spi->irq; + + wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk"); + if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (!IS_ERR(wilc->rtc_clk)) + clk_prepare_enable(wilc->rtc_clk); + + return 0; +} + +static int wilc_bus_remove(struct spi_device *spi) +{ + struct wilc *wilc = spi_get_drvdata(spi); + + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + + wilc_netdev_cleanup(wilc); + return 0; +} + +static const struct of_device_id wilc_of_match[] = { + { .compatible = "microchip,wilc1000", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, wilc_of_match); + +static struct spi_driver wilc_spi_driver = { + .driver = { + .name = MODALIAS, + .of_match_table = wilc_of_match, + }, + .probe = wilc_bus_probe, + .remove = wilc_bus_remove, +}; +module_spi_driver(wilc_spi_driver); +MODULE_LICENSE("GPL"); + +static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int ret; + struct spi_message msg; + + if (len > 0 && b) { + struct spi_transfer tr = { + .tx_buf = b, + .len = len, + .delay = { + .value = 0, + .unit = SPI_DELAY_UNIT_USECS + }, + }; + char *r_buffer = kzalloc(len, GFP_KERNEL); + + if (!r_buffer) + return -ENOMEM; + + tr.rx_buf = r_buffer; + dev_dbg(&spi->dev, "Request writing %d bytes\n", len); + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = spi; + msg.is_dma_mapped = USE_SPI_DMA; + spi_message_add_tail(&tr, &msg); + + ret = spi_sync(spi, &msg); + if (ret < 0) + dev_err(&spi->dev, "SPI transaction failed\n"); + + kfree(r_buffer); + } else { + dev_err(&spi->dev, + "can't write data with the following length: %d\n", + len); + ret = -EINVAL; + } + + return ret; +} + +static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .len = rlen, + .delay = { + .value = 0, + .unit = SPI_DELAY_UNIT_USECS + }, + + }; + char *t_buffer = kzalloc(rlen, GFP_KERNEL); + + if (!t_buffer) + return -ENOMEM; + + tr.tx_buf = t_buffer; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = spi; + msg.is_dma_mapped = USE_SPI_DMA; + spi_message_add_tail(&tr, &msg); + + ret = spi_sync(spi, &msg); + if (ret < 0) + dev_err(&spi->dev, "SPI transaction failed\n"); + kfree(t_buffer); + } else { + dev_err(&spi->dev, + "can't read data with the following length: %u\n", + rlen); + ret = -EINVAL; + } + + return ret; +} + +static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int ret; + + if (rlen > 0) { + struct spi_message msg; + struct spi_transfer tr = { + .rx_buf = rb, + .tx_buf = wb, + .len = rlen, + .bits_per_word = 8, + .delay = { + .value = 0, + .unit = SPI_DELAY_UNIT_USECS + }, + + }; + + memset(&msg, 0, sizeof(msg)); + spi_message_init(&msg); + msg.spi = spi; + msg.is_dma_mapped = USE_SPI_DMA; + + spi_message_add_tail(&tr, &msg); + ret = spi_sync(spi, &msg); + if (ret < 0) + dev_err(&spi->dev, "SPI transaction failed\n"); + } else { + dev_err(&spi->dev, + "can't read data with the following length: %u\n", + rlen); + ret = -EINVAL; + } + + return ret; +} + +static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + int ix, nbytes; + int result = 0; + u8 cmd, order, crc[2] = {0}; + + /* + * Data + */ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) { + nbytes = sz; + order = 0x3; + } else { + nbytes = DATA_PKT_SZ; + if (ix == 0) + order = 0x1; + else + order = 0x02; + } + + /* + * Write command + */ + cmd = 0xf0; + cmd |= order; + + if (wilc_spi_tx(wilc, &cmd, 1)) { + dev_err(&spi->dev, + "Failed data block cmd write, bus error...\n"); + result = -EINVAL; + break; + } + + /* + * Write data + */ + if (wilc_spi_tx(wilc, &b[ix], nbytes)) { + dev_err(&spi->dev, + "Failed data block write, bus error...\n"); + result = -EINVAL; + break; + } + + /* + * Write Crc + */ + if (!spi_priv->crc_off) { + if (wilc_spi_tx(wilc, crc, 2)) { + dev_err(&spi->dev, "Failed data block crc write, bus error...\n"); + result = -EINVAL; + break; + } + } + + /* + * No need to wait for response + */ + ix += nbytes; + sz -= nbytes; + } while (sz); + + return result; +} + +/******************************************** + * + * Spi Internal Read/Write Function + * + ********************************************/ +static u8 wilc_get_crc7(u8 *buffer, u32 len) +{ + return crc7_be(0xfe, buffer, len); +} + +static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b, + u8 clockless) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + u8 wb[32], rb[32]; + int cmd_len, resp_len; + u8 crc[2]; + struct wilc_spi_cmd *c; + struct wilc_spi_read_rsp_data *r; + + memset(wb, 0x0, sizeof(wb)); + memset(rb, 0x0, sizeof(rb)); + c = (struct wilc_spi_cmd *)wb; + c->cmd_type = cmd; + if (cmd == CMD_SINGLE_READ) { + c->u.simple_cmd.addr[0] = adr >> 16; + c->u.simple_cmd.addr[1] = adr >> 8; + c->u.simple_cmd.addr[2] = adr; + } else if (cmd == CMD_INTERNAL_READ) { + c->u.simple_cmd.addr[0] = adr >> 8; + if (clockless == 1) + c->u.simple_cmd.addr[0] |= BIT(7); + c->u.simple_cmd.addr[1] = adr; + c->u.simple_cmd.addr[2] = 0x0; + } else { + dev_err(&spi->dev, "cmd [%x] not supported\n", cmd); + return -EINVAL; + } + + cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc); + resp_len = sizeof(*r); + if (!spi_priv->crc_off) { + c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); + cmd_len += 1; + resp_len += 2; + } + + if (cmd_len + resp_len > ARRAY_SIZE(wb)) { + dev_err(&spi->dev, + "spi buffer size too small (%d) (%d) (%zu)\n", + cmd_len, resp_len, ARRAY_SIZE(wb)); + return -EINVAL; + } + + if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { + dev_err(&spi->dev, "Failed cmd write, bus error...\n"); + return -EINVAL; + } + + r = (struct wilc_spi_read_rsp_data *)&rb[cmd_len]; + if (r->rsp_cmd_type != cmd) { + dev_err(&spi->dev, + "Failed cmd response, cmd (%02x), resp (%02x)\n", + cmd, r->rsp_cmd_type); + return -EINVAL; + } + + if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { + dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", + r->status); + return -EINVAL; + } + + if (WILC_GET_RESP_HDR_START(r->resp_header) != 0xf) { + dev_err(&spi->dev, "Error, data read response (%02x)\n", + r->resp_header); + return -EINVAL; + } + + if (b) + memcpy(b, r->resp_data, 4); + + if (!spi_priv->crc_off) + memcpy(crc, r->crc, 2); + + return 0; +} + +static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data, + u8 clockless) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + u8 wb[32], rb[32]; + int cmd_len, resp_len; + struct wilc_spi_cmd *c; + struct wilc_spi_rsp_data *r; + + memset(wb, 0x0, sizeof(wb)); + memset(rb, 0x0, sizeof(rb)); + c = (struct wilc_spi_cmd *)wb; + c->cmd_type = cmd; + if (cmd == CMD_INTERNAL_WRITE) { + c->u.internal_w_cmd.addr[0] = adr >> 8; + if (clockless == 1) + c->u.internal_w_cmd.addr[0] |= BIT(7); + + c->u.internal_w_cmd.addr[1] = adr; + c->u.internal_w_cmd.data = cpu_to_be32(data); + cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc); + if (!spi_priv->crc_off) + c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); + } else if (cmd == CMD_SINGLE_WRITE) { + c->u.w_cmd.addr[0] = adr >> 16; + c->u.w_cmd.addr[1] = adr >> 8; + c->u.w_cmd.addr[2] = adr; + c->u.w_cmd.data = cpu_to_be32(data); + cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc); + if (!spi_priv->crc_off) + c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); + } else { + dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd); + return -EINVAL; + } + + if (!spi_priv->crc_off) + cmd_len += 1; + + resp_len = sizeof(*r); + + if (cmd_len + resp_len > ARRAY_SIZE(wb)) { + dev_err(&spi->dev, + "spi buffer size too small (%d) (%d) (%zu)\n", + cmd_len, resp_len, ARRAY_SIZE(wb)); + return -EINVAL; + } + + if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { + dev_err(&spi->dev, "Failed cmd write, bus error...\n"); + return -EINVAL; + } + + r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; + if (r->rsp_cmd_type != cmd) { + dev_err(&spi->dev, + "Failed cmd response, cmd (%02x), resp (%02x)\n", + cmd, r->rsp_cmd_type); + return -EINVAL; + } + + if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { + dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", + r->status); + return -EINVAL; + } + + return 0; +} + +static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + u8 wb[32], rb[32]; + int cmd_len, resp_len; + int retry, ix = 0; + u8 crc[2]; + struct wilc_spi_cmd *c; + struct wilc_spi_rsp_data *r; + + memset(wb, 0x0, sizeof(wb)); + memset(rb, 0x0, sizeof(rb)); + c = (struct wilc_spi_cmd *)wb; + c->cmd_type = cmd; + if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) { + c->u.dma_cmd.addr[0] = adr >> 16; + c->u.dma_cmd.addr[1] = adr >> 8; + c->u.dma_cmd.addr[2] = adr; + c->u.dma_cmd.size[0] = sz >> 8; + c->u.dma_cmd.size[1] = sz; + cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc); + if (!spi_priv->crc_off) + c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len); + } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) { + c->u.dma_cmd_ext.addr[0] = adr >> 16; + c->u.dma_cmd_ext.addr[1] = adr >> 8; + c->u.dma_cmd_ext.addr[2] = adr; + c->u.dma_cmd_ext.size[0] = sz >> 16; + c->u.dma_cmd_ext.size[1] = sz >> 8; + c->u.dma_cmd_ext.size[2] = sz; + cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc); + if (!spi_priv->crc_off) + c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len); + } else { + dev_err(&spi->dev, "dma read write cmd [%x] not supported\n", + cmd); + return -EINVAL; + } + if (!spi_priv->crc_off) + cmd_len += 1; + + resp_len = sizeof(*r); + + if (cmd_len + resp_len > ARRAY_SIZE(wb)) { + dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n", + cmd_len, resp_len, ARRAY_SIZE(wb)); + return -EINVAL; + } + + if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) { + dev_err(&spi->dev, "Failed cmd write, bus error...\n"); + return -EINVAL; + } + + r = (struct wilc_spi_rsp_data *)&rb[cmd_len]; + if (r->rsp_cmd_type != cmd) { + dev_err(&spi->dev, + "Failed cmd response, cmd (%02x), resp (%02x)\n", + cmd, r->rsp_cmd_type); + return -EINVAL; + } + + if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) { + dev_err(&spi->dev, "Failed cmd state response state (%02x)\n", + r->status); + return -EINVAL; + } + + if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE) + return 0; + + while (sz > 0) { + int nbytes; + u8 rsp; + + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /* + * Data Response header + */ + retry = 100; + do { + if (wilc_spi_rx(wilc, &rsp, 1)) { + dev_err(&spi->dev, + "Failed resp read, bus err\n"); + return -EINVAL; + } + if (WILC_GET_RESP_HDR_START(rsp) == 0xf) + break; + } while (retry--); + + /* + * Read bytes + */ + if (wilc_spi_rx(wilc, &b[ix], nbytes)) { + dev_err(&spi->dev, + "Failed block read, bus err\n"); + return -EINVAL; + } + + /* + * Read Crc + */ + if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) { + dev_err(&spi->dev, + "Failed block crc read, bus err\n"); + return -EINVAL; + } + + ix += nbytes; + sz -= nbytes; + } + return 0; +} + +static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result; + u8 cmd = CMD_SINGLE_READ; + u8 clockless = 0; + + if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { + /* Clockless register */ + cmd = CMD_INTERNAL_READ; + clockless = 1; + } + + result = wilc_spi_single_read(wilc, cmd, addr, data, clockless); + if (result) { + dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr); + return result; + } + + le32_to_cpus(data); + + return 0; +} + +static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result; + + if (size <= 4) + return -EINVAL; + + result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size); + if (result) { + dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr); + return result; + } + + return 0; +} + +static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result; + + result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0); + if (result) { + dev_err(&spi->dev, "Failed internal write cmd...\n"); + return result; + } + + return 0; +} + +static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result; + + result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0); + if (result) { + dev_err(&spi->dev, "Failed internal read cmd...\n"); + return result; + } + + le32_to_cpus(data); + + return 0; +} + +/******************************************** + * + * Spi interfaces + * + ********************************************/ + +static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result; + u8 cmd = CMD_SINGLE_WRITE; + u8 clockless = 0; + + if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) { + /* Clockless register */ + cmd = CMD_INTERNAL_WRITE; + clockless = 1; + } + + result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless); + if (result) { + dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr); + return result; + } + + return 0; +} + +static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + int result; + + /* + * has to be greated than 4 + */ + if (size <= 4) + return -EINVAL; + + result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size); + if (result) { + dev_err(&spi->dev, + "Failed cmd, write block (%08x)...\n", addr); + return result; + } + + /* + * Data + */ + result = spi_data_write(wilc, buf, size); + if (result) { + dev_err(&spi->dev, "Failed block data write...\n"); + return result; + } + + return 0; +} + +/******************************************** + * + * Bus interfaces + * + ********************************************/ + +static int wilc_spi_deinit(struct wilc *wilc) +{ + /* + * TODO: + */ + return 0; +} + +static int wilc_spi_init(struct wilc *wilc, bool resume) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + struct wilc_spi *spi_priv = wilc->bus_data; + u32 reg; + u32 chipid; + static int isinit; + int ret; + + if (isinit) { + ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); + if (ret) + dev_err(&spi->dev, "Fail cmd read chip id...\n"); + + return ret; + } + + /* + * configure protocol + */ + + /* + * TODO: We can remove the CRC trials if there is a definite + * way to reset + */ + /* the SPI to it's initial value. */ + ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); + if (ret) { + /* + * Read failed. Try with CRC off. This might happen when module + * is removed but chip isn't reset + */ + spi_priv->crc_off = 1; + dev_err(&spi->dev, + "Failed read with CRC on, retrying with CRC off\n"); + ret = spi_internal_read(wilc, WILC_SPI_PROTOCOL_OFFSET, ®); + if (ret) { + /* + * Read failed with both CRC on and off, + * something went bad + */ + dev_err(&spi->dev, "Failed internal read protocol\n"); + return ret; + } + } + if (spi_priv->crc_off == 0) { + reg &= ~0xc; /* disable crc checking */ + reg &= ~0x70; + reg |= (0x5 << 4); + ret = spi_internal_write(wilc, WILC_SPI_PROTOCOL_OFFSET, reg); + if (ret) { + dev_err(&spi->dev, + "[wilc spi %d]: Failed internal write reg\n", + __LINE__); + return ret; + } + spi_priv->crc_off = 1; + } + + /* + * make sure can read back chip id correctly + */ + ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid); + if (ret) { + dev_err(&spi->dev, "Fail cmd read chip id...\n"); + return ret; + } + + isinit = 1; + + return 0; +} + +static int wilc_spi_read_size(struct wilc *wilc, u32 *size) +{ + int ret; + + ret = spi_internal_read(wilc, + WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size); + *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size); + + return ret; +} + +static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status) +{ + return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, + int_status); +} + +static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val) +{ + return spi_internal_write(wilc, WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE, + val); +} + +static int wilc_spi_sync_ext(struct wilc *wilc, int nint) +{ + struct spi_device *spi = to_spi_device(wilc->dev); + u32 reg; + int ret, i; + + if (nint > MAX_NUM_INT) { + dev_err(&spi->dev, "Too many interrupts (%d)...\n", nint); + return -EINVAL; + } + + /* + * interrupt pin mux select + */ + ret = wilc_spi_read_reg(wilc, WILC_PIN_MUX_0, ®); + if (ret) { + dev_err(&spi->dev, "Failed read reg (%08x)...\n", + WILC_PIN_MUX_0); + return ret; + } + reg |= BIT(8); + ret = wilc_spi_write_reg(wilc, WILC_PIN_MUX_0, reg); + if (ret) { + dev_err(&spi->dev, "Failed write reg (%08x)...\n", + WILC_PIN_MUX_0); + return ret; + } + + /* + * interrupt enable + */ + ret = wilc_spi_read_reg(wilc, WILC_INTR_ENABLE, ®); + if (ret) { + dev_err(&spi->dev, "Failed read reg (%08x)...\n", + WILC_INTR_ENABLE); + return ret; + } + + for (i = 0; (i < 5) && (nint > 0); i++, nint--) + reg |= (BIT((27 + i))); + + ret = wilc_spi_write_reg(wilc, WILC_INTR_ENABLE, reg); + if (ret) { + dev_err(&spi->dev, "Failed write reg (%08x)...\n", + WILC_INTR_ENABLE); + return ret; + } + if (nint) { + ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); + if (ret) { + dev_err(&spi->dev, "Failed read reg (%08x)...\n", + WILC_INTR2_ENABLE); + return ret; + } + + for (i = 0; (i < 3) && (nint > 0); i++, nint--) + reg |= BIT(i); + + ret = wilc_spi_read_reg(wilc, WILC_INTR2_ENABLE, ®); + if (ret) { + dev_err(&spi->dev, "Failed write reg (%08x)...\n", + WILC_INTR2_ENABLE); + return ret; + } + } + + return 0; +} + +/* Global spi HIF function table */ +static const struct wilc_hif_func wilc_hif_spi = { + .hif_init = wilc_spi_init, + .hif_deinit = wilc_spi_deinit, + .hif_read_reg = wilc_spi_read_reg, + .hif_write_reg = wilc_spi_write_reg, + .hif_block_rx = wilc_spi_read, + .hif_block_tx = wilc_spi_write, + .hif_read_int = wilc_spi_read_int, + .hif_clear_int_ext = wilc_spi_clear_int_ext, + .hif_read_size = wilc_spi_read_size, + .hif_block_tx_ext = wilc_spi_write, + .hif_block_rx_ext = wilc_spi_read, + .hif_sync_ext = wilc_spi_sync_ext, +}; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c new file mode 100644 index 000000000000..6a82fb2f283e --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -0,0 +1,1238 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include <linux/if_ether.h> +#include <linux/ip.h> +#include "cfg80211.h" +#include "wlan_cfg.h" + +static inline bool is_wilc1000(u32 id) +{ + return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID; +} + +static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire) +{ + mutex_lock(&wilc->hif_cs); + if (acquire == WILC_BUS_ACQUIRE_AND_WAKEUP) + chip_wakeup(wilc); +} + +static inline void release_bus(struct wilc *wilc, enum bus_release release) +{ + if (release == WILC_BUS_RELEASE_ALLOW_SLEEP) + chip_allow_sleep(wilc); + mutex_unlock(&wilc->hif_cs); +} + +static void wilc_wlan_txq_remove(struct wilc *wilc, struct txq_entry_t *tqe) +{ + list_del(&tqe->list); + wilc->txq_entries -= 1; +} + +static struct txq_entry_t * +wilc_wlan_txq_remove_from_head(struct net_device *dev) +{ + struct txq_entry_t *tqe = NULL; + unsigned long flags; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + if (!list_empty(&wilc->txq_head.list)) { + tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t, + list); + list_del(&tqe->list); + wilc->txq_entries -= 1; + } + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + return tqe; +} + +static void wilc_wlan_txq_add_to_tail(struct net_device *dev, + struct txq_entry_t *tqe) +{ + unsigned long flags; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + list_add_tail(&tqe->list, &wilc->txq_head.list); + wilc->txq_entries += 1; + + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + + complete(&wilc->txq_event); +} + +static void wilc_wlan_txq_add_to_head(struct wilc_vif *vif, + struct txq_entry_t *tqe) +{ + unsigned long flags; + struct wilc *wilc = vif->wilc; + + mutex_lock(&wilc->txq_add_to_head_cs); + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + list_add(&tqe->list, &wilc->txq_head.list); + wilc->txq_entries += 1; + + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + mutex_unlock(&wilc->txq_add_to_head_cs); + complete(&wilc->txq_event); +} + +#define NOT_TCP_ACK (-1) + +static inline void add_tcp_session(struct wilc_vif *vif, u32 src_prt, + u32 dst_prt, u32 seq) +{ + struct tcp_ack_filter *f = &vif->ack_filter; + + if (f->tcp_session < 2 * MAX_TCP_SESSION) { + f->ack_session_info[f->tcp_session].seq_num = seq; + f->ack_session_info[f->tcp_session].bigger_ack_num = 0; + f->ack_session_info[f->tcp_session].src_port = src_prt; + f->ack_session_info[f->tcp_session].dst_port = dst_prt; + f->tcp_session++; + } +} + +static inline void update_tcp_session(struct wilc_vif *vif, u32 index, u32 ack) +{ + struct tcp_ack_filter *f = &vif->ack_filter; + + if (index < 2 * MAX_TCP_SESSION && + ack > f->ack_session_info[index].bigger_ack_num) + f->ack_session_info[index].bigger_ack_num = ack; +} + +static inline void add_tcp_pending_ack(struct wilc_vif *vif, u32 ack, + u32 session_index, + struct txq_entry_t *txqe) +{ + struct tcp_ack_filter *f = &vif->ack_filter; + u32 i = f->pending_base + f->pending_acks_idx; + + if (i < MAX_PENDING_ACKS) { + f->pending_acks[i].ack_num = ack; + f->pending_acks[i].txqe = txqe; + f->pending_acks[i].session_index = session_index; + txqe->ack_idx = i; + f->pending_acks_idx++; + } +} + +static inline void tcp_process(struct net_device *dev, struct txq_entry_t *tqe) +{ + void *buffer = tqe->buffer; + const struct ethhdr *eth_hdr_ptr = buffer; + int i; + unsigned long flags; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + struct tcp_ack_filter *f = &vif->ack_filter; + const struct iphdr *ip_hdr_ptr; + const struct tcphdr *tcp_hdr_ptr; + u32 ihl, total_length, data_offset; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + if (eth_hdr_ptr->h_proto != htons(ETH_P_IP)) + goto out; + + ip_hdr_ptr = buffer + ETH_HLEN; + + if (ip_hdr_ptr->protocol != IPPROTO_TCP) + goto out; + + ihl = ip_hdr_ptr->ihl << 2; + tcp_hdr_ptr = buffer + ETH_HLEN + ihl; + total_length = ntohs(ip_hdr_ptr->tot_len); + + data_offset = tcp_hdr_ptr->doff << 2; + if (total_length == (ihl + data_offset)) { + u32 seq_no, ack_no; + + seq_no = ntohl(tcp_hdr_ptr->seq); + ack_no = ntohl(tcp_hdr_ptr->ack_seq); + for (i = 0; i < f->tcp_session; i++) { + u32 j = f->ack_session_info[i].seq_num; + + if (i < 2 * MAX_TCP_SESSION && + j == seq_no) { + update_tcp_session(vif, i, ack_no); + break; + } + } + if (i == f->tcp_session) + add_tcp_session(vif, 0, 0, seq_no); + + add_tcp_pending_ack(vif, ack_no, i, tqe); + } + +out: + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); +} + +static void wilc_wlan_txq_filter_dup_tcp_ack(struct net_device *dev) +{ + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + struct tcp_ack_filter *f = &vif->ack_filter; + u32 i = 0; + u32 dropped = 0; + unsigned long flags; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + for (i = f->pending_base; + i < (f->pending_base + f->pending_acks_idx); i++) { + u32 index; + u32 bigger_ack_num; + + if (i >= MAX_PENDING_ACKS) + break; + + index = f->pending_acks[i].session_index; + + if (index >= 2 * MAX_TCP_SESSION) + break; + + bigger_ack_num = f->ack_session_info[index].bigger_ack_num; + + if (f->pending_acks[i].ack_num < bigger_ack_num) { + struct txq_entry_t *tqe; + + tqe = f->pending_acks[i].txqe; + if (tqe) { + wilc_wlan_txq_remove(wilc, tqe); + tqe->status = 1; + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, + tqe->status); + kfree(tqe); + dropped++; + } + } + } + f->pending_acks_idx = 0; + f->tcp_session = 0; + + if (f->pending_base == 0) + f->pending_base = MAX_TCP_SESSION; + else + f->pending_base = 0; + + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + + while (dropped > 0) { + wait_for_completion_timeout(&wilc->txq_event, + msecs_to_jiffies(1)); + dropped--; + } +} + +void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value) +{ + vif->ack_filter.enabled = value; +} + +static int wilc_wlan_txq_add_cfg_pkt(struct wilc_vif *vif, u8 *buffer, + u32 buffer_size) +{ + struct txq_entry_t *tqe; + struct wilc *wilc = vif->wilc; + + netdev_dbg(vif->ndev, "Adding config packet ...\n"); + if (wilc->quit) { + netdev_dbg(vif->ndev, "Return due to clear function\n"); + complete(&wilc->cfg_event); + return 0; + } + + tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); + if (!tqe) + return 0; + + tqe->type = WILC_CFG_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = NULL; + tqe->priv = NULL; + tqe->ack_idx = NOT_TCP_ACK; + tqe->vif = vif; + + wilc_wlan_txq_add_to_head(vif, tqe); + + return 1; +} + +int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, + u32 buffer_size, + void (*tx_complete_fn)(void *, int)) +{ + struct txq_entry_t *tqe; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc; + + wilc = vif->wilc; + + if (wilc->quit) + return 0; + + tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); + + if (!tqe) + return 0; + tqe->type = WILC_NET_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = tx_complete_fn; + tqe->priv = priv; + tqe->vif = vif; + + tqe->ack_idx = NOT_TCP_ACK; + if (vif->ack_filter.enabled) + tcp_process(dev, tqe); + wilc_wlan_txq_add_to_tail(dev, tqe); + return wilc->txq_entries; +} + +int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, + u32 buffer_size, + void (*tx_complete_fn)(void *, int)) +{ + struct txq_entry_t *tqe; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc; + + wilc = vif->wilc; + + if (wilc->quit) + return 0; + + tqe = kmalloc(sizeof(*tqe), GFP_ATOMIC); + + if (!tqe) + return 0; + tqe->type = WILC_MGMT_PKT; + tqe->buffer = buffer; + tqe->buffer_size = buffer_size; + tqe->tx_complete_func = tx_complete_fn; + tqe->priv = priv; + tqe->ack_idx = NOT_TCP_ACK; + tqe->vif = vif; + wilc_wlan_txq_add_to_tail(dev, tqe); + return 1; +} + +static struct txq_entry_t *wilc_wlan_txq_get_first(struct wilc *wilc) +{ + struct txq_entry_t *tqe = NULL; + unsigned long flags; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + if (!list_empty(&wilc->txq_head.list)) + tqe = list_first_entry(&wilc->txq_head.list, struct txq_entry_t, + list); + + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + + return tqe; +} + +static struct txq_entry_t *wilc_wlan_txq_get_next(struct wilc *wilc, + struct txq_entry_t *tqe) +{ + unsigned long flags; + + spin_lock_irqsave(&wilc->txq_spinlock, flags); + + if (!list_is_last(&tqe->list, &wilc->txq_head.list)) + tqe = list_next_entry(tqe, list); + else + tqe = NULL; + spin_unlock_irqrestore(&wilc->txq_spinlock, flags); + + return tqe; +} + +static void wilc_wlan_rxq_add(struct wilc *wilc, struct rxq_entry_t *rqe) +{ + if (wilc->quit) + return; + + mutex_lock(&wilc->rxq_cs); + list_add_tail(&rqe->list, &wilc->rxq_head.list); + mutex_unlock(&wilc->rxq_cs); +} + +static struct rxq_entry_t *wilc_wlan_rxq_remove(struct wilc *wilc) +{ + struct rxq_entry_t *rqe = NULL; + + mutex_lock(&wilc->rxq_cs); + if (!list_empty(&wilc->rxq_head.list)) { + rqe = list_first_entry(&wilc->rxq_head.list, struct rxq_entry_t, + list); + list_del(&rqe->list); + } + mutex_unlock(&wilc->rxq_cs); + return rqe; +} + +void chip_allow_sleep(struct wilc *wilc) +{ + u32 reg = 0; + + wilc->hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); + + wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, + reg & ~WILC_SDIO_WAKEUP_BIT); + wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG, 0); +} +EXPORT_SYMBOL_GPL(chip_allow_sleep); + +void chip_wakeup(struct wilc *wilc) +{ + u32 reg, clk_status_reg; + const struct wilc_hif_func *h = wilc->hif_func; + + if (wilc->io_type == WILC_HIF_SPI) { + do { + h->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, ®); + h->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, + reg | WILC_SPI_WAKEUP_BIT); + h->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG, + reg & ~WILC_SPI_WAKEUP_BIT); + + do { + usleep_range(2000, 2500); + wilc_get_chipid(wilc, true); + } while (wilc_get_chipid(wilc, true) == 0); + } while (wilc_get_chipid(wilc, true) == 0); + } else if (wilc->io_type == WILC_HIF_SDIO) { + h->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG, + WILC_SDIO_HOST_TO_FW_BIT); + usleep_range(200, 400); + h->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, ®); + do { + h->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, + reg | WILC_SDIO_WAKEUP_BIT); + h->hif_read_reg(wilc, WILC_SDIO_CLK_STATUS_REG, + &clk_status_reg); + + while (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)) { + usleep_range(2000, 2500); + + h->hif_read_reg(wilc, WILC_SDIO_CLK_STATUS_REG, + &clk_status_reg); + } + if (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)) { + h->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG, + reg & ~WILC_SDIO_WAKEUP_BIT); + } + } while (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)); + } + + if (wilc->chip_ps_state == WILC_CHIP_SLEEPING_MANUAL) { + if (wilc_get_chipid(wilc, false) < WILC_1000_BASE_ID_2B) { + u32 val32; + + h->hif_read_reg(wilc, WILC_REG_4_TO_1_RX, &val32); + val32 |= BIT(6); + h->hif_write_reg(wilc, WILC_REG_4_TO_1_RX, val32); + + h->hif_read_reg(wilc, WILC_REG_4_TO_1_TX_BANK0, &val32); + val32 |= BIT(6); + h->hif_write_reg(wilc, WILC_REG_4_TO_1_TX_BANK0, val32); + } + } + wilc->chip_ps_state = WILC_CHIP_WAKEDUP; +} +EXPORT_SYMBOL_GPL(chip_wakeup); + +void host_wakeup_notify(struct wilc *wilc) +{ + acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1); + release_bus(wilc, WILC_BUS_RELEASE_ONLY); +} +EXPORT_SYMBOL_GPL(host_wakeup_notify); + +void host_sleep_notify(struct wilc *wilc) +{ + acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1); + release_bus(wilc, WILC_BUS_RELEASE_ONLY); +} +EXPORT_SYMBOL_GPL(host_sleep_notify); + +int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count) +{ + int i, entries = 0; + u32 sum; + u32 reg; + u32 offset = 0; + int vmm_sz = 0; + struct txq_entry_t *tqe; + int ret = 0; + int counter; + int timeout; + u32 vmm_table[WILC_VMM_TBL_SIZE]; + const struct wilc_hif_func *func; + u8 *txb = wilc->tx_buffer; + struct net_device *dev; + struct wilc_vif *vif; + + if (wilc->quit) + goto out_update_cnt; + + mutex_lock(&wilc->txq_add_to_head_cs); + tqe = wilc_wlan_txq_get_first(wilc); + if (!tqe) + goto out_unlock; + dev = tqe->vif->ndev; + wilc_wlan_txq_filter_dup_tcp_ack(dev); + i = 0; + sum = 0; + while (tqe && (i < (WILC_VMM_TBL_SIZE - 1))) { + if (tqe->type == WILC_CFG_PKT) + vmm_sz = ETH_CONFIG_PKT_HDR_OFFSET; + else if (tqe->type == WILC_NET_PKT) + vmm_sz = ETH_ETHERNET_HDR_OFFSET; + else + vmm_sz = HOST_HDR_OFFSET; + + vmm_sz += tqe->buffer_size; + vmm_sz = ALIGN(vmm_sz, 4); + + if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE) + break; + + vmm_table[i] = vmm_sz / 4; + if (tqe->type == WILC_CFG_PKT) + vmm_table[i] |= BIT(10); + cpu_to_le32s(&vmm_table[i]); + + i++; + sum += vmm_sz; + tqe = wilc_wlan_txq_get_next(wilc, tqe); + } + + if (i == 0) + goto out_unlock; + vmm_table[i] = 0x0; + + acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + counter = 0; + func = wilc->hif_func; + do { + ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); + if (ret) + break; + + if ((reg & 0x1) == 0) + break; + + counter++; + if (counter > 200) { + counter = 0; + ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, 0); + break; + } + } while (!wilc->quit); + + if (ret) + goto out_release_bus; + + timeout = 200; + do { + ret = func->hif_block_tx(wilc, + WILC_VMM_TBL_RX_SHADOW_BASE, + (u8 *)vmm_table, + ((i + 1) * 4)); + if (ret) + break; + + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x2); + if (ret) + break; + + do { + ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, ®); + if (ret) + break; + if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) { + entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg); + break; + } + } while (--timeout); + if (timeout <= 0) { + ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0); + break; + } + + if (ret) + break; + + if (entries == 0) { + ret = func->hif_read_reg(wilc, WILC_HOST_TX_CTRL, ®); + if (ret) + break; + reg &= ~BIT(0); + ret = func->hif_write_reg(wilc, WILC_HOST_TX_CTRL, reg); + } + } while (0); + + if (ret) + goto out_release_bus; + + if (entries == 0) { + /* + * No VMM space available in firmware so retry to transmit + * the packet from tx queue. + */ + ret = WILC_VMM_ENTRY_FULL_RETRY; + goto out_release_bus; + } + + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + + offset = 0; + i = 0; + do { + u32 header, buffer_offset; + char *bssid; + u8 mgmt_ptk = 0; + + tqe = wilc_wlan_txq_remove_from_head(dev); + if (!tqe) + break; + + vif = tqe->vif; + if (vmm_table[i] == 0) + break; + + le32_to_cpus(&vmm_table[i]); + vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]); + vmm_sz *= 4; + + if (tqe->type == WILC_MGMT_PKT) + mgmt_ptk = 1; + + header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tqe->type) | + FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) | + FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->buffer_size) | + FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz)); + + cpu_to_le32s(&header); + memcpy(&txb[offset], &header, 4); + if (tqe->type == WILC_CFG_PKT) { + buffer_offset = ETH_CONFIG_PKT_HDR_OFFSET; + } else if (tqe->type == WILC_NET_PKT) { + bssid = tqe->vif->bssid; + buffer_offset = ETH_ETHERNET_HDR_OFFSET; + memcpy(&txb[offset + 8], bssid, 6); + } else { + buffer_offset = HOST_HDR_OFFSET; + } + + memcpy(&txb[offset + buffer_offset], + tqe->buffer, tqe->buffer_size); + offset += vmm_sz; + i++; + tqe->status = 1; + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, tqe->status); + if (tqe->ack_idx != NOT_TCP_ACK && + tqe->ack_idx < MAX_PENDING_ACKS) + vif->ack_filter.pending_acks[tqe->ack_idx].txqe = NULL; + kfree(tqe); + } while (--entries); + + acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + ret = func->hif_clear_int_ext(wilc, ENABLE_TX_VMM); + if (ret) + goto out_release_bus; + + ret = func->hif_block_tx_ext(wilc, 0, txb, offset); + +out_release_bus: + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + +out_unlock: + mutex_unlock(&wilc->txq_add_to_head_cs); + +out_update_cnt: + *txq_count = wilc->txq_entries; + return ret; +} + +static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size) +{ + int offset = 0; + u32 header; + u32 pkt_len, pkt_offset, tp_len; + int is_cfg_packet; + u8 *buff_ptr; + + do { + buff_ptr = buffer + offset; + header = get_unaligned_le32(buff_ptr); + + is_cfg_packet = FIELD_GET(WILC_PKT_HDR_CONFIG_FIELD, header); + pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header); + tp_len = FIELD_GET(WILC_PKT_HDR_TOTAL_LEN_FIELD, header); + pkt_len = FIELD_GET(WILC_PKT_HDR_LEN_FIELD, header); + + if (pkt_len == 0 || tp_len == 0) + break; + + if (pkt_offset & IS_MANAGMEMENT) { + buff_ptr += HOST_HDR_OFFSET; + wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len); + } else { + if (!is_cfg_packet) { + wilc_frmw_to_host(wilc, buff_ptr, pkt_len, + pkt_offset); + } else { + struct wilc_cfg_rsp rsp; + + buff_ptr += pkt_offset; + + wilc_wlan_cfg_indicate_rx(wilc, buff_ptr, + pkt_len, + &rsp); + if (rsp.type == WILC_CFG_RSP) { + if (wilc->cfg_seq_no == rsp.seq_no) + complete(&wilc->cfg_event); + } else if (rsp.type == WILC_CFG_RSP_STATUS) { + wilc_mac_indicate(wilc); + } + } + } + offset += tp_len; + } while (offset < size); +} + +static void wilc_wlan_handle_rxq(struct wilc *wilc) +{ + int size; + u8 *buffer; + struct rxq_entry_t *rqe; + + while (!wilc->quit) { + rqe = wilc_wlan_rxq_remove(wilc); + if (!rqe) + break; + + buffer = rqe->buffer; + size = rqe->buffer_size; + wilc_wlan_handle_rx_buff(wilc, buffer, size); + + kfree(rqe); + } + if (wilc->quit) + complete(&wilc->cfg_event); +} + +static void wilc_unknown_isr_ext(struct wilc *wilc) +{ + wilc->hif_func->hif_clear_int_ext(wilc, 0); +} + +static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) +{ + u32 offset = wilc->rx_buffer_offset; + u8 *buffer = NULL; + u32 size; + u32 retries = 0; + int ret = 0; + struct rxq_entry_t *rqe; + + size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, int_status) << 2; + + while (!size && retries < 10) { + wilc->hif_func->hif_read_size(wilc, &size); + size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, size) << 2; + retries++; + } + + if (size <= 0) + return; + + if (WILC_RX_BUFF_SIZE - offset < size) + offset = 0; + + buffer = &wilc->rx_buffer[offset]; + + wilc->hif_func->hif_clear_int_ext(wilc, DATA_INT_CLR | ENABLE_RX_VMM); + ret = wilc->hif_func->hif_block_rx_ext(wilc, 0, buffer, size); + if (ret) + return; + + offset += size; + wilc->rx_buffer_offset = offset; + rqe = kmalloc(sizeof(*rqe), GFP_KERNEL); + if (!rqe) + return; + + rqe->buffer = buffer; + rqe->buffer_size = size; + wilc_wlan_rxq_add(wilc, rqe); + wilc_wlan_handle_rxq(wilc); +} + +void wilc_handle_isr(struct wilc *wilc) +{ + u32 int_status; + + acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + wilc->hif_func->hif_read_int(wilc, &int_status); + + if (int_status & DATA_INT_EXT) + wilc_wlan_handle_isr_ext(wilc, int_status); + + if (!(int_status & (ALL_INT_EXT))) + wilc_unknown_isr_ext(wilc); + + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); +} +EXPORT_SYMBOL_GPL(wilc_handle_isr); + +int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, + u32 buffer_size) +{ + u32 offset; + u32 addr, size, size2, blksz; + u8 *dma_buffer; + int ret = 0; + + blksz = BIT(12); + + dma_buffer = kmalloc(blksz, GFP_KERNEL); + if (!dma_buffer) + return -EIO; + + offset = 0; + do { + addr = get_unaligned_le32(&buffer[offset]); + size = get_unaligned_le32(&buffer[offset + 4]); + acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + offset += 8; + while (((int)size) && (offset < buffer_size)) { + if (size <= blksz) + size2 = size; + else + size2 = blksz; + + memcpy(dma_buffer, &buffer[offset], size2); + ret = wilc->hif_func->hif_block_tx(wilc, addr, + dma_buffer, size2); + if (ret) + break; + + addr += size2; + offset += size2; + size -= size2; + } + release_bus(wilc, WILC_BUS_RELEASE_ONLY); + + if (ret) + goto fail; + } while (offset < buffer_size); + +fail: + + kfree(dma_buffer); + + return ret; +} + +int wilc_wlan_start(struct wilc *wilc) +{ + u32 reg = 0; + int ret; + u32 chipid; + + if (wilc->io_type == WILC_HIF_SDIO) { + reg = 0; + reg |= BIT(3); + } else if (wilc->io_type == WILC_HIF_SPI) { + reg = 1; + } + acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + ret = wilc->hif_func->hif_write_reg(wilc, WILC_VMM_CORE_CFG, reg); + if (ret) { + release_bus(wilc, WILC_BUS_RELEASE_ONLY); + return ret; + } + reg = 0; + if (wilc->io_type == WILC_HIF_SDIO && wilc->dev_irq_num) + reg |= WILC_HAVE_SDIO_IRQ_GPIO; + + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_1, reg); + if (ret) { + release_bus(wilc, WILC_BUS_RELEASE_ONLY); + return ret; + } + + wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT); + + ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid); + if (ret) { + release_bus(wilc, WILC_BUS_RELEASE_ONLY); + return ret; + } + + wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); + if ((reg & BIT(10)) == BIT(10)) { + reg &= ~BIT(10); + wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); + wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); + } + + reg |= BIT(10); + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GLB_RESET_0, reg); + wilc->hif_func->hif_read_reg(wilc, WILC_GLB_RESET_0, ®); + release_bus(wilc, WILC_BUS_RELEASE_ONLY); + + return ret; +} + +int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) +{ + u32 reg = 0; + int ret; + + acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); + + ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); + if (ret) { + netdev_err(vif->ndev, "Error while reading reg\n"); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret; + } + + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, + (reg | WILC_ABORT_REQ_BIT)); + if (ret) { + netdev_err(vif->ndev, "Error while writing reg\n"); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret; + } + + ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); + if (ret) { + netdev_err(vif->ndev, "Error while reading reg\n"); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret; + } + reg = BIT(0); + + ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); + if (ret) { + netdev_err(vif->ndev, "Error while writing reg\n"); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + return ret; + } + + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); + + return 0; +} + +void wilc_wlan_cleanup(struct net_device *dev) +{ + struct txq_entry_t *tqe; + struct rxq_entry_t *rqe; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + wilc->quit = 1; + while ((tqe = wilc_wlan_txq_remove_from_head(dev))) { + if (tqe->tx_complete_func) + tqe->tx_complete_func(tqe->priv, 0); + kfree(tqe); + } + + while ((rqe = wilc_wlan_rxq_remove(wilc))) + kfree(rqe); + + kfree(wilc->rx_buffer); + wilc->rx_buffer = NULL; + kfree(wilc->tx_buffer); + wilc->tx_buffer = NULL; + wilc->hif_func->hif_deinit(NULL); +} + +static int wilc_wlan_cfg_commit(struct wilc_vif *vif, int type, + u32 drv_handler) +{ + struct wilc *wilc = vif->wilc; + struct wilc_cfg_frame *cfg = &wilc->cfg_frame; + int t_len = wilc->cfg_frame_offset + sizeof(struct wilc_cfg_cmd_hdr); + + if (type == WILC_CFG_SET) + cfg->hdr.cmd_type = 'W'; + else + cfg->hdr.cmd_type = 'Q'; + + cfg->hdr.seq_no = wilc->cfg_seq_no % 256; + cfg->hdr.total_len = cpu_to_le16(t_len); + cfg->hdr.driver_handler = cpu_to_le32(drv_handler); + wilc->cfg_seq_no = cfg->hdr.seq_no; + + if (!wilc_wlan_txq_add_cfg_pkt(vif, (u8 *)&cfg->hdr, t_len)) + return -1; + + return 0; +} + +int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, + u32 buffer_size, int commit, u32 drv_handler) +{ + u32 offset; + int ret_size; + struct wilc *wilc = vif->wilc; + + mutex_lock(&wilc->cfg_cmd_lock); + + if (start) + wilc->cfg_frame_offset = 0; + + offset = wilc->cfg_frame_offset; + ret_size = wilc_wlan_cfg_set_wid(wilc->cfg_frame.frame, offset, + wid, buffer, buffer_size); + offset += ret_size; + wilc->cfg_frame_offset = offset; + + if (!commit) { + mutex_unlock(&wilc->cfg_cmd_lock); + return ret_size; + } + + netdev_dbg(vif->ndev, "%s: seqno[%d]\n", __func__, wilc->cfg_seq_no); + + if (wilc_wlan_cfg_commit(vif, WILC_CFG_SET, drv_handler)) + ret_size = 0; + + if (!wait_for_completion_timeout(&wilc->cfg_event, + WILC_CFG_PKTS_TIMEOUT)) { + netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__); + ret_size = 0; + } + + wilc->cfg_frame_offset = 0; + wilc->cfg_seq_no += 1; + mutex_unlock(&wilc->cfg_cmd_lock); + + return ret_size; +} + +int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, + u32 drv_handler) +{ + u32 offset; + int ret_size; + struct wilc *wilc = vif->wilc; + + mutex_lock(&wilc->cfg_cmd_lock); + + if (start) + wilc->cfg_frame_offset = 0; + + offset = wilc->cfg_frame_offset; + ret_size = wilc_wlan_cfg_get_wid(wilc->cfg_frame.frame, offset, wid); + offset += ret_size; + wilc->cfg_frame_offset = offset; + + if (!commit) { + mutex_unlock(&wilc->cfg_cmd_lock); + return ret_size; + } + + if (wilc_wlan_cfg_commit(vif, WILC_CFG_QUERY, drv_handler)) + ret_size = 0; + + if (!wait_for_completion_timeout(&wilc->cfg_event, + WILC_CFG_PKTS_TIMEOUT)) { + netdev_dbg(vif->ndev, "%s: Timed Out\n", __func__); + ret_size = 0; + } + wilc->cfg_frame_offset = 0; + wilc->cfg_seq_no += 1; + mutex_unlock(&wilc->cfg_cmd_lock); + + return ret_size; +} + +int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, + u32 count) +{ + int i; + int ret = 0; + u32 drv = wilc_get_vif_idx(vif); + + if (mode == WILC_GET_CFG) { + for (i = 0; i < count; i++) { + if (!wilc_wlan_cfg_get(vif, !i, + wids[i].id, + (i == count - 1), + drv)) { + ret = -ETIMEDOUT; + break; + } + } + for (i = 0; i < count; i++) { + wids[i].size = wilc_wlan_cfg_get_val(vif->wilc, + wids[i].id, + wids[i].val, + wids[i].size); + } + } else if (mode == WILC_SET_CFG) { + for (i = 0; i < count; i++) { + if (!wilc_wlan_cfg_set(vif, !i, + wids[i].id, + wids[i].val, + wids[i].size, + (i == count - 1), + drv)) { + ret = -ETIMEDOUT; + break; + } + } + } + + return ret; +} + +static int init_chip(struct net_device *dev) +{ + u32 chipid; + u32 reg; + int ret = 0; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc = vif->wilc; + + acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + + chipid = wilc_get_chipid(wilc, true); + + if ((chipid & 0xfff) != 0xa0) { + ret = wilc->hif_func->hif_read_reg(wilc, + WILC_CORTUS_RESET_MUX_SEL, + ®); + if (ret) { + netdev_err(dev, "fail read reg 0x1118\n"); + goto release; + } + reg |= BIT(0); + ret = wilc->hif_func->hif_write_reg(wilc, + WILC_CORTUS_RESET_MUX_SEL, + reg); + if (ret) { + netdev_err(dev, "fail write reg 0x1118\n"); + goto release; + } + ret = wilc->hif_func->hif_write_reg(wilc, + WILC_CORTUS_BOOT_REGISTER, + WILC_CORTUS_BOOT_FROM_IRAM); + if (ret) { + netdev_err(dev, "fail write reg 0xc0000\n"); + goto release; + } + } + +release: + release_bus(wilc, WILC_BUS_RELEASE_ONLY); + + return ret; +} + +u32 wilc_get_chipid(struct wilc *wilc, bool update) +{ + static u32 chipid; + u32 tempchipid = 0; + u32 rfrevid = 0; + + if (chipid == 0 || update) { + wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &tempchipid); + wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID, + &rfrevid); + if (!is_wilc1000(tempchipid)) { + chipid = 0; + return chipid; + } + if (tempchipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */ + if (rfrevid != 0x1) + tempchipid = WILC_1000_BASE_ID_2A_REV1; + } else if (tempchipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */ + if (rfrevid == 0x4) + tempchipid = WILC_1000_BASE_ID_2B_REV1; + else if (rfrevid != 0x3) + tempchipid = WILC_1000_BASE_ID_2B_REV2; + } + + chipid = tempchipid; + } + return chipid; +} + +int wilc_wlan_init(struct net_device *dev) +{ + int ret = 0; + struct wilc_vif *vif = netdev_priv(dev); + struct wilc *wilc; + + wilc = vif->wilc; + + wilc->quit = 0; + + if (wilc->hif_func->hif_init(wilc, false)) { + ret = -EIO; + goto fail; + } + + if (!wilc->tx_buffer) + wilc->tx_buffer = kmalloc(WILC_TX_BUFF_SIZE, GFP_KERNEL); + + if (!wilc->tx_buffer) { + ret = -ENOBUFS; + goto fail; + } + + if (!wilc->rx_buffer) + wilc->rx_buffer = kmalloc(WILC_RX_BUFF_SIZE, GFP_KERNEL); + + if (!wilc->rx_buffer) { + ret = -ENOBUFS; + goto fail; + } + + if (init_chip(dev)) { + ret = -EIO; + goto fail; + } + + return 0; + +fail: + + kfree(wilc->rx_buffer); + wilc->rx_buffer = NULL; + kfree(wilc->tx_buffer); + wilc->tx_buffer = NULL; + + return ret; +} diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h new file mode 100644 index 000000000000..7689569cd82f --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -0,0 +1,397 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef WILC_WLAN_H +#define WILC_WLAN_H + +#include <linux/types.h> +#include <linux/bitfield.h> + +/******************************************** + * + * Mac eth header length + * + ********************************************/ +#define MAX_MAC_HDR_LEN 26 /* QOS_MAC_HDR_LEN */ +#define SUB_MSDU_HEADER_LENGTH 14 +#define SNAP_HDR_LEN 8 +#define ETHERNET_HDR_LEN 14 +#define WORD_ALIGNMENT_PAD 0 + +#define ETH_ETHERNET_HDR_OFFSET (MAX_MAC_HDR_LEN + \ + SUB_MSDU_HEADER_LENGTH + \ + SNAP_HDR_LEN - \ + ETHERNET_HDR_LEN + \ + WORD_ALIGNMENT_PAD) + +#define HOST_HDR_OFFSET 4 +#define ETHERNET_HDR_LEN 14 +#define IP_HDR_LEN 20 +#define IP_HDR_OFFSET ETHERNET_HDR_LEN +#define UDP_HDR_OFFSET (IP_HDR_LEN + IP_HDR_OFFSET) +#define UDP_HDR_LEN 8 +#define UDP_DATA_OFFSET (UDP_HDR_OFFSET + UDP_HDR_LEN) +#define ETH_CONFIG_PKT_HDR_LEN UDP_DATA_OFFSET + +#define ETH_CONFIG_PKT_HDR_OFFSET (ETH_ETHERNET_HDR_OFFSET + \ + ETH_CONFIG_PKT_HDR_LEN) + +/******************************************** + * + * Register Defines + * + ********************************************/ +#define WILC_PERIPH_REG_BASE 0x1000 +#define WILC_CHANGING_VIR_IF 0x108c +#define WILC_CHIPID WILC_PERIPH_REG_BASE +#define WILC_GLB_RESET_0 (WILC_PERIPH_REG_BASE + 0x400) +#define WILC_PIN_MUX_0 (WILC_PERIPH_REG_BASE + 0x408) +#define WILC_HOST_TX_CTRL (WILC_PERIPH_REG_BASE + 0x6c) +#define WILC_HOST_RX_CTRL_0 (WILC_PERIPH_REG_BASE + 0x70) +#define WILC_HOST_RX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x74) +#define WILC_HOST_VMM_CTL (WILC_PERIPH_REG_BASE + 0x78) +#define WILC_HOST_RX_CTRL (WILC_PERIPH_REG_BASE + 0x80) +#define WILC_HOST_RX_EXTRA_SIZE (WILC_PERIPH_REG_BASE + 0x84) +#define WILC_HOST_TX_CTRL_1 (WILC_PERIPH_REG_BASE + 0x88) +#define WILC_MISC (WILC_PERIPH_REG_BASE + 0x428) +#define WILC_INTR_REG_BASE (WILC_PERIPH_REG_BASE + 0xa00) +#define WILC_INTR_ENABLE WILC_INTR_REG_BASE +#define WILC_INTR2_ENABLE (WILC_INTR_REG_BASE + 4) + +#define WILC_INTR_POLARITY (WILC_INTR_REG_BASE + 0x10) +#define WILC_INTR_TYPE (WILC_INTR_REG_BASE + 0x20) +#define WILC_INTR_CLEAR (WILC_INTR_REG_BASE + 0x30) +#define WILC_INTR_STATUS (WILC_INTR_REG_BASE + 0x40) + +#define WILC_RF_REVISION_ID 0x13f4 + +#define WILC_VMM_TBL_SIZE 64 +#define WILC_VMM_TX_TBL_BASE 0x150400 +#define WILC_VMM_RX_TBL_BASE 0x150500 + +#define WILC_VMM_BASE 0x150000 +#define WILC_VMM_CORE_CTL WILC_VMM_BASE +#define WILC_VMM_TBL_CTL (WILC_VMM_BASE + 0x4) +#define WILC_VMM_TBL_ENTRY (WILC_VMM_BASE + 0x8) +#define WILC_VMM_TBL0_SIZE (WILC_VMM_BASE + 0xc) +#define WILC_VMM_TO_HOST_SIZE (WILC_VMM_BASE + 0x10) +#define WILC_VMM_CORE_CFG (WILC_VMM_BASE + 0x14) +#define WILC_VMM_TBL_ACTIVE (WILC_VMM_BASE + 040) +#define WILC_VMM_TBL_STATUS (WILC_VMM_BASE + 0x44) + +#define WILC_SPI_REG_BASE 0xe800 +#define WILC_SPI_CTL WILC_SPI_REG_BASE +#define WILC_SPI_MASTER_DMA_ADDR (WILC_SPI_REG_BASE + 0x4) +#define WILC_SPI_MASTER_DMA_COUNT (WILC_SPI_REG_BASE + 0x8) +#define WILC_SPI_SLAVE_DMA_ADDR (WILC_SPI_REG_BASE + 0xc) +#define WILC_SPI_SLAVE_DMA_COUNT (WILC_SPI_REG_BASE + 0x10) +#define WILC_SPI_TX_MODE (WILC_SPI_REG_BASE + 0x20) +#define WILC_SPI_PROTOCOL_CONFIG (WILC_SPI_REG_BASE + 0x24) +#define WILC_SPI_INTR_CTL (WILC_SPI_REG_BASE + 0x2c) +#define WILC_SPI_INT_STATUS (WILC_SPI_REG_BASE + 0x40) +#define WILC_SPI_INT_CLEAR (WILC_SPI_REG_BASE + 0x44) + +#define WILC_SPI_WAKEUP_REG 0x1 +#define WILC_SPI_WAKEUP_BIT BIT(1) + +#define WILC_SPI_PROTOCOL_OFFSET (WILC_SPI_PROTOCOL_CONFIG - \ + WILC_SPI_REG_BASE) + +#define WILC_SPI_CLOCKLESS_ADDR_LIMIT 0x30 + +/* Functions IO enables bits */ +#define WILC_SDIO_CCCR_IO_EN_FUNC1 BIT(1) + +/* Function/Interrupt enables bits */ +#define WILC_SDIO_CCCR_IEN_MASTER BIT(0) +#define WILC_SDIO_CCCR_IEN_FUNC1 BIT(1) + +/* Abort CCCR register bits */ +#define WILC_SDIO_CCCR_ABORT_RESET BIT(3) + +/* Vendor specific CCCR registers */ +#define WILC_SDIO_WAKEUP_REG 0xf0 +#define WILC_SDIO_WAKEUP_BIT BIT(0) + +#define WILC_SDIO_CLK_STATUS_REG 0xf1 +#define WILC_SDIO_CLK_STATUS_BIT BIT(0) + +#define WILC_SDIO_INTERRUPT_DATA_SZ_REG 0xf2 /* Read size (2 bytes) */ + +#define WILC_SDIO_VMM_TBL_CTRL_REG 0xf6 +#define WILC_SDIO_IRQ_FLAG_REG 0xf7 +#define WILC_SDIO_IRQ_CLEAR_FLAG_REG 0xf8 + +#define WILC_SDIO_HOST_TO_FW_REG 0xfa +#define WILC_SDIO_HOST_TO_FW_BIT BIT(0) + +#define WILC_SDIO_FW_TO_HOST_REG 0xfc +#define WILC_SDIO_FW_TO_HOST_BIT BIT(0) + +/* Function 1 specific FBR register */ +#define WILC_SDIO_FBR_CSA_REG 0x10C /* CSA pointer (3 bytes) */ +#define WILC_SDIO_FBR_DATA_REG 0x10F + +#define WILC_SDIO_F1_DATA_REG 0x0 +#define WILC_SDIO_EXT_IRQ_FLAG_REG 0x4 + +#define WILC_AHB_DATA_MEM_BASE 0x30000 +#define WILC_AHB_SHARE_MEM_BASE 0xd0000 + +#define WILC_VMM_TBL_RX_SHADOW_BASE WILC_AHB_SHARE_MEM_BASE +#define WILC_VMM_TBL_RX_SHADOW_SIZE 256 + +#define WILC_FW_HOST_COMM 0x13c0 +#define WILC_GP_REG_0 0x149c +#define WILC_GP_REG_1 0x14a0 + +#define WILC_HAVE_SDIO_IRQ_GPIO BIT(0) +#define WILC_HAVE_USE_PMU BIT(1) +#define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2) +#define WILC_HAVE_SLEEP_CLK_SRC_XO BIT(3) +#define WILC_HAVE_EXT_PA_INV_TX_RX BIT(4) +#define WILC_HAVE_LEGACY_RF_SETTINGS BIT(5) +#define WILC_HAVE_XTAL_24 BIT(6) +#define WILC_HAVE_DISABLE_WILC_UART BIT(7) +#define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8) + +#define WILC_CORTUS_INTERRUPT_BASE 0x10A8 +#define WILC_CORTUS_INTERRUPT_1 (WILC_CORTUS_INTERRUPT_BASE + 0x4) +#define WILC_CORTUS_INTERRUPT_2 (WILC_CORTUS_INTERRUPT_BASE + 0x8) + +/* tx control register 1 to 4 for RX */ +#define WILC_REG_4_TO_1_RX 0x1e1c + +/* tx control register 1 to 4 for TX Bank_0 */ +#define WILC_REG_4_TO_1_TX_BANK0 0x1e9c + +#define WILC_CORTUS_RESET_MUX_SEL 0x1118 +#define WILC_CORTUS_BOOT_REGISTER 0xc0000 + +#define WILC_CORTUS_BOOT_FROM_IRAM 0x71 + +#define WILC_1000_BASE_ID 0x100000 + +#define WILC_1000_BASE_ID_2A 0x1002A0 +#define WILC_1000_BASE_ID_2A_REV1 (WILC_1000_BASE_ID_2A + 1) + +#define WILC_1000_BASE_ID_2B 0x1002B0 +#define WILC_1000_BASE_ID_2B_REV1 (WILC_1000_BASE_ID_2B + 1) +#define WILC_1000_BASE_ID_2B_REV2 (WILC_1000_BASE_ID_2B + 2) + +#define WILC_CHIP_REV_FIELD GENMASK(11, 0) + +/******************************************** + * + * Wlan Defines + * + ********************************************/ +#define WILC_CFG_PKT 1 +#define WILC_NET_PKT 0 +#define WILC_MGMT_PKT 2 + +#define WILC_CFG_SET 1 +#define WILC_CFG_QUERY 0 + +#define WILC_CFG_RSP 1 +#define WILC_CFG_RSP_STATUS 2 +#define WILC_CFG_RSP_SCAN 3 + +#define WILC_ABORT_REQ_BIT BIT(31) + +#define WILC_RX_BUFF_SIZE (96 * 1024) +#define WILC_TX_BUFF_SIZE (64 * 1024) + +#define MODALIAS "WILC_SPI" + +#define WILC_PKT_HDR_CONFIG_FIELD BIT(31) +#define WILC_PKT_HDR_OFFSET_FIELD GENMASK(30, 22) +#define WILC_PKT_HDR_TOTAL_LEN_FIELD GENMASK(21, 11) +#define WILC_PKT_HDR_LEN_FIELD GENMASK(10, 0) + +#define WILC_INTERRUPT_DATA_SIZE GENMASK(14, 0) + +#define WILC_VMM_BUFFER_SIZE GENMASK(9, 0) + +#define WILC_VMM_HDR_TYPE BIT(31) +#define WILC_VMM_HDR_MGMT_FIELD BIT(30) +#define WILC_VMM_HDR_PKT_SIZE GENMASK(29, 15) +#define WILC_VMM_HDR_BUFF_SIZE GENMASK(14, 0) + +#define WILC_VMM_ENTRY_COUNT GENMASK(8, 3) +#define WILC_VMM_ENTRY_AVAILABLE BIT(2) +/*******************************************/ +/* E0 and later Interrupt flags. */ +/*******************************************/ +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Status word */ +/* 15:0 = DMA count in words. */ +/* 16: INT0 flag */ +/* 17: INT1 flag */ +/* 18: INT2 flag */ +/* 19: INT3 flag */ +/* 20: INT4 flag */ +/* 21: INT5 flag */ +/*******************************************/ +#define IRG_FLAGS_OFFSET 16 +#define IRQ_DMA_WD_CNT_MASK GENMASK(IRG_FLAGS_OFFSET - 1, 0) +#define INT_0 BIT(IRG_FLAGS_OFFSET) +#define INT_1 BIT(IRG_FLAGS_OFFSET + 1) +#define INT_2 BIT(IRG_FLAGS_OFFSET + 2) +#define INT_3 BIT(IRG_FLAGS_OFFSET + 3) +#define INT_4 BIT(IRG_FLAGS_OFFSET + 4) +#define INT_5 BIT(IRG_FLAGS_OFFSET + 5) +#define MAX_NUM_INT 5 +#define IRG_FLAGS_MASK GENMASK(IRG_FLAGS_OFFSET + MAX_NUM_INT, \ + IRG_FLAGS_OFFSET) + +/*******************************************/ +/* E0 and later Interrupt flags. */ +/* IRQ Clear word */ +/* 0: Clear INT0 */ +/* 1: Clear INT1 */ +/* 2: Clear INT2 */ +/* 3: Clear INT3 */ +/* 4: Clear INT4 */ +/* 5: Clear INT5 */ +/* 6: Select VMM table 1 */ +/* 7: Select VMM table 2 */ +/* 8: Enable VMM */ +/*******************************************/ +#define CLR_INT0 BIT(0) +#define CLR_INT1 BIT(1) +#define CLR_INT2 BIT(2) +#define CLR_INT3 BIT(3) +#define CLR_INT4 BIT(4) +#define CLR_INT5 BIT(5) +#define SEL_VMM_TBL0 BIT(6) +#define SEL_VMM_TBL1 BIT(7) +#define EN_VMM BIT(8) + +#define DATA_INT_EXT INT_0 +#define ALL_INT_EXT DATA_INT_EXT +#define NUM_INT_EXT 1 +#define UNHANDLED_IRQ_MASK GENMASK(MAX_NUM_INT - 1, NUM_INT_EXT) + +#define DATA_INT_CLR CLR_INT0 + +#define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM) +#define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM) +/* time for expiring the completion of cfg packets */ +#define WILC_CFG_PKTS_TIMEOUT msecs_to_jiffies(2000) + +#define IS_MANAGMEMENT 0x100 +#define IS_MANAGMEMENT_CALLBACK 0x080 +#define IS_MGMT_STATUS_SUCCES 0x040 + +#define WILC_WID_TYPE GENMASK(15, 12) +#define WILC_VMM_ENTRY_FULL_RETRY 1 +/******************************************** + * + * Tx/Rx Queue Structure + * + ********************************************/ + +struct txq_entry_t { + struct list_head list; + int type; + int ack_idx; + u8 *buffer; + int buffer_size; + void *priv; + int status; + struct wilc_vif *vif; + void (*tx_complete_func)(void *priv, int status); +}; + +struct rxq_entry_t { + struct list_head list; + u8 *buffer; + int buffer_size; +}; + +/******************************************** + * + * Host IF Structure + * + ********************************************/ +struct wilc; +struct wilc_hif_func { + int (*hif_init)(struct wilc *wilc, bool resume); + int (*hif_deinit)(struct wilc *wilc); + int (*hif_read_reg)(struct wilc *wilc, u32 addr, u32 *data); + int (*hif_write_reg)(struct wilc *wilc, u32 addr, u32 data); + int (*hif_block_rx)(struct wilc *wilc, u32 addr, u8 *buf, u32 size); + int (*hif_block_tx)(struct wilc *wilc, u32 addr, u8 *buf, u32 size); + int (*hif_read_int)(struct wilc *wilc, u32 *int_status); + int (*hif_clear_int_ext)(struct wilc *wilc, u32 val); + int (*hif_read_size)(struct wilc *wilc, u32 *size); + int (*hif_block_tx_ext)(struct wilc *wilc, u32 addr, u8 *buf, u32 size); + int (*hif_block_rx_ext)(struct wilc *wilc, u32 addr, u8 *buf, u32 size); + int (*hif_sync_ext)(struct wilc *wilc, int nint); + int (*enable_interrupt)(struct wilc *nic); + void (*disable_interrupt)(struct wilc *nic); +}; + +#define WILC_MAX_CFG_FRAME_SIZE 1468 + +struct tx_complete_data { + int size; + void *buff; + struct sk_buff *skb; +}; + +struct wilc_cfg_cmd_hdr { + u8 cmd_type; + u8 seq_no; + __le16 total_len; + __le32 driver_handler; +}; + +struct wilc_cfg_frame { + struct wilc_cfg_cmd_hdr hdr; + u8 frame[WILC_MAX_CFG_FRAME_SIZE]; +}; + +struct wilc_cfg_rsp { + u8 type; + u8 seq_no; +}; + +struct wilc; +struct wilc_vif; + +int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, + u32 buffer_size); +int wilc_wlan_start(struct wilc *wilc); +int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif); +int wilc_wlan_txq_add_net_pkt(struct net_device *dev, void *priv, u8 *buffer, + u32 buffer_size, + void (*tx_complete_fn)(void *, int)); +int wilc_wlan_handle_txq(struct wilc *wl, u32 *txq_count); +void wilc_handle_isr(struct wilc *wilc); +void wilc_wlan_cleanup(struct net_device *dev); +int wilc_wlan_cfg_set(struct wilc_vif *vif, int start, u16 wid, u8 *buffer, + u32 buffer_size, int commit, u32 drv_handler); +int wilc_wlan_cfg_get(struct wilc_vif *vif, int start, u16 wid, int commit, + u32 drv_handler); +int wilc_wlan_txq_add_mgmt_pkt(struct net_device *dev, void *priv, u8 *buffer, + u32 buffer_size, void (*func)(void *, int)); +void wilc_enable_tcp_ack_filter(struct wilc_vif *vif, bool value); +int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc); +netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev); + +void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size); +void host_wakeup_notify(struct wilc *wilc); +void host_sleep_notify(struct wilc *wilc); +void chip_allow_sleep(struct wilc *wilc); +void chip_wakeup(struct wilc *wilc); +int wilc_send_config_pkt(struct wilc_vif *vif, u8 mode, struct wid *wids, + u32 count); +int wilc_wlan_init(struct net_device *dev); +u32 wilc_get_chipid(struct wilc *wilc, bool update); +#endif diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c new file mode 100644 index 000000000000..fe2a7ed8e5cd --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c @@ -0,0 +1,413 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#include <linux/bitfield.h> +#include "wlan_if.h" +#include "wlan.h" +#include "wlan_cfg.h" +#include "netdev.h" + +enum cfg_cmd_type { + CFG_BYTE_CMD = 0, + CFG_HWORD_CMD = 1, + CFG_WORD_CMD = 2, + CFG_STR_CMD = 3, + CFG_BIN_CMD = 4 +}; + +static const struct wilc_cfg_byte g_cfg_byte[] = { + {WID_STATUS, 0}, + {WID_RSSI, 0}, + {WID_LINKSPEED, 0}, + {WID_NIL, 0} +}; + +static const struct wilc_cfg_hword g_cfg_hword[] = { + {WID_NIL, 0} +}; + +static const struct wilc_cfg_word g_cfg_word[] = { + {WID_FAILED_COUNT, 0}, + {WID_RECEIVED_FRAGMENT_COUNT, 0}, + {WID_SUCCESS_FRAME_COUNT, 0}, + {WID_GET_INACTIVE_TIME, 0}, + {WID_NIL, 0} + +}; + +static const struct wilc_cfg_str g_cfg_str[] = { + {WID_FIRMWARE_VERSION, NULL}, + {WID_MAC_ADDR, NULL}, + {WID_ASSOC_RES_INFO, NULL}, + {WID_NIL, NULL} +}; + +#define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R' +#define WILC_RESP_MSG_TYPE_STATUS_INFO 'I' +#define WILC_RESP_MSG_TYPE_NETWORK_INFO 'N' +#define WILC_RESP_MSG_TYPE_SCAN_COMPLETE 'S' + +/******************************************** + * + * Configuration Functions + * + ********************************************/ + +static int wilc_wlan_cfg_set_byte(u8 *frame, u32 offset, u16 id, u8 val8) +{ + if ((offset + 4) >= WILC_MAX_CFG_FRAME_SIZE) + return 0; + + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(1, &frame[offset + 2]); + frame[offset + 4] = val8; + return 5; +} + +static int wilc_wlan_cfg_set_hword(u8 *frame, u32 offset, u16 id, u16 val16) +{ + if ((offset + 5) >= WILC_MAX_CFG_FRAME_SIZE) + return 0; + + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(2, &frame[offset + 2]); + put_unaligned_le16(val16, &frame[offset + 4]); + + return 6; +} + +static int wilc_wlan_cfg_set_word(u8 *frame, u32 offset, u16 id, u32 val32) +{ + if ((offset + 7) >= WILC_MAX_CFG_FRAME_SIZE) + return 0; + + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(4, &frame[offset + 2]); + put_unaligned_le32(val32, &frame[offset + 4]); + + return 8; +} + +static int wilc_wlan_cfg_set_str(u8 *frame, u32 offset, u16 id, u8 *str, + u32 size) +{ + if ((offset + size + 4) >= WILC_MAX_CFG_FRAME_SIZE) + return 0; + + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(size, &frame[offset + 2]); + if (str && size != 0) + memcpy(&frame[offset + 4], str, size); + + return (size + 4); +} + +static int wilc_wlan_cfg_set_bin(u8 *frame, u32 offset, u16 id, u8 *b, u32 size) +{ + u32 i; + u8 checksum = 0; + + if ((offset + size + 5) >= WILC_MAX_CFG_FRAME_SIZE) + return 0; + + put_unaligned_le16(id, &frame[offset]); + put_unaligned_le16(size, &frame[offset + 2]); + + if ((b) && size != 0) { + memcpy(&frame[offset + 4], b, size); + for (i = 0; i < size; i++) + checksum += frame[offset + i + 4]; + } + + frame[offset + size + 4] = checksum; + + return (size + 5); +} + +/******************************************** + * + * Configuration Response Functions + * + ********************************************/ + +static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) +{ + u16 wid; + u32 len = 0, i = 0; + struct wilc_cfg *cfg = &wl->cfg; + + while (size > 0) { + i = 0; + wid = get_unaligned_le16(info); + + switch (FIELD_GET(WILC_WID_TYPE, wid)) { + case WID_CHAR: + while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid) + i++; + + if (cfg->b[i].id == wid) + cfg->b[i].val = info[4]; + + len = 3; + break; + + case WID_SHORT: + while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid) + i++; + + if (cfg->hw[i].id == wid) + cfg->hw[i].val = get_unaligned_le16(&info[4]); + + len = 4; + break; + + case WID_INT: + while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid) + i++; + + if (cfg->w[i].id == wid) + cfg->w[i].val = get_unaligned_le32(&info[4]); + + len = 6; + break; + + case WID_STR: + while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid) + i++; + + if (cfg->s[i].id == wid) + memcpy(cfg->s[i].str, &info[2], info[2] + 2); + + len = 2 + info[2]; + break; + + default: + break; + } + size -= (2 + len); + info += (2 + len); + } +} + +static void wilc_wlan_parse_info_frame(struct wilc *wl, u8 *info) +{ + u32 wid, len; + + wid = get_unaligned_le16(info); + + len = info[2]; + + if (len == 1 && wid == WID_STATUS) { + int i = 0; + + while (wl->cfg.b[i].id != WID_NIL && + wl->cfg.b[i].id != wid) + i++; + + if (wl->cfg.b[i].id == wid) + wl->cfg.b[i].val = info[3]; + } +} + +/******************************************** + * + * Configuration Exported Functions + * + ********************************************/ + +int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size) +{ + u8 type = FIELD_GET(WILC_WID_TYPE, id); + int ret = 0; + + switch (type) { + case CFG_BYTE_CMD: + if (size >= 1) + ret = wilc_wlan_cfg_set_byte(frame, offset, id, *buf); + break; + + case CFG_HWORD_CMD: + if (size >= 2) + ret = wilc_wlan_cfg_set_hword(frame, offset, id, + *((u16 *)buf)); + break; + + case CFG_WORD_CMD: + if (size >= 4) + ret = wilc_wlan_cfg_set_word(frame, offset, id, + *((u32 *)buf)); + break; + + case CFG_STR_CMD: + ret = wilc_wlan_cfg_set_str(frame, offset, id, buf, size); + break; + + case CFG_BIN_CMD: + ret = wilc_wlan_cfg_set_bin(frame, offset, id, buf, size); + break; + } + + return ret; +} + +int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id) +{ + if ((offset + 2) >= WILC_MAX_CFG_FRAME_SIZE) + return 0; + + put_unaligned_le16(id, &frame[offset]); + + return 2; +} + +int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, + u32 buffer_size) +{ + u8 type = FIELD_GET(WILC_WID_TYPE, wid); + int i, ret = 0; + struct wilc_cfg *cfg = &wl->cfg; + + i = 0; + if (type == CFG_BYTE_CMD) { + while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid) + i++; + + if (cfg->b[i].id == wid) { + memcpy(buffer, &cfg->b[i].val, 1); + ret = 1; + } + } else if (type == CFG_HWORD_CMD) { + while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid) + i++; + + if (cfg->hw[i].id == wid) { + memcpy(buffer, &cfg->hw[i].val, 2); + ret = 2; + } + } else if (type == CFG_WORD_CMD) { + while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid) + i++; + + if (cfg->w[i].id == wid) { + memcpy(buffer, &cfg->w[i].val, 4); + ret = 4; + } + } else if (type == CFG_STR_CMD) { + while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid) + i++; + + if (cfg->s[i].id == wid) { + u16 size = get_unaligned_le16(cfg->s[i].str); + + if (buffer_size >= size) { + memcpy(buffer, &cfg->s[i].str[2], size); + ret = size; + } + } + } + return ret; +} + +void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, + struct wilc_cfg_rsp *rsp) +{ + u8 msg_type; + u8 msg_id; + + msg_type = frame[0]; + msg_id = frame[1]; /* seq no */ + frame += 4; + size -= 4; + rsp->type = 0; + + switch (msg_type) { + case WILC_RESP_MSG_TYPE_CONFIG_REPLY: + wilc_wlan_parse_response_frame(wilc, frame, size); + rsp->type = WILC_CFG_RSP; + rsp->seq_no = msg_id; + break; + + case WILC_RESP_MSG_TYPE_STATUS_INFO: + wilc_wlan_parse_info_frame(wilc, frame); + rsp->type = WILC_CFG_RSP_STATUS; + rsp->seq_no = msg_id; + /* call host interface info parse as well */ + wilc_gnrl_async_info_received(wilc, frame - 4, size + 4); + break; + + case WILC_RESP_MSG_TYPE_NETWORK_INFO: + wilc_network_info_received(wilc, frame - 4, size + 4); + break; + + case WILC_RESP_MSG_TYPE_SCAN_COMPLETE: + wilc_scan_complete_received(wilc, frame - 4, size + 4); + break; + + default: + rsp->seq_no = msg_id; + break; + } +} + +int wilc_wlan_cfg_init(struct wilc *wl) +{ + struct wilc_cfg_str_vals *str_vals; + int i = 0; + + wl->cfg.b = kmemdup(g_cfg_byte, sizeof(g_cfg_byte), GFP_KERNEL); + if (!wl->cfg.b) + return -ENOMEM; + + wl->cfg.hw = kmemdup(g_cfg_hword, sizeof(g_cfg_hword), GFP_KERNEL); + if (!wl->cfg.hw) + goto out_b; + + wl->cfg.w = kmemdup(g_cfg_word, sizeof(g_cfg_word), GFP_KERNEL); + if (!wl->cfg.w) + goto out_hw; + + wl->cfg.s = kmemdup(g_cfg_str, sizeof(g_cfg_str), GFP_KERNEL); + if (!wl->cfg.s) + goto out_w; + + str_vals = kzalloc(sizeof(*str_vals), GFP_KERNEL); + if (!str_vals) + goto out_s; + + wl->cfg.str_vals = str_vals; + /* store the string cfg parameters */ + wl->cfg.s[i].id = WID_FIRMWARE_VERSION; + wl->cfg.s[i].str = str_vals->firmware_version; + i++; + wl->cfg.s[i].id = WID_MAC_ADDR; + wl->cfg.s[i].str = str_vals->mac_address; + i++; + wl->cfg.s[i].id = WID_ASSOC_RES_INFO; + wl->cfg.s[i].str = str_vals->assoc_rsp; + i++; + wl->cfg.s[i].id = WID_NIL; + wl->cfg.s[i].str = NULL; + return 0; + +out_s: + kfree(wl->cfg.s); +out_w: + kfree(wl->cfg.w); +out_hw: + kfree(wl->cfg.hw); +out_b: + kfree(wl->cfg.b); + return -ENOMEM; +} + +void wilc_wlan_cfg_deinit(struct wilc *wl) +{ + kfree(wl->cfg.b); + kfree(wl->cfg.hw); + kfree(wl->cfg.w); + kfree(wl->cfg.s); + kfree(wl->cfg.str_vals); +} diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h new file mode 100644 index 000000000000..614c5673f232 --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef WILC_WLAN_CFG_H +#define WILC_WLAN_CFG_H + +struct wilc_cfg_byte { + u16 id; + u8 val; +}; + +struct wilc_cfg_hword { + u16 id; + u16 val; +}; + +struct wilc_cfg_word { + u16 id; + u32 val; +}; + +struct wilc_cfg_str { + u16 id; + u8 *str; +}; + +struct wilc_cfg_str_vals { + u8 mac_address[7]; + u8 firmware_version[129]; + u8 assoc_rsp[256]; +}; + +struct wilc_cfg { + struct wilc_cfg_byte *b; + struct wilc_cfg_hword *hw; + struct wilc_cfg_word *w; + struct wilc_cfg_str *s; + struct wilc_cfg_str_vals *str_vals; +}; + +struct wilc; +int wilc_wlan_cfg_set_wid(u8 *frame, u32 offset, u16 id, u8 *buf, int size); +int wilc_wlan_cfg_get_wid(u8 *frame, u32 offset, u16 id); +int wilc_wlan_cfg_get_val(struct wilc *wl, u16 wid, u8 *buffer, + u32 buffer_size); +void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, + struct wilc_cfg_rsp *rsp); +int wilc_wlan_cfg_init(struct wilc *wl); +void wilc_wlan_cfg_deinit(struct wilc *wl); + +#endif diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_if.h b/drivers/net/wireless/microchip/wilc1000/wlan_if.h new file mode 100644 index 000000000000..f85fd575136d --- /dev/null +++ b/drivers/net/wireless/microchip/wilc1000/wlan_if.h @@ -0,0 +1,803 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 - 2018 Microchip Technology Inc., and its subsidiaries. + * All rights reserved. + */ + +#ifndef WILC_WLAN_IF_H +#define WILC_WLAN_IF_H + +#include <linux/netdevice.h> +#include "fw.h" + +/******************************************** + * + * Wlan Configuration ID + * + ********************************************/ + +enum bss_types { + WILC_FW_BSS_TYPE_INFRA = 0, + WILC_FW_BSS_TYPE_INDEPENDENT, + WILC_FW_BSS_TYPE_AP, +}; + +enum { + WILC_FW_OPER_MODE_B_ONLY = 0, /* 1, 2 M, otherwise 5, 11 M */ + WILC_FW_OPER_MODE_G_ONLY, /* 6,12,24 otherwise 9,18,36,48,54 */ + WILC_FW_OPER_MODE_G_MIXED_11B_1, /* 1,2,5.5,11 otherwise all on */ + WILC_FW_OPER_MODE_G_MIXED_11B_2, /* 1,2,5,11,6,12,24 otherwise all on */ +}; + +enum { + WILC_FW_PREAMBLE_SHORT = 0, /* Short Preamble */ + WILC_FW_PREAMBLE_LONG = 1, /* Long Preamble */ + WILC_FW_PREAMBLE_AUTO = 2, /* Auto Preamble Selection */ +}; + +enum { + WILC_FW_PASSIVE_SCAN = 0, + WILC_FW_ACTIVE_SCAN = 1, +}; + +enum { + WILC_FW_NO_POWERSAVE = 0, + WILC_FW_MIN_FAST_PS = 1, + WILC_FW_MAX_FAST_PS = 2, + WILC_FW_MIN_PSPOLL_PS = 3, + WILC_FW_MAX_PSPOLL_PS = 4 +}; + +enum chip_ps_states { + WILC_CHIP_WAKEDUP = 0, + WILC_CHIP_SLEEPING_AUTO = 1, + WILC_CHIP_SLEEPING_MANUAL = 2 +}; + +enum bus_acquire { + WILC_BUS_ACQUIRE_ONLY = 0, + WILC_BUS_ACQUIRE_AND_WAKEUP = 1, +}; + +enum bus_release { + WILC_BUS_RELEASE_ONLY = 0, + WILC_BUS_RELEASE_ALLOW_SLEEP = 1, +}; + +enum { + WILC_FW_NO_ENCRYPT = 0, + WILC_FW_ENCRYPT_ENABLED = BIT(0), + WILC_FW_WEP = BIT(1), + WILC_FW_WEP_EXTENDED = BIT(2), + WILC_FW_WPA = BIT(3), + WILC_FW_WPA2 = BIT(4), + WILC_FW_AES = BIT(5), + WILC_FW_TKIP = BIT(6) +}; + +enum { + WILC_FW_SEC_NO = WILC_FW_NO_ENCRYPT, + WILC_FW_SEC_WEP = WILC_FW_WEP | WILC_FW_ENCRYPT_ENABLED, + WILC_FW_SEC_WEP_EXTENDED = WILC_FW_WEP_EXTENDED | WILC_FW_SEC_WEP, + WILC_FW_SEC_WPA = WILC_FW_WPA | WILC_FW_ENCRYPT_ENABLED, + WILC_FW_SEC_WPA_AES = WILC_FW_AES | WILC_FW_SEC_WPA, + WILC_FW_SEC_WPA_TKIP = WILC_FW_TKIP | WILC_FW_SEC_WPA, + WILC_FW_SEC_WPA2 = WILC_FW_WPA2 | WILC_FW_ENCRYPT_ENABLED, + WILC_FW_SEC_WPA2_AES = WILC_FW_AES | WILC_FW_SEC_WPA2, + WILC_FW_SEC_WPA2_TKIP = WILC_FW_TKIP | WILC_FW_SEC_WPA2 +}; + +enum authtype { + WILC_FW_AUTH_OPEN_SYSTEM = 1, + WILC_FW_AUTH_SHARED_KEY = 2, + WILC_FW_AUTH_ANY = 3, + WILC_FW_AUTH_IEEE8021 = 5 +}; + +enum site_survey { + WILC_FW_SITE_SURVEY_1CH = 0, + WILC_FW_SITE_SURVEY_ALL_CH = 1, + WILC_FW_SITE_SURVEY_OFF = 2 +}; + +enum { + WILC_FW_ACK_POLICY_NORMAL = 0, + WILC_FW_ACK_NO_POLICY, +}; + +enum { + WILC_FW_REKEY_POLICY_DISABLE = 1, + WILC_FW_REKEY_POLICY_TIME_BASE, + WILC_FW_REKEY_POLICY_PKT_BASE, + WILC_FW_REKEY_POLICY_TIME_PKT_BASE +}; + +enum { + WILC_FW_FILTER_NO = 0x00, + WILC_FW_FILTER_AP_ONLY = 0x01, + WILC_FW_FILTER_STA_ONLY = 0x02 +}; + +enum { + WILC_FW_11N_PROT_AUTO = 0, /* Auto */ + WILC_FW_11N_NO_PROT, /* Do not use any protection */ + WILC_FW_11N_PROT_ERP, /* Protect all ERP frame exchanges */ + WILC_FW_11N_PROT_HT, /* Protect all HT frame exchanges */ + WILC_FW_11N_PROT_GF /* Protect all GF frame exchanges */ +}; + +enum { + WILC_FW_ERP_PROT_SELF_CTS, + WILC_FW_ERP_PROT_RTS_CTS, +}; + +enum { + WILC_FW_11N_OP_MODE_HT_MIXED = 1, + WILC_FW_11N_OP_MODE_HT_ONLY_20MHZ, + WILC_FW_11N_OP_MODE_HT_ONLY_20_40MHZ, +}; + +enum { + WILC_FW_OBBS_NONHT_NO_DETECT = 0, + WILC_FW_OBBS_NONHT_DETECT_ONLY = 1, + WILC_FW_OBBS_NONHT_DETECT_PROTECT = 2, + WILC_FW_OBBS_NONHT_DETECT_PROTECT_REPORT = 3, +}; + +enum { + WILC_FW_HT_PROT_RTS_CTS_NONHT = 0, /* RTS-CTS at non-HT rate */ + WILC_FW_HT_PROT_FIRST_FRAME_NONHT, /* First frame at non-HT rate */ + WILC_FW_HT_PROT_LSIG_TXOP, /* LSIG TXOP Protection */ + WILC_FW_HT_PROT_FIRST_FRAME_MIXED, /* First frame at Mixed format */ +}; + +enum { + WILC_FW_SMPS_MODE_STATIC = 1, + WILC_FW_SMPS_MODE_DYNAMIC = 2, + WILC_FW_SMPS_MODE_MIMO = 3, /* power save disable */ +}; + +enum { + WILC_FW_TX_RATE_AUTO = 0, + WILC_FW_TX_RATE_MBPS_1 = 1, + WILC_FW_TX_RATE_MBPS_2 = 2, + WILC_FW_TX_RATE_MBPS_5_5 = 5, + WILC_FW_TX_RATE_MBPS_11 = 11, + WILC_FW_TX_RATE_MBPS_6 = 6, + WILC_FW_TX_RATE_MBPS_9 = 9, + WILC_FW_TX_RATE_MBPS_12 = 12, + WILC_FW_TX_RATE_MBPS_18 = 18, + WILC_FW_TX_RATE_MBPS_24 = 24, + WILC_FW_TX_RATE_MBPS_36 = 36, + WILC_FW_TX_RATE_MBPS_48 = 48, + WILC_FW_TX_RATE_MBPS_54 = 54 +}; + +enum { + WILC_FW_DEFAULT_SCAN = 0, + WILC_FW_USER_SCAN = BIT(0), + WILC_FW_OBSS_PERIODIC_SCAN = BIT(1), + WILC_FW_OBSS_ONETIME_SCAN = BIT(2) +}; + +enum { + WILC_FW_ACTION_FRM_IDX = 0, + WILC_FW_PROBE_REQ_IDX = 1 +}; + +enum wid_type { + WID_CHAR = 0, + WID_SHORT = 1, + WID_INT = 2, + WID_STR = 3, + WID_BIN_DATA = 4, + WID_BIN = 5, +}; + +struct wid { + u16 id; + enum wid_type type; + s32 size; + s8 *val; +}; + +enum { + WID_NIL = 0xffff, + + /* + * BSS Type + * ----------------------------------------------------------- + * Configuration : Infrastructure Independent Access Point + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_BSS_TYPE = 0x0000, + + /* + * Transmit Rate + * ----------------------------------------------------------- + * Configuration : 1 2 5.5 11 6 9 12 18 24 36 48 54 + * Values to set : 1 2 5 11 6 9 12 18 24 36 48 54 + * ----------------------------------------------------------- + */ + WID_CURRENT_TX_RATE = 0x0001, + + /* + * Channel + * ----------------------------------------------------------- + * Configuration(g) : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + * Values to set : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + * ----------------------------------------------------------- + */ + WID_CURRENT_CHANNEL = 0x0002, + + /* + * Preamble + * ----------------------------------------------------------- + * Configuration : short long Auto + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_PREAMBLE = 0x0003, + + /* + * 11g operating mode (ignored if 11g not present) + * ----------------------------------------------------------- + * Configuration : HighPerf Compat(RSet #1) Compat(RSet #2) + * Values to set : 1 2 3 + * ----------------------------------------------------------- + */ + WID_11G_OPERATING_MODE = 0x0004, + + /* + * Mac status (response only) + * ----------------------------------------------------------- + * Configuration : disconnect connect + * Values to get : 0 1 + * ----------------------------------------------------------- + */ + WID_STATUS = 0x0005, + + /* + * Scan type + * ----------------------------------------------------------- + * Configuration : Passive Scanning Active Scanning + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_SCAN_TYPE = 0x0007, + + /* + * Key Id (WEP default key Id) + * ----------------------------------------------------------- + * Configuration : Any value between 0 to 3 + * Values to set : Same value. Default is 0 + * ----------------------------------------------------------- + */ + WID_KEY_ID = 0x0009, + + /* + * QoS Enable + * ----------------------------------------------------------- + * Configuration : QoS Disable WMM Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_QOS_ENABLE = 0x000A, + + /* + * Power Management + * ----------------------------------------------------------- + * Configuration : NO_POWERSAVE MIN_POWERSAVE MAX_POWERSAVE + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_POWER_MANAGEMENT = 0x000B, + + /* + * WEP/802 11I Configuration + * ----------------------------------------------------------- + * Configuration:Disable WP40 WP104 WPA-AES WPA-TKIP RSN-AES RSN-TKIP + * Values (0x) : 00 03 07 29 49 31 51 + * Configuration:WPA-AES+TKIP RSN-AES+TKIP + * Values (0x) : 69 71 + * ----------------------------------------------------------- + */ + WID_11I_MODE = 0x000C, + + /* + * WEP Configuration: Used in BSS STA mode only when WEP is enabled + * ----------------------------------------------------------- + * Configuration : Open System Shared Key Any Type | 802.1x Auth + * Values (0x) : 01 02 03 | BIT2 + * ----------------------------------------------------------- + */ + WID_AUTH_TYPE = 0x000D, + + /* + * Site Survey Type + * ----------------------------------------------------------- + * Configuration : Values to set + * Survey 1 Channel : 0 + * survey all Channels : 1 + * Disable Site Survey : 2 + * ----------------------------------------------------------- + */ + WID_SITE_SURVEY = 0x000E, + + /* + * Listen Interval + * ----------------------------------------------------------- + * Configuration : Any value between 1 to 255 + * Values to set : Same value. Default is 3 + * ----------------------------------------------------------- + */ + WID_LISTEN_INTERVAL = 0x000F, + + /* + * DTIM Period + * ----------------------------------------------------------- + * Configuration : Any value between 1 to 255 + * Values to set : Same value. Default is 3 + * ----------------------------------------------------------- + */ + WID_DTIM_PERIOD = 0x0010, + + /* + * ACK Policy + * ----------------------------------------------------------- + * Configuration : Normal Ack No Ack + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_ACK_POLICY = 0x0011, + + /* + * Reset MAC (Set only) + * ----------------------------------------------------------- + * Configuration : Don't Reset Reset No Request + * Values to set : 0 1 2 + * ----------------------------------------------------------- + */ + WID_RESET = 0x0012, + + /* + * Broadcast SSID Option: Setting this will adhere to "" SSID element + * ----------------------------------------------------------- + * Configuration : Enable Disable + * Values to set : 1 0 + * ----------------------------------------------------------- + */ + WID_BCAST_SSID = 0x0015, + + /* + * Disconnect (Station) + * ----------------------------------------------------------- + * Configuration : Association ID + * Values to set : Association ID + * ----------------------------------------------------------- + */ + WID_DISCONNECT = 0x0016, + + /* + * 11a Tx Power Level + * ----------------------------------------------------------- + * Configuration : Sets TX Power (Higher the value greater the power) + * Values to set : Any value between 0 and 63 (inclusive Default 48) + * ----------------------------------------------------------- + */ + WID_TX_POWER_LEVEL_11A = 0x0018, + + /* + * Group Key Update Policy Selection + * ----------------------------------------------------------- + * Configuration : Disabled timeBased packetBased timePacketBased + * Values to set : 1 2 3 4 + * ----------------------------------------------------------- + */ + WID_REKEY_POLICY = 0x0019, + + /* + * Allow Short Slot + * ----------------------------------------------------------- + * Configuration : Disallow Short Slot Allow Short Slot + * (Enable Only Long Slot) (Enable Short Slot if applicable) + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_SHORT_SLOT_ALLOWED = 0x001A, + + WID_PHY_ACTIVE_REG = 0x001B, + + /* + * 11b Tx Power Level + * ----------------------------------------------------------- + * Configuration : Sets TX Power (Higher the value greater the power) + * Values to set : Any value between 0 and 63 (inclusive Default 48) + * ----------------------------------------------------------- + */ + WID_TX_POWER_LEVEL_11B = 0x001D, + + /* + * Scan Request + * ----------------------------------------------------------- + * Configuration : Request default scan + * Values to set : 0 + * ----------------------------------------------------------- + */ + WID_START_SCAN_REQ = 0x001E, + + /* + * Rssi (get only) + * ----------------------------------------------------------- + * Configuration : + * Values to get : Rssi value + * ----------------------------------------------------------- + */ + WID_RSSI = 0x001F, + + /* + * Join Request + * ----------------------------------------------------------- + * Configuration : Request to join + * Values to set : index of scan result + * ----------------------------------------------------------- + */ + WID_JOIN_REQ = 0x0020, + + WID_LINKSPEED = 0x0026, + + /* + * Enable User Control of TX Power + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_USER_CONTROL_ON_TX_POWER = 0x0027, + + WID_MEMORY_ACCESS_8BIT = 0x0029, + + /* + * Enable Auto RX Sensitivity feature + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_AUTO_RX_SENSITIVITY = 0x0032, + + /* + * Receive Buffer Based Ack + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_DATAFLOW_CONTROL = 0x0033, + + /* + * Scan Filter + * ----------------------------------------------------------- + * Configuration : Class No filter AP only Station Only + * Values to set : 0 1 2 + * Configuration : Priority High Rssi Low Rssi Detect + * Values to set : 0 0x4 0x0 + * Configuration : Channel filter off filter on + * Values to set : 0 0x10 + * ----------------------------------------------------------- + */ + WID_SCAN_FILTER = 0x0036, + + /* + * Link Loss Threshold (measure in the beacon period) + * ----------------------------------------------------------- + * Configuration : Any value between 10 and 254(Set to 255 disable) + * Values to set : Same value. Default is 10 + * ----------------------------------------------------------- + */ + WID_LINK_LOSS_THRESHOLD = 0x0037, + + WID_ABORT_RUNNING_SCAN = 0x003E, + + /* NMAC Character WID list */ + WID_WPS_START = 0x0043, + + /* + * Protection mode for MAC + * ----------------------------------------------------------- + * Configuration : Auto No protection ERP HT GF + * Values to set : 0 1 2 3 4 + * ----------------------------------------------------------- + */ + WID_11N_PROT_MECH = 0x0080, + + /* + * ERP Protection type for MAC + * ----------------------------------------------------------- + * Configuration : Self-CTS RTS-CTS + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_ERP_PROT_TYPE = 0x0081, + + /* + * HT Option Enable + * ----------------------------------------------------------- + * Configuration : HT Enable HT Disable + * Values to set : 1 0 + * ----------------------------------------------------------- + */ + WID_11N_ENABLE = 0x0082, + + /* + * 11n Operating mode (Note that 11g operating mode will also be + * used in addition to this, if this is set to HT Mixed mode) + * ----------------------------------------------------------- + * Configuration : HT Mixed HT Only-20MHz HT Only-20/40MHz + * Values to set : 1 2 3 + * ----------------------------------------------------------- + */ + WID_11N_OPERATING_MODE = 0x0083, + + /* + * 11n OBSS non-HT STA Detection flag + * ----------------------------------------------------------- + * Configuration : Do not detect + * Values to set : 0 + * Configuration : Detect, do not protect or report + * Values to set : 1 + * Configuration : Detect, protect and do not report + * Values to set : 2 + * Configuration : Detect, protect and report to other BSS + * Values to set : 3 + * ----------------------------------------------------------- + */ + WID_11N_OBSS_NONHT_DETECTION = 0x0084, + + /* + * 11n HT Protection Type + * ----------------------------------------------------------- + * Configuration : RTS-CTS First Frame Exchange at non-HT-rate + * Values to set : 0 1 + * Configuration : LSIG TXOP First Frame Exchange in Mixed Fmt + * Values to set : 2 3 + * ----------------------------------------------------------- + */ + WID_11N_HT_PROT_TYPE = 0x0085, + + /* + * 11n RIFS Protection Enable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_RIFS_PROT_ENABLE = 0x0086, + + /* + * SMPS Mode + * ----------------------------------------------------------- + * Configuration : Static Dynamic MIMO (Power Save Disabled) + * Values to set : 1 2 3 + * ----------------------------------------------------------- + */ + WID_11N_SMPS_MODE = 0x0087, + + /* + * Current transmit MCS + * ----------------------------------------------------------- + * Configuration : MCS Index for data rate + * Values to set : 0 to 7 + * ----------------------------------------------------------- + */ + WID_11N_CURRENT_TX_MCS = 0x0088, + + WID_11N_PRINT_STATS = 0x0089, + + /* + * 11n Short GI Enable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_SHORT_GI_ENABLE = 0x008D, + + /* + * 11n RIFS Enable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_RIFS_MODE = 0x0094, + + /* + * TX Abort Feature + * ----------------------------------------------------------- + * Configuration : Disable Self CTS Enable Self CTS + * Values to set : 0 1 + * Configuration : Disable TX Abort Enable TX Abort + * Values to set : 2 3 + * Configuration : Enable HW TX Abort Enable SW TX Abort + * Values to set : 4 5 + * ----------------------------------------------------------- + */ + WID_TX_ABORT_CONFIG = 0x00A1, + + WID_REG_TSSI_11B_VALUE = 0x00A6, + WID_REG_TSSI_11G_VALUE = 0x00A7, + WID_REG_TSSI_11N_VALUE = 0x00A8, + WID_TX_CALIBRATION = 0x00A9, + WID_DSCR_TSSI_11B_VALUE = 0x00AA, + WID_DSCR_TSSI_11G_VALUE = 0x00AB, + WID_DSCR_TSSI_11N_VALUE = 0x00AC, + + /* + * Immediate Block-Ack Support + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 0 1 + * ----------------------------------------------------------- + */ + WID_11N_IMMEDIATE_BA_ENABLED = 0x00AF, + + /* + * TXOP Disable Flag + * ----------------------------------------------------------- + * Configuration : Disable Enable + * Values to set : 1 0 + * ----------------------------------------------------------- + */ + WID_11N_TXOP_PROT_DISABLE = 0x00B0, + + WID_TX_POWER_LEVEL_11N = 0x00B1, + + /* Custom Character WID list */ + /* SCAN Complete notification WID*/ + WID_SCAN_COMPLETE = 0x00C9, + + WID_DEL_BEACON = 0x00CA, + + WID_LOG_TERMINAL_SWITCH = 0x00CD, + WID_TX_POWER = 0x00CE, + /* EMAC Short WID list */ + /* RTS Threshold */ + /* + * ----------------------------------------------------------- + * Configuration : Any value between 256 to 2347 + * Values to set : Same value. Default is 2347 + * ----------------------------------------------------------- + */ + WID_RTS_THRESHOLD = 0x1000, + + /* + * Fragmentation Threshold + * ----------------------------------------------------------- + * Configuration : Any value between 256 to 2346 + * Values to set : Same value. Default is 2346 + * ----------------------------------------------------------- + */ + WID_FRAG_THRESHOLD = 0x1001, + + WID_SHORT_RETRY_LIMIT = 0x1002, + WID_LONG_RETRY_LIMIT = 0x1003, + WID_BEACON_INTERVAL = 0x1006, + WID_MEMORY_ACCESS_16BIT = 0x1008, + WID_PASSIVE_SCAN_TIME = 0x100D, + WID_JOIN_START_TIMEOUT = 0x100F, + WID_ASOC_TIMEOUT = 0x1011, + WID_11I_PROTOCOL_TIMEOUT = 0x1012, + WID_EAPOL_RESPONSE_TIMEOUT = 0x1013, + + /* NMAC Short WID list */ + WID_11N_SIG_QUAL_VAL = 0x1085, + WID_CCA_THRESHOLD = 0x1087, + + /* Custom Short WID list */ + + /* EMAC Integer WID list */ + WID_FAILED_COUNT = 0x2000, + WID_RETRY_COUNT = 0x2001, + WID_MULTIPLE_RETRY_COUNT = 0x2002, + WID_FRAME_DUPLICATE_COUNT = 0x2003, + WID_ACK_FAILURE_COUNT = 0x2004, + WID_RECEIVED_FRAGMENT_COUNT = 0x2005, + WID_MCAST_RECEIVED_FRAME_COUNT = 0x2006, + WID_FCS_ERROR_COUNT = 0x2007, + WID_SUCCESS_FRAME_COUNT = 0x2008, + WID_HUT_TX_COUNT = 0x200A, + WID_TX_FRAGMENT_COUNT = 0x200B, + WID_TX_MULTICAST_FRAME_COUNT = 0x200C, + WID_RTS_SUCCESS_COUNT = 0x200D, + WID_RTS_FAILURE_COUNT = 0x200E, + WID_WEP_UNDECRYPTABLE_COUNT = 0x200F, + WID_REKEY_PERIOD = 0x2010, + WID_REKEY_PACKET_COUNT = 0x2011, + WID_1X_SERV_ADDR = 0x2012, + WID_STACK_IP_ADDR = 0x2013, + WID_STACK_NETMASK_ADDR = 0x2014, + WID_HW_RX_COUNT = 0x2015, + WID_MEMORY_ADDRESS = 0x201E, + WID_MEMORY_ACCESS_32BIT = 0x201F, + + /* NMAC Integer WID list */ + /* Custom Integer WID list */ + WID_GET_INACTIVE_TIME = 0x2084, + /* EMAC String WID list */ + WID_SSID = 0x3000, + WID_FIRMWARE_VERSION = 0x3001, + WID_OPERATIONAL_RATE_SET = 0x3002, + WID_BSSID = 0x3003, + WID_WEP_KEY_VALUE = 0x3004, + WID_11I_PSK = 0x3008, + WID_11E_P_ACTION_REQ = 0x3009, + WID_1X_KEY = 0x300A, + WID_HARDWARE_VERSION = 0x300B, + WID_MAC_ADDR = 0x300C, + WID_HUT_DEST_ADDR = 0x300D, + WID_PHY_VERSION = 0x300F, + WID_SUPP_USERNAME = 0x3010, + WID_SUPP_PASSWORD = 0x3011, + WID_SITE_SURVEY_RESULTS = 0x3012, + WID_RX_POWER_LEVEL = 0x3013, + WID_SET_STA_MAC_INACTIVE_TIME = 0x3017, + WID_ADD_WEP_KEY = 0x3019, + WID_REMOVE_WEP_KEY = 0x301A, + WID_ADD_PTK = 0x301B, + WID_ADD_RX_GTK = 0x301C, + WID_ADD_TX_GTK = 0x301D, + WID_REMOVE_KEY = 0x301E, + WID_ASSOC_REQ_INFO = 0x301F, + WID_ASSOC_RES_INFO = 0x3020, + WID_MANUFACTURER = 0x3026, /* Added for CAPI tool */ + WID_MODEL_NAME = 0x3027, /* Added for CAPI tool */ + WID_MODEL_NUM = 0x3028, /* Added for CAPI tool */ + WID_DEVICE_NAME = 0x3029, /* Added for CAPI tool */ + + /* NMAC String WID list */ + WID_SET_OPERATION_MODE = 0x3079, + WID_11N_P_ACTION_REQ = 0x3080, + WID_HUT_TEST_ID = 0x3081, + WID_PMKID_INFO = 0x3082, + WID_FIRMWARE_INFO = 0x3083, + WID_REGISTER_FRAME = 0x3084, + WID_DEL_ALL_STA = 0x3085, + WID_REMAIN_ON_CHAN = 0x3996, + WID_SSID_PROBE_REQ = 0x3997, + WID_JOIN_REQ_EXTENDED = 0x3998, + + WID_IP_ADDRESS = 0x3999, + + /* Custom String WID list */ + + /* EMAC Binary WID list */ + WID_UAPSD_CONFIG = 0x4001, + WID_UAPSD_STATUS = 0x4002, + WID_WMM_AP_AC_PARAMS = 0x4003, + WID_WMM_STA_AC_PARAMS = 0x4004, + WID_NETWORK_INFO = 0x4005, + WID_STA_JOIN_INFO = 0x4006, + WID_CONNECTED_STA_LIST = 0x4007, + + /* NMAC Binary WID list */ + WID_11N_AUTORATE_TABLE = 0x4080, + + WID_SCAN_CHANNEL_LIST = 0x4084, + + WID_INFO_ELEMENT_PROBE = 0x4085, + WID_INFO_ELEMENT_ASSOCIATE = 0x4086, + WID_ADD_STA = 0X4087, + WID_REMOVE_STA = 0X4088, + WID_EDIT_STA = 0X4089, + WID_ADD_BEACON = 0x408a, + + WID_SETUP_MULTICAST_FILTER = 0x408b, + + /* Miscellaneous WIDs */ + WID_ALL = 0x7FFE, + WID_MAX = 0xFFFF +}; + +#endif diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index eea777f8acea..6aafff9d4231 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -446,8 +446,11 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, } wiphy = qtnf_wiphy_allocate(bus, pdev); - if (!wiphy) + if (!wiphy) { + if (pdev) + platform_device_unregister(pdev); return ERR_PTR(-ENOMEM); + } mac = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c index 4d44509e2ce3..c1ac933349d1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c @@ -1834,8 +1834,7 @@ static struct pci_driver rt2400pci_driver = { .id_table = rt2400pci_device_table, .probe = rt2400pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt2400pci_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c index 4620990a94cf..0859adebd860 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c @@ -2132,8 +2132,7 @@ static struct pci_driver rt2500pci_driver = { .id_table = rt2500pci_device_table, .probe = rt2500pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt2500pci_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 3868c07672bd..9a33baaa6184 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -455,8 +455,7 @@ static struct pci_driver rt2800pci_driver = { .id_table = rt2800pci_device_table, .probe = rt2800pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt2800pci_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index ea8a34ecae14..ecc60d8cbb01 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1487,9 +1487,8 @@ bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw); */ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev); void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev); -#ifdef CONFIG_PM -int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state); + +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev); int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev); -#endif /* CONFIG_PM */ #endif /* RT2X00_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index 7f9e43a4f805..8c6d3099b19d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -1556,8 +1556,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev); /* * Device state handlers */ -#ifdef CONFIG_PM -int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) +int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev) { rt2x00_dbg(rt2x00dev, "Going to sleep\n"); @@ -1614,7 +1613,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) return 0; } EXPORT_SYMBOL_GPL(rt2x00lib_resume); -#endif /* CONFIG_PM */ /* * rt2x00lib module information. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c index 7f9baa94c7c8..cabeef0dde45 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.c @@ -169,39 +169,24 @@ void rt2x00pci_remove(struct pci_dev *pci_dev) } EXPORT_SYMBOL_GPL(rt2x00pci_remove); -#ifdef CONFIG_PM -int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) +static int __maybe_unused rt2x00pci_suspend(struct device *dev) { - struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct ieee80211_hw *hw = dev_get_drvdata(dev); struct rt2x00_dev *rt2x00dev = hw->priv; - int retval; - - retval = rt2x00lib_suspend(rt2x00dev, state); - if (retval) - return retval; - pci_save_state(pci_dev); - pci_disable_device(pci_dev); - return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + return rt2x00lib_suspend(rt2x00dev); } -EXPORT_SYMBOL_GPL(rt2x00pci_suspend); -int rt2x00pci_resume(struct pci_dev *pci_dev) +static int __maybe_unused rt2x00pci_resume(struct device *dev) { - struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); + struct ieee80211_hw *hw = dev_get_drvdata(dev); struct rt2x00_dev *rt2x00dev = hw->priv; - if (pci_set_power_state(pci_dev, PCI_D0) || - pci_enable_device(pci_dev)) { - rt2x00_err(rt2x00dev, "Failed to resume device\n"); - return -EIO; - } - - pci_restore_state(pci_dev); return rt2x00lib_resume(rt2x00dev); } -EXPORT_SYMBOL_GPL(rt2x00pci_resume); -#endif /* CONFIG_PM */ + +SIMPLE_DEV_PM_OPS(rt2x00pci_pm_ops, rt2x00pci_suspend, rt2x00pci_resume); +EXPORT_SYMBOL_GPL(rt2x00pci_pm_ops); /* * rt2x00pci module information. diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h index fd955ccaa1e6..27f7b2bd26ea 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00pci.h @@ -21,12 +21,7 @@ */ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops); void rt2x00pci_remove(struct pci_dev *pci_dev); -#ifdef CONFIG_PM -int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state); -int rt2x00pci_resume(struct pci_dev *pci_dev); -#else -#define rt2x00pci_suspend NULL -#define rt2x00pci_resume NULL -#endif /* CONFIG_PM */ + +extern const struct dev_pm_ops rt2x00pci_pm_ops; #endif /* RT2X00PCI_H */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c index 596b8a432946..eface610178d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c @@ -130,7 +130,7 @@ int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) struct ieee80211_hw *hw = platform_get_drvdata(pdev); struct rt2x00_dev *rt2x00dev = hw->priv; - return rt2x00lib_suspend(rt2x00dev, state); + return rt2x00lib_suspend(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00soc_suspend); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c index 92e9e023c349..e4473a551241 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c @@ -886,7 +886,7 @@ int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state) struct ieee80211_hw *hw = usb_get_intfdata(usb_intf); struct rt2x00_dev *rt2x00dev = hw->priv; - return rt2x00lib_suspend(rt2x00dev, state); + return rt2x00lib_suspend(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00usb_suspend); diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index d83288bef2fc..eefce76fc99b 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -3009,8 +3009,7 @@ static struct pci_driver rt61pci_driver = { .id_table = rt61pci_device_table, .probe = rt61pci_probe, .remove = rt2x00pci_remove, - .suspend = rt2x00pci_suspend, - .resume = rt2x00pci_resume, + .driver.pm = &rt2x00pci_pm_ops, }; module_pci_driver(rt61pci_driver); diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index d5f65372356b..ba3286f732cc 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1966,32 +1966,17 @@ static void rtl8180_remove(struct pci_dev *pdev) ieee80211_free_hw(dev); } -#ifdef CONFIG_PM -static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) -{ - pci_save_state(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int rtl8180_resume(struct pci_dev *pdev) -{ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - return 0; -} +#define rtl8180_suspend NULL +#define rtl8180_resume NULL -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(rtl8180_pm_ops, rtl8180_suspend, rtl8180_resume); static struct pci_driver rtl8180_driver = { .name = KBUILD_MODNAME, .id_table = rtl8180_table, .probe = rtl8180_probe, .remove = rtl8180_remove, -#ifdef CONFIG_PM - .suspend = rtl8180_suspend, - .resume = rtl8180_resume, -#endif /* CONFIG_PM */ + .driver.pm = &rtl8180_pm_ops, }; module_pci_driver(rtl8180_driver); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index a4940a3842de..2b140c1e8e8d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -894,11 +894,9 @@ static void halbtc_display_wifi_status(struct btc_coexist *btcoexist, (low_power ? ", 32k" : "")); seq_printf(m, - "\n %-35s = %02x %02x %02x %02x %02x %02x (0x%x/0x%x)", + "\n %-35s = %6ph (0x%x/0x%x)", "Power mode cmd(lps/rpwm)", - btcoexist->pwr_mode_val[0], btcoexist->pwr_mode_val[1], - btcoexist->pwr_mode_val[2], btcoexist->pwr_mode_val[3], - btcoexist->pwr_mode_val[4], btcoexist->pwr_mode_val[5], + btcoexist->pwr_mode_val, btcoexist->bt_info.lps_val, btcoexist->bt_info.rpwm_val); } @@ -1318,7 +1316,7 @@ bool exhalbtc_bind_bt_coex_withadapter(void *adapter) { struct rtl_priv *rtlpriv = adapter; struct btc_coexist *btcoexist = rtl_btc_coexist(rtlpriv); - u8 ant_num = 2, chip_type, single_ant_path = 0; + u8 ant_num, chip_type, single_ant_path; if (!btcoexist) return false; diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index bc0ac96ee615..90f92728e16a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -769,13 +769,13 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, *(u8 *)(ie + index); index += 1; p2pinfo->noa_duration[i] = - le32_to_cpu(*(__le32 *)ie + index); + le32_to_cpu(*(__le32 *)(ie + index)); index += 4; p2pinfo->noa_interval[i] = - le32_to_cpu(*(__le32 *)ie + index); + le32_to_cpu(*(__le32 *)(ie + index)); index += 4; p2pinfo->noa_start_time[i] = - le32_to_cpu(*(__le32 *)ie + index); + le32_to_cpu(*(__le32 *)(ie + index)); index += 4; } @@ -864,13 +864,13 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, *(u8 *)(ie + index); index += 1; p2pinfo->noa_duration[i] = - le32_to_cpu(*(__le32 *)ie + index); + le32_to_cpu(*(__le32 *)(ie + index)); index += 4; p2pinfo->noa_interval[i] = - le32_to_cpu(*(__le32 *)ie + index); + le32_to_cpu(*(__le32 *)(ie + index)); index += 4; p2pinfo->noa_start_time[i] = - le32_to_cpu(*(__le32 *)ie + index); + le32_to_cpu(*(__le32 *)(ie + index)); index += 4; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c index dceb04a9b3f5..1ffa188a65c9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c @@ -870,11 +870,11 @@ static void dm_txpower_track_cb_therm(struct ieee80211_hw *hw) /*0.1 the following TWO tables decide the *final index of OFDM/CCK swing table */ - s8 delta_swing_table_idx[2][15] = { + static const s8 delta_swing_table_idx[2][15] = { {0, 0, 2, 3, 4, 4, 5, 6, 7, 7, 8, 9, 10, 10, 11}, {0, 0, -1, -2, -3, -4, -4, -4, -4, -5, -7, -8, -9, -9, -10} }; - u8 thermal_threshold[2][15] = { + static const u8 thermal_threshold[2][15] = { {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 27}, {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 25, 25, 25} }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c index aa2e9e88be53..a5d2d6ece8db 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c @@ -497,7 +497,7 @@ void rtl88ee_tx_fill_desc(struct ieee80211_hw *hw, dma_addr_t mapping; u8 bw_40 = 0; u8 short_gi = 0; - __le32 *pdesc = (u32 *)pdesc8; + __le32 *pdesc = (__le32 *)pdesc8; if (mac->opmode == NL80211_IFTYPE_STATION) { bw_40 = mac->bw_40; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index f070f25bb735..0ae9cfc65272 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -592,7 +592,7 @@ static void _rtl92cu_init_chipn_one_out_ep_priority(struct ieee80211_hw *hw, bool wmm_enable, u8 queue_sel) { - u16 uninitialized_var(value); + u16 value; switch (queue_sel) { case TX_SELE_HQ: @@ -606,7 +606,7 @@ static void _rtl92cu_init_chipn_one_out_ep_priority(struct ieee80211_hw *hw, break; default: WARN_ON(1); /* Shall not reach here! */ - break; + return; } _rtl92c_init_chipn_reg_priority(hw, value, value, value, value, value, value); @@ -618,8 +618,8 @@ static void _rtl92cu_init_chipn_two_out_ep_priority(struct ieee80211_hw *hw, u8 queue_sel) { u16 beq, bkq, viq, voq, mgtq, hiq; - u16 uninitialized_var(valuehi); - u16 uninitialized_var(valuelow); + u16 valuehi; + u16 valuelow; switch (queue_sel) { case (TX_SELE_HQ | TX_SELE_LQ): diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c index b13fd3c0c832..c9b3d9d09c48 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c @@ -736,11 +736,11 @@ static void rtl8723be_dm_txpower_tracking_callback_thermalmeter( u8 ofdm_min_index = 6; u8 index_for_channel = 0; - s8 delta_swing_table_idx_tup_a[TXSCALE_TABLE_SIZE] = { + static const s8 delta_swing_table_idx_tup_a[TXSCALE_TABLE_SIZE] = { 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 15}; - s8 delta_swing_table_idx_tdown_a[TXSCALE_TABLE_SIZE] = { + static const s8 delta_swing_table_idx_tdown_a[TXSCALE_TABLE_SIZE] = { 0, 0, 1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15}; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index f57e8794f0ec..97a30ccf0b27 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -115,47 +115,47 @@ static const u32 edca_setting_ul[PEER_MAX] = { 0x5ea44f, /* 7 MARV */ }; -static u8 rtl8818e_delta_swing_table_idx_24gb_p[] = { +static const u8 rtl8818e_delta_swing_table_idx_24gb_p[] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9}; -static u8 rtl8818e_delta_swing_table_idx_24gb_n[] = { +static const u8 rtl8818e_delta_swing_table_idx_24gb_n[] = { 0, 0, 0, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11}; -static u8 rtl8812ae_delta_swing_table_idx_24gb_n[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24gb_n[] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11}; -static u8 rtl8812ae_delta_swing_table_idx_24gb_p[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24gb_p[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; -static u8 rtl8812ae_delta_swing_table_idx_24ga_n[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24ga_n[] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11}; -static u8 rtl8812ae_delta_swing_table_idx_24ga_p[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24ga_p[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; -static u8 rtl8812ae_delta_swing_table_idx_24gcckb_n[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24gcckb_n[] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11}; -static u8 rtl8812ae_delta_swing_table_idx_24gcckb_p[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24gcckb_p[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; -static u8 rtl8812ae_delta_swing_table_idx_24gccka_n[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24gccka_n[] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11}; -static u8 rtl8812ae_delta_swing_table_idx_24gccka_p[] = { +static const u8 rtl8812ae_delta_swing_table_idx_24gccka_p[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9}; -static u8 rtl8812ae_delta_swing_table_idx_5gb_n[][DEL_SW_IDX_SZ] = { +static const u8 rtl8812ae_delta_swing_table_idx_5gb_n[][DEL_SW_IDX_SZ] = { {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 12, 12, 13}, {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, @@ -164,7 +164,7 @@ static u8 rtl8812ae_delta_swing_table_idx_5gb_n[][DEL_SW_IDX_SZ] = { 12, 12, 13, 14, 14, 14, 15, 16, 17, 17, 17, 18, 18, 18}, }; -static u8 rtl8812ae_delta_swing_table_idx_5gb_p[][DEL_SW_IDX_SZ] = { +static const u8 rtl8812ae_delta_swing_table_idx_5gb_p[][DEL_SW_IDX_SZ] = { {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11}, {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, @@ -173,7 +173,7 @@ static u8 rtl8812ae_delta_swing_table_idx_5gb_p[][DEL_SW_IDX_SZ] = { 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}, }; -static u8 rtl8812ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = { +static const u8 rtl8812ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = { {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13}, {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 8, 9, @@ -182,7 +182,7 @@ static u8 rtl8812ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = { 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18}, }; -static u8 rtl8812ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = { +static const u8 rtl8812ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = { {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11}, {0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, @@ -191,57 +191,23 @@ static u8 rtl8812ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = { 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11}, }; -static u8 rtl8821ae_delta_swing_table_idx_24gb_n[] = { +static const u8 rtl8821ae_delta_swing_table_idx_24ga_n[] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; -static u8 rtl8821ae_delta_swing_table_idx_24gb_p[] = { +static const u8 rtl8821ae_delta_swing_table_idx_24ga_p[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; -static u8 rtl8821ae_delta_swing_table_idx_24ga_n[] = { +static const u8 rtl8821ae_delta_swing_table_idx_24gccka_n[] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; -static u8 rtl8821ae_delta_swing_table_idx_24ga_p[] = { +static const u8 rtl8821ae_delta_swing_table_idx_24gccka_p[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; -static u8 rtl8821ae_delta_swing_table_idx_24gcckb_n[] = { - 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, - 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; - -static u8 rtl8821ae_delta_swing_table_idx_24gcckb_p[] = { - 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; - -static u8 rtl8821ae_delta_swing_table_idx_24gccka_n[] = { - 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, - 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10}; - -static u8 rtl8821ae_delta_swing_table_idx_24gccka_p[] = { - 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 12}; - -static u8 rtl8821ae_delta_swing_table_idx_5gb_n[][DEL_SW_IDX_SZ] = { - {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, - 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, - {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, - 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, - {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, - 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, -}; - -static u8 rtl8821ae_delta_swing_table_idx_5gb_p[][DEL_SW_IDX_SZ] = { - {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, - 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, - {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, - 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, - {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, - 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, -}; - -static u8 rtl8821ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = { +static const u8 rtl8821ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = { {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, @@ -250,7 +216,7 @@ static u8 rtl8821ae_delta_swing_table_idx_5ga_n[][DEL_SW_IDX_SZ] = { 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, }; -static u8 rtl8821ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = { +static const u8 rtl8821ae_delta_swing_table_idx_5ga_p[][DEL_SW_IDX_SZ] = { {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16}, {0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 11, @@ -962,8 +928,10 @@ static void rtl8821ae_dm_iq_calibrate(struct ieee80211_hw *hw) } static void rtl8812ae_get_delta_swing_table(struct ieee80211_hw *hw, - u8 **up_a, u8 **down_a, - u8 **up_b, u8 **down_b) + const u8 **up_a, + const u8 **down_a, + const u8 **up_b, + const u8 **down_b) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; @@ -999,10 +967,10 @@ static void rtl8812ae_get_delta_swing_table(struct ieee80211_hw *hw, *up_b = rtl8812ae_delta_swing_table_idx_5gb_p[2]; *down_b = rtl8812ae_delta_swing_table_idx_5gb_n[2]; } else { - *up_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p; - *down_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n; - *up_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p; - *down_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n; + *up_a = rtl8818e_delta_swing_table_idx_24gb_p; + *down_a = rtl8818e_delta_swing_table_idx_24gb_n; + *up_b = rtl8818e_delta_swing_table_idx_24gb_p; + *down_b = rtl8818e_delta_swing_table_idx_24gb_n; } } @@ -1492,17 +1460,17 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter( /* 1. The following TWO tables decide * the final index of OFDM/CCK swing table. */ - u8 *delta_swing_table_idx_tup_a; - u8 *delta_swing_table_idx_tdown_a; - u8 *delta_swing_table_idx_tup_b; - u8 *delta_swing_table_idx_tdown_b; + const u8 *delta_swing_table_idx_tup_a; + const u8 *delta_swing_table_idx_tdown_a; + const u8 *delta_swing_table_idx_tup_b; + const u8 *delta_swing_table_idx_tdown_b; /*2. Initilization ( 7 steps in total )*/ rtl8812ae_get_delta_swing_table(hw, - (u8 **)&delta_swing_table_idx_tup_a, - (u8 **)&delta_swing_table_idx_tdown_a, - (u8 **)&delta_swing_table_idx_tup_b, - (u8 **)&delta_swing_table_idx_tdown_b); + &delta_swing_table_idx_tup_a, + &delta_swing_table_idx_tdown_a, + &delta_swing_table_idx_tup_b, + &delta_swing_table_idx_tdown_b); rtldm->txpower_trackinginit = true; @@ -1830,8 +1798,9 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter( "<===rtl8812ae_dm_txpower_tracking_callback_thermalmeter\n"); } -static void rtl8821ae_get_delta_swing_table(struct ieee80211_hw *hw, u8 **up_a, - u8 **down_a, u8 **up_b, u8 **down_b) +static void rtl8821ae_get_delta_swing_table(struct ieee80211_hw *hw, + const u8 **up_a, + const u8 **down_a) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; @@ -1843,34 +1812,22 @@ static void rtl8821ae_get_delta_swing_table(struct ieee80211_hw *hw, u8 **up_a, if (RTL8821AE_RX_HAL_IS_CCK_RATE(rate)) { *up_a = rtl8821ae_delta_swing_table_idx_24gccka_p; *down_a = rtl8821ae_delta_swing_table_idx_24gccka_n; - *up_b = rtl8821ae_delta_swing_table_idx_24gcckb_p; - *down_b = rtl8821ae_delta_swing_table_idx_24gcckb_n; } else { *up_a = rtl8821ae_delta_swing_table_idx_24ga_p; *down_a = rtl8821ae_delta_swing_table_idx_24ga_n; - *up_b = rtl8821ae_delta_swing_table_idx_24gb_p; - *down_b = rtl8821ae_delta_swing_table_idx_24gb_n; } } else if (36 <= channel && channel <= 64) { *up_a = rtl8821ae_delta_swing_table_idx_5ga_p[0]; *down_a = rtl8821ae_delta_swing_table_idx_5ga_n[0]; - *up_b = rtl8821ae_delta_swing_table_idx_5gb_p[0]; - *down_b = rtl8821ae_delta_swing_table_idx_5gb_n[0]; } else if (100 <= channel && channel <= 140) { *up_a = rtl8821ae_delta_swing_table_idx_5ga_p[1]; *down_a = rtl8821ae_delta_swing_table_idx_5ga_n[1]; - *up_b = rtl8821ae_delta_swing_table_idx_5gb_p[1]; - *down_b = rtl8821ae_delta_swing_table_idx_5gb_n[1]; } else if (149 <= channel && channel <= 173) { *up_a = rtl8821ae_delta_swing_table_idx_5ga_p[2]; *down_a = rtl8821ae_delta_swing_table_idx_5ga_n[2]; - *up_b = rtl8821ae_delta_swing_table_idx_5gb_p[2]; - *down_b = rtl8821ae_delta_swing_table_idx_5gb_n[2]; } else { - *up_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p; - *down_a = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n; - *up_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_p; - *down_b = (u8 *)rtl8818e_delta_swing_table_idx_24gb_n; + *up_a = rtl8818e_delta_swing_table_idx_24gb_p; + *down_a = rtl8818e_delta_swing_table_idx_24gb_n; } return; } @@ -2075,16 +2032,13 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter( /* 1. The following TWO tables decide the final * index of OFDM/CCK swing table. */ - u8 *delta_swing_table_idx_tup_a; - u8 *delta_swing_table_idx_tdown_a; - u8 *delta_swing_table_idx_tup_b; - u8 *delta_swing_table_idx_tdown_b; + const u8 *delta_swing_table_idx_tup_a; + const u8 *delta_swing_table_idx_tdown_a; /*2. Initilization ( 7 steps in total )*/ - rtl8821ae_get_delta_swing_table(hw, (u8 **)&delta_swing_table_idx_tup_a, - (u8 **)&delta_swing_table_idx_tdown_a, - (u8 **)&delta_swing_table_idx_tup_b, - (u8 **)&delta_swing_table_idx_tdown_b); + rtl8821ae_get_delta_swing_table(hw, + &delta_swing_table_idx_tup_a, + &delta_swing_table_idx_tdown_a); rtldm->txpower_trackinginit = true; diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index c66c6dc00378..d05e709536ea 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -680,8 +680,10 @@ static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw) tasklet_kill(&rtlusb->rx_work_tasklet); cancel_work_sync(&rtlpriv->works.lps_change_work); - flush_workqueue(rtlpriv->works.rtl_wq); - destroy_workqueue(rtlpriv->works.rtl_wq); + if (rtlpriv->works.rtl_wq) { + destroy_workqueue(rtlpriv->works.rtl_wq); + rtlpriv->works.rtl_wq = NULL; + } skb_queue_purge(&rtlusb->rx_queue); @@ -718,8 +720,11 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw) usb_anchor_urb(urb, &rtlusb->rx_submitted); err = usb_submit_urb(urb, GFP_KERNEL); - if (err) + if (err) { + usb_unanchor_urb(urb); + usb_free_urb(urb); goto err_out; + } usb_free_urb(urb); } return 0; @@ -1082,6 +1087,7 @@ error_out2: usb_put_dev(udev); complete(&rtlpriv->firmware_loading_complete); kfree(rtlpriv->usb_data); + ieee80211_free_hw(hw); return -ENODEV; } EXPORT_SYMBOL(rtl_usb_probe); diff --git a/drivers/net/wireless/realtek/rtw88/Kconfig b/drivers/net/wireless/realtek/rtw88/Kconfig index ca894c4f96ac..e3d7cb6c1290 100644 --- a/drivers/net/wireless/realtek/rtw88/Kconfig +++ b/drivers/net/wireless/realtek/rtw88/Kconfig @@ -25,6 +25,9 @@ config RTW88_8822C config RTW88_8723D tristate +config RTW88_8821C + tristate + config RTW88_8822BE tristate "Realtek 8822BE PCI wireless network adapter" depends on PCI @@ -58,6 +61,17 @@ config RTW88_8723DE 802.11n PCIe wireless network adapter +config RTW88_8821CE + tristate "Realtek 8821CE PCI wireless network adapter" + depends on PCI + select RTW88_CORE + select RTW88_PCI + select RTW88_8821C + help + Select this option will enable support for 8821CE chipset + + 802.11ac PCIe wireless network adapter + config RTW88_DEBUG bool "Realtek rtw88 debug support" depends on RTW88_CORE diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index f31e78a6f146..c0e4b111c8b4 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -37,5 +37,11 @@ rtw88_8723d-objs := rtw8723d.o rtw8723d_table.o obj-$(CONFIG_RTW88_8723DE) += rtw88_8723de.o rtw88_8723de-objs := rtw8723de.o +obj-$(CONFIG_RTW88_8821C) += rtw88_8821c.o +rtw88_8821c-objs := rtw8821c.o rtw8821c_table.o + +obj-$(CONFIG_RTW88_8821CE) += rtw88_8821ce.o +rtw88_8821ce-objs := rtw8821ce.o + obj-$(CONFIG_RTW88_PCI) += rtw88_pci.o rtw88_pci-objs := pci.o diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c index 8a070d5d9174..aff70e4ae028 100644 --- a/drivers/net/wireless/realtek/rtw88/bf.c +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -183,7 +183,7 @@ void rtw_bf_del_sounding(struct rtw_dev *rtwdev) void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, struct rtw_bfee *bfee) { - u8 nc_index = 1; + u8 nc_index = hweight8(rtwdev->hal.antenna_rx) - 1; u8 nr_index = bfee->sound_dim; u8 grouping = 0, codebookinfo = 1, coefficientsize = 3; u32 addr_bfer_info, addr_csi_rpt, csi_param; @@ -231,7 +231,8 @@ void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, { struct rtw_bf_info *bf_info = &rtwdev->bf_info; struct mu_bfer_init_para param; - u8 nc_index = 1, nr_index = 1; + u8 nc_index = hweight8(rtwdev->hal.antenna_rx) - 1; + u8 nr_index = 1; u8 grouping = 0, codebookinfo = 1, coefficientsize = 0; u32 csi_param; diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index cbf3d503df1c..aa08fd7d9fcd 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -378,6 +378,7 @@ static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) struct rtw_chip_info *chip = rtwdev->chip; struct rtw_traffic_stats *stats = &rtwdev->stats; bool is_5G = false; + bool wl_busy = false; bool scan = false, link = false; int i; u8 rssi_state; @@ -386,7 +387,16 @@ static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags); coex_stat->wl_connected = !!rtwdev->sta_cnt; - coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + + wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + if (wl_busy != coex_stat->wl_gl_busy) { + if (wl_busy) + coex_stat->wl_gl_busy = true; + else + ieee80211_queue_delayed_work(rtwdev->hw, + &coex->wl_remain_work, + 12 * HZ); + } if (stats->tx_throughput > stats->rx_throughput) coex_stat->wl_tput_dir = COEX_WL_TPUT_TX; @@ -888,10 +898,12 @@ static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase) { struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_coex_stat *coex_stat = &coex->stat; struct rtw_chip_info *chip = rtwdev->chip; struct rtw_efuse *efuse = &rtwdev->efuse; u8 n, type; bool turn_on; + bool wl_busy = false; if (tcase & TDMA_4SLOT)/* 4-slot (50ms) mode */ rtw_coex_tdma_timer_base(rtwdev, 3); @@ -909,13 +921,18 @@ static void rtw_coex_tdma(struct rtw_dev *rtwdev, bool force, u32 tcase) } } - if (turn_on) { - /* enable TBTT interrupt */ + /* enable TBTT interrupt */ + if (turn_on) rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); - rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true); - } else { + + wl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + + if ((coex_stat->bt_a2dp_exist && + (coex_stat->bt_inq_remain || coex_stat->bt_multi_link)) || + !wl_busy) rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, false); - } + else + rtw_coex_write_scbd(rtwdev, COEX_SCBD_TDMA, true); if (efuse->share_ant) { if (type < chip->tdma_sant_num) @@ -1323,20 +1340,31 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) /* Shared-Ant */ if (wl_hi_pri) { table_case = 15; - if (coex_stat->bt_a2dp_exist && - !coex_stat->bt_pan_exist) { - slot_type = TDMA_4SLOT; - tdma_case = 11; - } else if (coex_stat->wl_hi_pri_task1) { + if (coex_stat->bt_profile_num > 0) + tdma_case = 10; + else if (coex_stat->wl_hi_pri_task1) tdma_case = 6; - } else if (!coex_stat->bt_page) { + else if (!coex_stat->bt_page) tdma_case = 8; - } else { + else tdma_case = 9; + } else if (coex_stat->wl_gl_busy) { + if (coex_stat->bt_profile_num == 0) { + table_case = 12; + tdma_case = 18; + } else if (coex_stat->bt_profile_num == 1 && + !coex_stat->bt_a2dp_exist) { + slot_type = TDMA_4SLOT; + table_case = 12; + tdma_case = 20; + } else { + slot_type = TDMA_4SLOT; + table_case = 12; + tdma_case = 26; } } else if (coex_stat->wl_connected) { - table_case = 10; - tdma_case = 10; + table_case = 9; + tdma_case = 27; } else { table_case = 1; tdma_case = 0; @@ -1934,7 +1962,8 @@ static void rtw_coex_run_coex(struct rtw_dev *rtwdev, u8 reason) if (coex_stat->wl_under_ips) return; - if (coex->freeze && !coex_stat->bt_setup_link) + if (coex->freeze && coex_dm->reason == COEX_RSN_BTINFO && + !coex_stat->bt_setup_link) return; coex_stat->cnt_wl[COEX_CNT_WL_COEXRUN]++; @@ -2277,6 +2306,7 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) struct rtw_chip_info *chip = rtwdev->chip; unsigned long bt_relink_time; u8 i, rsp_source = 0, type; + bool inq_page = false; rsp_source = buf[0] & 0xf; if (rsp_source >= COEX_BTINFO_SRC_MAX) @@ -2343,7 +2373,20 @@ void rtw_coex_bt_info_notify(struct rtw_dev *rtwdev, u8 *buf, u8 length) /* 0xff means BT is under WHCK test */ coex_stat->bt_whck_test = (coex_stat->bt_info_lb2 == 0xff); - coex_stat->bt_inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2)); + + inq_page = ((coex_stat->bt_info_lb2 & BIT(2)) == BIT(2)); + + if (inq_page != coex_stat->bt_inq_page) { + cancel_delayed_work_sync(&coex->bt_remain_work); + coex_stat->bt_inq_page = inq_page; + + if (inq_page) + coex_stat->bt_inq_remain = true; + else + ieee80211_queue_delayed_work(rtwdev->hw, + &coex->bt_remain_work, + 4 * HZ); + } coex_stat->bt_acl_busy = ((coex_stat->bt_info_lb2 & BIT(3)) == BIT(3)); coex_stat->cnt_bt[COEX_CNT_BT_RETRY] = coex_stat->bt_info_lb3 & 0xf; if (coex_stat->cnt_bt[COEX_CNT_BT_RETRY] >= 1) @@ -2518,6 +2561,30 @@ void rtw_coex_defreeze_work(struct work_struct *work) mutex_unlock(&rtwdev->mutex); } +void rtw_coex_wl_remain_work(struct work_struct *work) +{ + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, + coex.wl_remain_work.work); + struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; + + mutex_lock(&rtwdev->mutex); + coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + rtw_coex_run_coex(rtwdev, COEX_RSN_WLSTATUS); + mutex_unlock(&rtwdev->mutex); +} + +void rtw_coex_bt_remain_work(struct work_struct *work) +{ + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, + coex.bt_remain_work.work); + struct rtw_coex_stat *coex_stat = &rtwdev->coex.stat; + + mutex_lock(&rtwdev->mutex); + coex_stat->bt_inq_remain = coex_stat->bt_inq_page; + rtw_coex_run_coex(rtwdev, COEX_RSN_BTSTATUS); + mutex_unlock(&rtwdev->mutex); +} + #ifdef CONFIG_RTW88_DEBUGFS #define INFO_SIZE 80 diff --git a/drivers/net/wireless/realtek/rtw88/coex.h b/drivers/net/wireless/realtek/rtw88/coex.h index 4c3a01968f5e..44720fdfc053 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.h +++ b/drivers/net/wireless/realtek/rtw88/coex.h @@ -95,6 +95,7 @@ enum coex_runreason { COEX_RSN_BTINFO = 12, COEX_RSN_LPS = 13, COEX_RSN_WLSTATUS = 14, + COEX_RSN_BTSTATUS = 15, COEX_RSN_MAX }; @@ -362,6 +363,8 @@ void rtw_coex_write_scbd(struct rtw_dev *rtwdev, u16 bitpos, bool set); void rtw_coex_bt_relink_work(struct work_struct *work); void rtw_coex_bt_reenable_work(struct work_struct *work); void rtw_coex_defreeze_work(struct work_struct *work); +void rtw_coex_wl_remain_work(struct work_struct *work); +void rtw_coex_bt_remain_work(struct work_struct *work); void rtw_coex_power_on_setting(struct rtw_dev *rtwdev); void rtw_coex_init_hw_config(struct rtw_dev *rtwdev, bool wifi_only); diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 09f04feb8fe1..f769c982cc91 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -344,6 +344,31 @@ static ssize_t rtw_debugfs_set_write_reg(struct file *filp, return count; } +static ssize_t rtw_debugfs_set_h2c(struct file *filp, + const char __user *buffer, + size_t count, loff_t *loff) +{ + struct rtw_debugfs_priv *debugfs_priv = filp->private_data; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + char tmp[32 + 1]; + u8 param[8]; + int num; + + rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 3); + + num = sscanf(tmp, "%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx,%hhx", + ¶m[0], ¶m[1], ¶m[2], ¶m[3], + ¶m[4], ¶m[5], ¶m[6], ¶m[7]); + if (num != 8) { + rtw_info(rtwdev, "invalid H2C command format for debug\n"); + return -EINVAL; + } + + rtw_fw_h2c_cmd_dbg(rtwdev, param); + + return count; +} + static ssize_t rtw_debugfs_set_rf_write(struct file *filp, const char __user *buffer, size_t count, loff_t *loff) @@ -808,6 +833,10 @@ static struct rtw_debugfs_priv rtw_debug_priv_write_reg = { .cb_write = rtw_debugfs_set_write_reg, }; +static struct rtw_debugfs_priv rtw_debug_priv_h2c = { + .cb_write = rtw_debugfs_set_h2c, +}; + static struct rtw_debugfs_priv rtw_debug_priv_rf_write = { .cb_write = rtw_debugfs_set_rf_write, }; @@ -877,6 +906,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_r(phy_info); rtw_debugfs_add_r(coex_info); rtw_debugfs_add_rw(coex_enable); + rtw_debugfs_add_w(h2c); rtw_debugfs_add_r(mac_0); rtw_debugfs_add_r(mac_1); rtw_debugfs_add_r(mac_2); diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 6478fd7a78f6..63b00bc19000 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -253,6 +253,11 @@ out: spin_unlock(&rtwdev->h2c.lock); } +void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c) +{ + rtw_fw_send_h2c_command(rtwdev, h2c); +} + static void rtw_fw_send_h2c_packet(struct rtw_dev *rtwdev, u8 *h2c_pkt) { int ret; @@ -456,7 +461,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) SET_RA_INFO_INIT_RA_LVL(h2c_pkt, si->init_ra_lv); SET_RA_INFO_SGI_EN(h2c_pkt, si->sgi_enable); SET_RA_INFO_BW_MODE(h2c_pkt, si->bw_mode); - SET_RA_INFO_LDPC(h2c_pkt, si->ldpc_en); + SET_RA_INFO_LDPC(h2c_pkt, !!si->ldpc_en); SET_RA_INFO_NO_UPDATE(h2c_pkt, no_update); SET_RA_INFO_VHT_EN(h2c_pkt, si->vht_enable); SET_RA_INFO_DIS_PT(h2c_pkt, disable_pt); @@ -915,14 +920,14 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, return skb_new; } -static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb) +static void rtw_fill_rsvd_page_desc(struct rtw_dev *rtwdev, struct sk_buff *skb, + enum rtw_rsvd_packet_type type) { - struct rtw_tx_pkt_info pkt_info; + struct rtw_tx_pkt_info pkt_info = {0}; struct rtw_chip_info *chip = rtwdev->chip; u8 *pkt_desc; - memset(&pkt_info, 0, sizeof(pkt_info)); - rtw_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb); + rtw_tx_rsvd_page_pkt_info_update(rtwdev, &pkt_info, skb, type); pkt_desc = skb_push(skb, chip->tx_pkt_desc_sz); memset(pkt_desc, 0, chip->tx_pkt_desc_sz); rtw_tx_fill_tx_desc(&pkt_info, skb); @@ -1261,7 +1266,7 @@ static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, u32 *size) * And iter->len will be added with size of tx_desc_sz. */ if (rsvd_pkt->add_txdesc) - rtw_fill_rsvd_page_desc(rtwdev, iter); + rtw_fill_rsvd_page_desc(rtwdev, iter, rsvd_pkt->type); rsvd_pkt->skb = iter; rsvd_pkt->page = total_page; diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 470e1809645a..686dcd3bbda6 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -563,4 +563,6 @@ void rtw_fw_set_nlo_info(struct rtw_dev *rtwdev, bool enable); void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev, struct cfg80211_ssid *ssid); void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable); +void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c); + #endif diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index c412bc54efde..6b199152abcf 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -231,6 +231,23 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +static int rtw_ops_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype type, bool p2p) +{ + struct rtw_dev *rtwdev = hw->priv; + + rtw_info(rtwdev, "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n", + vif->addr, vif->type, type, vif->p2p, p2p); + + rtw_ops_remove_interface(hw, vif); + + vif->type = type; + vif->p2p = p2p; + + return rtw_ops_add_interface(hw, vif); +} + static void rtw_ops_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *new_flags, @@ -373,6 +390,15 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON) rtw_fw_download_rsvd_page(rtwdev); + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (conf->enable_beacon) + rtw_write32_set(rtwdev, REG_FWHW_TXQ_CTRL, + BIT_EN_BCNQ_DL); + else + rtw_write32_clr(rtwdev, REG_FWHW_TXQ_CTRL, + BIT_EN_BCNQ_DL); + } + if (changed & BSS_CHANGED_MU_GROUPS) rtw_chip_set_gid_table(rtwdev, vif, conf); @@ -827,6 +853,7 @@ const struct ieee80211_ops rtw_ops = { .config = rtw_ops_config, .add_interface = rtw_ops_add_interface, .remove_interface = rtw_ops_remove_interface, + .change_interface = rtw_ops_change_interface, .configure_filter = rtw_ops_configure_filter, .bss_info_changed = rtw_ops_bss_info_changed, .conf_tx = rtw_ops_conf_tx, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 0eefafc51c62..54044abf30d7 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -722,8 +722,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) stbc_en = VHT_STBC_EN; if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC) ldpc_en = VHT_LDPC_EN; - if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80) - is_support_sgi = true; } else if (sta->ht_cap.ht_supported) { ra_mask |= (sta->ht_cap.mcs.rx_mask[1] << 20) | (sta->ht_cap.mcs.rx_mask[0] << 12); @@ -731,9 +729,6 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) stbc_en = HT_STBC_EN; if (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING) ldpc_en = HT_LDPC_EN; - if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20 || - sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) - is_support_sgi = true; } if (efuse->hw_cap.nss == 1) @@ -775,12 +770,18 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_80: bw_mode = RTW_CHANNEL_WIDTH_80; + is_support_sgi = sta->vht_cap.vht_supported && + (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); break; case IEEE80211_STA_RX_BW_40: bw_mode = RTW_CHANNEL_WIDTH_40; + is_support_sgi = sta->ht_cap.ht_supported && + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); break; default: bw_mode = RTW_CHANNEL_WIDTH_20; + is_support_sgi = sta->ht_cap.ht_supported && + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); break; } @@ -935,6 +936,8 @@ void rtw_core_stop(struct rtw_dev *rtwdev) cancel_delayed_work_sync(&coex->bt_relink_work); cancel_delayed_work_sync(&coex->bt_reenable_work); cancel_delayed_work_sync(&coex->defreeze_work); + cancel_delayed_work_sync(&coex->wl_remain_work); + cancel_delayed_work_sync(&coex->bt_remain_work); mutex_lock(&rtwdev->mutex); @@ -989,12 +992,12 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, vht_cap->vht_supported = true; vht_cap->cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_SHORT_GI_80 | - IEEE80211_VHT_CAP_TXSTBC | IEEE80211_VHT_CAP_RXSTBC_1 | IEEE80211_VHT_CAP_HTC_VHT | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | 0; - + if (rtwdev->hal.rf_path_num > 1) + vht_cap->cap |= IEEE80211_VHT_CAP_TXSTBC; vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << @@ -1326,6 +1329,10 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) efuse->share_ant = true; if (efuse->regd == 0xff) efuse->regd = 0; + if (efuse->tx_bb_swing_setting_2g == 0xff) + efuse->tx_bb_swing_setting_2g = 0; + if (efuse->tx_bb_swing_setting_5g == 0xff) + efuse->tx_bb_swing_setting_5g = 0; efuse->btcoex = (efuse->rf_board_option & 0xe0) == 0x20; efuse->ext_pa_2g = efuse->pa_type_2g & BIT(4) ? 1 : 0; @@ -1422,6 +1429,8 @@ int rtw_core_init(struct rtw_dev *rtwdev) INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); + INIT_DELAYED_WORK(&coex->wl_remain_work, rtw_coex_wl_remain_work); + INIT_DELAYED_WORK(&coex->bt_remain_work, rtw_coex_bt_remain_work); INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work); INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); skb_queue_head_init(&rtwdev->c2h_queue); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 0841f5fa4bf2..276b5d381467 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -183,6 +183,7 @@ enum rtw_chip_type { RTW_CHIP_TYPE_8822B, RTW_CHIP_TYPE_8822C, RTW_CHIP_TYPE_8723D, + RTW_CHIP_TYPE_8821C, }; enum rtw_tx_queue_type { @@ -591,6 +592,8 @@ struct rtw_tx_pkt_info { bool dis_qselseq; bool en_hwseq; u8 hw_ssn_sel; + bool nav_use_hdr; + bool bt_null; }; struct rtw_rx_pkt_stat { @@ -1147,6 +1150,9 @@ struct rtw_chip_info { const struct wiphy_wowlan_support *wowlan_stub; const u8 max_sched_scan_ssids; + /* for 8821c set channel */ + u32 ch_param[3]; + /* coex paras */ u32 coex_para_ver; u8 bt_desired_ver; @@ -1263,6 +1269,7 @@ struct rtw_coex_stat { bool bt_link_exist; bool bt_whck_test; bool bt_inq_page; + bool bt_inq_remain; bool bt_inq; bool bt_page; bool bt_ble_voice; @@ -1363,6 +1370,8 @@ struct rtw_coex { struct delayed_work bt_relink_work; struct delayed_work bt_reenable_work; struct delayed_work defreeze_work; + struct delayed_work wl_remain_work; + struct delayed_work bt_remain_work; }; #define DPK_RF_REG_NUM 7 @@ -1462,6 +1471,7 @@ struct rtw_dm_info { u8 thermal_avg[RTW_RF_PATH_MAX]; u8 thermal_meter_k; s8 delta_power_index[RTW_RF_PATH_MAX]; + s8 delta_power_index_last[RTW_RF_PATH_MAX]; u8 default_ofdm_index; bool pwr_trk_triggered; bool pwr_trk_init_trigger; @@ -1479,6 +1489,7 @@ struct rtw_dm_info { /* [bandwidth 0:20M/1:40M][number of path] */ u8 cck_pd_lv[2][RTW_RF_PATH_MAX]; u32 cck_fa_avg; + u8 cck_pd_default; /* save the last rx phy status for debug */ s8 rx_snr[RTW_RF_PATH_MAX]; @@ -1526,6 +1537,8 @@ struct rtw_efuse { u8 apa_type; bool ext_pa_2g; bool ext_pa_5g; + u8 tx_bb_swing_setting_2g; + u8 tx_bb_swing_setting_5g; bool btcoex; /* bt share antenna with wifi */ diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 8228db9a5fc8..3413973bc475 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -14,8 +14,11 @@ #include "debug.h" static bool rtw_disable_msi; +static bool rtw_pci_disable_aspm; module_param_named(disable_msi, rtw_disable_msi, bool, 0644); +module_param_named(disable_aspm, rtw_pci_disable_aspm, bool, 0644); MODULE_PARM_DESC(disable_msi, "Set Y to disable MSI interrupt support"); +MODULE_PARM_DESC(disable_aspm, "Set Y to disable PCI ASPM support"); static u32 rtw_pci_tx_queue_idx_addr[] = { [RTW_TX_QUEUE_BK] = RTK_PCI_TXBD_IDX_BKQ, @@ -1200,6 +1203,9 @@ static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable) u8 value; int ret; + if (rtw_pci_disable_aspm) + return; + ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value); if (ret) { rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret); @@ -1219,6 +1225,9 @@ static void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable) u8 value; int ret; + if (rtw_pci_disable_aspm) + return; + ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value); if (ret) { rtw_err(rtwdev, "failed to read ASPM, ret=%d", ret); diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 5a3e9cc7c400..8f468d6b5f78 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -43,6 +43,8 @@ #define BITS_EF_ADDR (BIT_MASK_EF_ADDR << BIT_SHIFT_EF_ADDR) #define BITS_PLL 0xf0 +#define REG_AFE_XTAL_CTRL 0x24 +#define REG_AFE_PLL_CTRL 0x28 #define REG_AFE_CTRL3 0x2c #define BIT_MASK_XTAL 0x00FFF000 #define BIT_XTAL_GMP_BIT4 BIT(28) @@ -59,6 +61,7 @@ #define BIT_FSPI_EN BIT(19) #define BIT_EN_SIC BIT(12) #define BIT_BT_AOD_GPIO3 BIT(9) +#define BIT_PO_BT_PTA_PINS BIT(9) #define BIT_BT_PTA_EN BIT(5) #define BIT_WLRFE_4_5_EN BIT(2) @@ -476,6 +479,8 @@ #define REG_RFE_CTRL_E 0x0974 #define REG_2ND_CCA_CTRL 0x0976 +#define REG_CCK0_FAREPORT 0xa2c + #define REG_DIS_DPD 0x0a70 #define DIS_DPD_MASK GENMASK(9, 0) #define DIS_DPD_RATE6M BIT(0) diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 4700195c8eef..3ddd170f1651 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1956,13 +1956,13 @@ static const struct coex_table_para table_sant_8723d[] = { {0xa5555555, 0xaaaa5aaa}, {0x6a5a5a5a, 0x5a5a5a5a}, {0x6a5a5a5a, 0x6a5a5a5a}, - {0x65555555, 0x5a5a5a5a}, + {0x66555555, 0x5a5a5a5a}, {0x65555555, 0x6a5a5a5a}, /* case-10 */ {0x65555555, 0xfafafafa}, - {0x65555555, 0x6a5a5aaa}, + {0x66555555, 0x5a5a5aaa}, {0x65555555, 0x5aaa5aaa}, {0x65555555, 0xaaaa5aaa}, - {0x65555555, 0xaaaaaaaa}, /* case-15 */ + {0x66555555, 0xaaaaaaaa}, /* case-15 */ {0xffff55ff, 0xfafafafa}, {0xffff55ff, 0x6afa5afa}, {0xaaffffaa, 0xfafafafa}, @@ -2034,8 +2034,9 @@ static const struct coex_tdma_para tdma_sant_8723d[] = { { {0x51, 0x0c, 0x03, 0x10, 0x54} }, { {0x55, 0x08, 0x03, 0x10, 0x54} }, { {0x65, 0x10, 0x03, 0x11, 0x11} }, - { {0x51, 0x10, 0x03, 0x10, 0x51} }, - { {0x61, 0x15, 0x03, 0x11, 0x10} } + { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ + { {0x51, 0x08, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } }; /* Non-Shared-Antenna TDMA */ @@ -2714,7 +2715,7 @@ struct rtw_chip_info rtw8723d_hw_spec = { .pwr_track_tbl = &rtw8723d_rtw_pwr_track_tbl, .iqk_threshold = 8, - .coex_para_ver = 0x1905302f, + .coex_para_ver = 0x2007022f, .bt_desired_ver = 0x2f, .scbd_support = true, .new_scbd10_def = true, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c new file mode 100644 index 000000000000..d8863d8a5468 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -0,0 +1,1853 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include "main.h" +#include "coex.h" +#include "fw.h" +#include "tx.h" +#include "rx.h" +#include "phy.h" +#include "rtw8821c.h" +#include "rtw8821c_table.h" +#include "mac.h" +#include "reg.h" +#include "debug.h" +#include "bf.h" + +static void rtw8821ce_efuse_parsing(struct rtw_efuse *efuse, + struct rtw8821c_efuse *map) +{ + ether_addr_copy(efuse->addr, map->e.mac_addr); +} + +static int rtw8821c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw8821c_efuse *map; + int i; + + map = (struct rtw8821c_efuse *)log_map; + + efuse->rfe_option = map->rfe_option; + efuse->rf_board_option = map->rf_board_option; + efuse->crystal_cap = map->xtal_k; + efuse->pa_type_2g = map->pa_type; + efuse->pa_type_5g = map->pa_type; + efuse->lna_type_2g = map->lna_type_2g[0]; + efuse->lna_type_5g = map->lna_type_5g[0]; + efuse->channel_plan = map->channel_plan; + efuse->country_code[0] = map->country_code[0]; + efuse->country_code[1] = map->country_code[1]; + efuse->bt_setting = map->rf_bt_setting; + efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[0] = map->thermal_meter; + efuse->thermal_meter_k = map->thermal_meter; + efuse->tx_bb_swing_setting_2g = map->tx_bb_swing_setting_2g; + efuse->tx_bb_swing_setting_5g = map->tx_bb_swing_setting_5g; + + for (i = 0; i < 4; i++) + efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; + + switch (rtw_hci_type(rtwdev)) { + case RTW_HCI_TYPE_PCIE: + rtw8821ce_efuse_parsing(efuse, map); + break; + default: + /* unsupported now */ + return -ENOTSUPP; + } + + return 0; +} + +static const u32 rtw8821c_txscale_tbl[] = { + 0x081, 0x088, 0x090, 0x099, 0x0a2, 0x0ac, 0x0b6, 0x0c0, 0x0cc, 0x0d8, + 0x0e5, 0x0f2, 0x101, 0x110, 0x120, 0x131, 0x143, 0x156, 0x16a, 0x180, + 0x197, 0x1af, 0x1c8, 0x1e3, 0x200, 0x21e, 0x23e, 0x261, 0x285, 0x2ab, + 0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe +}; + +static const u8 rtw8821c_get_swing_index(struct rtw_dev *rtwdev) +{ + u8 i = 0; + u32 swing, table_value; + + swing = rtw_read32_mask(rtwdev, REG_TXSCALE_A, 0xffe00000); + for (i = 0; i < ARRAY_SIZE(rtw8821c_txscale_tbl); i++) { + table_value = rtw8821c_txscale_tbl[i]; + if (swing == table_value) + break; + } + + return i; +} + +static void rtw8821c_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 swing_idx = rtw8821c_get_swing_index(rtwdev); + + if (swing_idx >= ARRAY_SIZE(rtw8821c_txscale_tbl)) + dm_info->default_ofdm_index = 24; + else + dm_info->default_ofdm_index = swing_idx; + + ewma_thermal_init(&dm_info->avg_thermal[RF_PATH_A]); + dm_info->delta_power_index[RF_PATH_A] = 0; + dm_info->delta_power_index_last[RF_PATH_A] = 0; + dm_info->pwr_trk_triggered = false; + dm_info->pwr_trk_init_trigger = true; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; +} + +static void rtw8821c_phy_bf_init(struct rtw_dev *rtwdev) +{ + rtw_bf_phy_init(rtwdev); + /* Grouping bitmap parameters */ + rtw_write32(rtwdev, 0x1C94, 0xAFFFAFFF); +} + +static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev) +{ + u8 crystal_cap, val; + + /* power on BB/RF domain */ + val = rtw_read8(rtwdev, REG_SYS_FUNC_EN); + val |= BIT_FEN_PCIEA; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val); + + /* toggle BB reset */ + val |= BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val); + val &= ~(BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST); + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val); + val |= BIT_FEN_BB_RSTB | BIT_FEN_BB_GLB_RST; + rtw_write8(rtwdev, REG_SYS_FUNC_EN, val); + + rtw_write8(rtwdev, REG_RF_CTRL, + BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB); + usleep_range(10, 11); + rtw_write8(rtwdev, REG_WLRF1 + 3, + BIT_RF_EN | BIT_RF_RSTB | BIT_RF_SDM_RSTB); + usleep_range(10, 11); + + /* pre init before header files config */ + rtw_write32_clr(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); + + rtw_phy_load_tables(rtwdev); + + crystal_cap = rtwdev->efuse.crystal_cap & 0x3F; + rtw_write32_mask(rtwdev, REG_AFE_XTAL_CTRL, 0x7e000000, crystal_cap); + rtw_write32_mask(rtwdev, REG_AFE_PLL_CTRL, 0x7e, crystal_cap); + rtw_write32_mask(rtwdev, REG_CCK0_FAREPORT, BIT(18) | BIT(22), 0); + + /* post init after header files config */ + rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST); + rtwdev->chip->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD); + rtwdev->chip->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD); + rtwdev->chip->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD); + + rtw_phy_init(rtwdev); + rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f; + + rtw8821c_pwrtrack_init(rtwdev); + + rtw8821c_phy_bf_init(rtwdev); +} + +static int rtw8821c_mac_init(struct rtw_dev *rtwdev) +{ + u32 value32; + u16 pre_txcnt; + + /* protocol configuration */ + rtw_write8(rtwdev, REG_AMPDU_MAX_TIME_V1, WLAN_AMPDU_MAX_TIME); + rtw_write8_set(rtwdev, REG_TX_HANG_CTRL, BIT_EN_EOF_V1); + pre_txcnt = WLAN_PRE_TXCNT_TIME_TH | BIT_EN_PRECNT; + rtw_write8(rtwdev, REG_PRECNT_CTRL, (u8)(pre_txcnt & 0xFF)); + rtw_write8(rtwdev, REG_PRECNT_CTRL + 1, (u8)(pre_txcnt >> 8)); + value32 = WLAN_RTS_LEN_TH | (WLAN_RTS_TX_TIME_TH << 8) | + (WLAN_MAX_AGG_PKT_LIMIT << 16) | + (WLAN_RTS_MAX_AGG_PKT_LIMIT << 24); + rtw_write32(rtwdev, REG_PROT_MODE_CTRL, value32); + rtw_write16(rtwdev, REG_BAR_MODE_CTRL + 2, + WLAN_BAR_RETRY_LIMIT | WLAN_RA_TRY_RATE_AGG_LIMIT << 8); + rtw_write8(rtwdev, REG_FAST_EDCA_VOVI_SETTING, FAST_EDCA_VO_TH); + rtw_write8(rtwdev, REG_FAST_EDCA_VOVI_SETTING + 2, FAST_EDCA_VI_TH); + rtw_write8(rtwdev, REG_FAST_EDCA_BEBK_SETTING, FAST_EDCA_BE_TH); + rtw_write8(rtwdev, REG_FAST_EDCA_BEBK_SETTING + 2, FAST_EDCA_BK_TH); + rtw_write8_set(rtwdev, REG_INIRTS_RATE_SEL, BIT(5)); + + /* EDCA configuration */ + rtw_write8_clr(rtwdev, REG_TIMER0_SRC_SEL, BIT_TSFT_SEL_TIMER0); + rtw_write16(rtwdev, REG_TXPAUSE, 0); + rtw_write8(rtwdev, REG_SLOT, WLAN_SLOT_TIME); + rtw_write8(rtwdev, REG_PIFS, WLAN_PIFS_TIME); + rtw_write32(rtwdev, REG_SIFS, WLAN_SIFS_CFG); + rtw_write16(rtwdev, REG_EDCA_VO_PARAM + 2, WLAN_VO_TXOP_LIMIT); + rtw_write16(rtwdev, REG_EDCA_VI_PARAM + 2, WLAN_VI_TXOP_LIMIT); + rtw_write32(rtwdev, REG_RD_NAV_NXT, WLAN_NAV_CFG); + rtw_write16(rtwdev, REG_RXTSF_OFFSET_CCK, WLAN_RX_TSF_CFG); + + /* Set beacon cotnrol - enable TSF and other related functions */ + rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + + /* Set send beacon related registers */ + rtw_write32(rtwdev, REG_TBTT_PROHIBIT, WLAN_TBTT_TIME); + rtw_write8(rtwdev, REG_DRVERLYINT, WLAN_DRV_EARLY_INT); + rtw_write8(rtwdev, REG_BCNDMATIM, WLAN_BCN_DMA_TIME); + rtw_write8_clr(rtwdev, REG_TX_PTCL_CTRL + 1, BIT_SIFS_BK_EN >> 8); + + /* WMAC configuration */ + rtw_write32(rtwdev, REG_RXFLTMAP0, WLAN_RX_FILTER0); + rtw_write16(rtwdev, REG_RXFLTMAP2, WLAN_RX_FILTER2); + rtw_write32(rtwdev, REG_RCR, WLAN_RCR_CFG); + rtw_write8(rtwdev, REG_RX_PKT_LIMIT, WLAN_RXPKT_MAX_SZ_512); + rtw_write8(rtwdev, REG_TCR + 2, WLAN_TX_FUNC_CFG2); + rtw_write8(rtwdev, REG_TCR + 1, WLAN_TX_FUNC_CFG1); + rtw_write8(rtwdev, REG_ACKTO_CCK, 0x40); + rtw_write8_set(rtwdev, REG_WMAC_TRXPTCL_CTL_H, BIT(1)); + rtw_write8_set(rtwdev, REG_SND_PTCL_CTRL, BIT(6)); + rtw_write32(rtwdev, REG_WMAC_OPTION_FUNCTION + 8, WLAN_MAC_OPT_FUNC2); + rtw_write8(rtwdev, REG_WMAC_OPTION_FUNCTION + 4, WLAN_MAC_OPT_NORM_FUNC1); + + return 0; +} + +static void rtw8821c_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) +{ + u8 ldo_pwr; + + ldo_pwr = rtw_read8(rtwdev, REG_LDO_EFUSE_CTRL + 3); + ldo_pwr = enable ? ldo_pwr | BIT(7) : ldo_pwr & ~BIT(7); + rtw_write8(rtwdev, REG_LDO_EFUSE_CTRL + 3, ldo_pwr); +} + +static void rtw8821c_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) +{ + u32 rf_reg18; + + rf_reg18 = rtw_read_rf(rtwdev, RF_PATH_A, 0x18, RFREG_MASK); + + rf_reg18 &= ~(RF18_BAND_MASK | RF18_CHANNEL_MASK | RF18_RFSI_MASK | + RF18_BW_MASK); + + rf_reg18 |= (channel <= 14 ? RF18_BAND_2G : RF18_BAND_5G); + rf_reg18 |= (channel & RF18_CHANNEL_MASK); + + if (channel >= 100 && channel <= 140) + rf_reg18 |= RF18_RFSI_GE; + else if (channel > 140) + rf_reg18 |= RF18_RFSI_GT; + + switch (bw) { + case RTW_CHANNEL_WIDTH_5: + case RTW_CHANNEL_WIDTH_10: + case RTW_CHANNEL_WIDTH_20: + default: + rf_reg18 |= RF18_BW_20M; + break; + case RTW_CHANNEL_WIDTH_40: + rf_reg18 |= RF18_BW_40M; + break; + case RTW_CHANNEL_WIDTH_80: + rf_reg18 |= RF18_BW_80M; + break; + } + + if (channel <= 14) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTDBG, BIT(6), 0x1); + rtw_write_rf(rtwdev, RF_PATH_A, 0x64, 0xf, 0xf); + } else { + rtw_write_rf(rtwdev, RF_PATH_A, RF_LUTDBG, BIT(6), 0x0); + } + + rtw_write_rf(rtwdev, RF_PATH_A, 0x18, RFREG_MASK, rf_reg18); + + rtw_write_rf(rtwdev, RF_PATH_A, RF_XTALX2, BIT(19), 0); + rtw_write_rf(rtwdev, RF_PATH_A, RF_XTALX2, BIT(19), 1); +} + +static void rtw8821c_set_channel_rxdfir(struct rtw_dev *rtwdev, u8 bw) +{ + if (bw == RTW_CHANNEL_WIDTH_40) { + /* RX DFIR for BW40 */ + rtw_write32_mask(rtwdev, REG_ACBB0, BIT(29) | BIT(28), 0x2); + rtw_write32_mask(rtwdev, REG_ACBBRXFIR, BIT(29) | BIT(28), 0x2); + rtw_write32_mask(rtwdev, REG_TXDFIR, BIT(31), 0x0); + rtw_write32_mask(rtwdev, REG_CHFIR, BIT(31), 0x0); + } else if (bw == RTW_CHANNEL_WIDTH_80) { + /* RX DFIR for BW80 */ + rtw_write32_mask(rtwdev, REG_ACBB0, BIT(29) | BIT(28), 0x2); + rtw_write32_mask(rtwdev, REG_ACBBRXFIR, BIT(29) | BIT(28), 0x1); + rtw_write32_mask(rtwdev, REG_TXDFIR, BIT(31), 0x0); + rtw_write32_mask(rtwdev, REG_CHFIR, BIT(31), 0x1); + } else { + /* RX DFIR for BW20, BW10 and BW5 */ + rtw_write32_mask(rtwdev, REG_ACBB0, BIT(29) | BIT(28), 0x2); + rtw_write32_mask(rtwdev, REG_ACBBRXFIR, BIT(29) | BIT(28), 0x2); + rtw_write32_mask(rtwdev, REG_TXDFIR, BIT(31), 0x1); + rtw_write32_mask(rtwdev, REG_CHFIR, BIT(31), 0x0); + } +} + +static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, + u8 primary_ch_idx) +{ + u32 val32; + + if (channel <= 14) { + rtw_write32_mask(rtwdev, REG_RXPSEL, BIT(28), 0x1); + rtw_write32_mask(rtwdev, REG_CCK_CHECK, BIT(7), 0x0); + rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x0); + rtw_write32_mask(rtwdev, REG_RXCCAMSK, 0x0000FC00, 15); + + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0x0); + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x96a); + if (channel == 14) { + rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD, 0x0000b81c); + rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD, 0x0000); + rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667); + } else { + rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD, + rtwdev->chip->ch_param[0]); + rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD, + rtwdev->chip->ch_param[1] & MASKLWORD); + rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, + rtwdev->chip->ch_param[2]); + } + } else if (channel > 35) { + rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1); + rtw_write32_mask(rtwdev, REG_CCK_CHECK, BIT(7), 0x1); + rtw_write32_mask(rtwdev, REG_RXPSEL, BIT(28), 0x0); + rtw_write32_mask(rtwdev, REG_RXCCAMSK, 0x0000FC00, 15); + + if (channel >= 36 && channel <= 64) + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0x1); + else if (channel >= 100 && channel <= 144) + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0x2); + else if (channel >= 149) + rtw_write32_mask(rtwdev, REG_TXSCALE_A, 0xf00, 0x3); + + if (channel >= 36 && channel <= 48) + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x494); + else if (channel >= 52 && channel <= 64) + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x453); + else if (channel >= 100 && channel <= 116) + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x452); + else if (channel >= 118 && channel <= 177) + rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x412); + } + + switch (bw) { + case RTW_CHANNEL_WIDTH_20: + default: + val32 = rtw_read32_mask(rtwdev, REG_ADCCLK, MASKDWORD); + val32 &= 0xffcffc00; + val32 |= 0x10010000; + rtw_write32_mask(rtwdev, REG_ADCCLK, MASKDWORD, val32); + + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x1); + break; + case RTW_CHANNEL_WIDTH_40: + if (primary_ch_idx == 1) + rtw_write32_set(rtwdev, REG_RXSB, BIT(4)); + else + rtw_write32_clr(rtwdev, REG_RXSB, BIT(4)); + + val32 = rtw_read32_mask(rtwdev, REG_ADCCLK, MASKDWORD); + val32 &= 0xff3ff300; + val32 |= 0x20020000 | ((primary_ch_idx & 0xf) << 2) | + RTW_CHANNEL_WIDTH_40; + rtw_write32_mask(rtwdev, REG_ADCCLK, MASKDWORD, val32); + + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x1); + break; + case RTW_CHANNEL_WIDTH_80: + val32 = rtw_read32_mask(rtwdev, REG_ADCCLK, MASKDWORD); + val32 &= 0xfcffcf00; + val32 |= 0x40040000 | ((primary_ch_idx & 0xf) << 2) | + RTW_CHANNEL_WIDTH_80; + rtw_write32_mask(rtwdev, REG_ADCCLK, MASKDWORD, val32); + + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x1); + break; + case RTW_CHANNEL_WIDTH_5: + val32 = rtw_read32_mask(rtwdev, REG_ADCCLK, MASKDWORD); + val32 &= 0xefcefc00; + val32 |= 0x200240; + rtw_write32_mask(rtwdev, REG_ADCCLK, MASKDWORD, val32); + + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x0); + rtw_write32_mask(rtwdev, REG_ADC40, BIT(31), 0x1); + break; + case RTW_CHANNEL_WIDTH_10: + val32 = rtw_read32_mask(rtwdev, REG_ADCCLK, MASKDWORD); + val32 &= 0xefcefc00; + val32 |= 0x300380; + rtw_write32_mask(rtwdev, REG_ADCCLK, MASKDWORD, val32); + + rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x0); + rtw_write32_mask(rtwdev, REG_ADC40, BIT(31), 0x1); + break; + } +} + +static u32 rtw8821c_get_bb_swing(struct rtw_dev *rtwdev, u8 channel) +{ + struct rtw_efuse efuse = rtwdev->efuse; + u8 tx_bb_swing; + u32 swing2setting[4] = {0x200, 0x16a, 0x101, 0x0b6}; + + tx_bb_swing = channel <= 14 ? efuse.tx_bb_swing_setting_2g : + efuse.tx_bb_swing_setting_5g; + if (tx_bb_swing > 9) + tx_bb_swing = 0; + + return swing2setting[(tx_bb_swing / 3)]; +} + +static void rtw8821c_set_channel_bb_swing(struct rtw_dev *rtwdev, u8 channel, + u8 bw, u8 primary_ch_idx) +{ + rtw_write32_mask(rtwdev, REG_TXSCALE_A, GENMASK(31, 21), + rtw8821c_get_bb_swing(rtwdev, channel)); + rtw8821c_pwrtrack_init(rtwdev); +} + +static void rtw8821c_set_channel(struct rtw_dev *rtwdev, u8 channel, u8 bw, + u8 primary_chan_idx) +{ + rtw8821c_set_channel_bb(rtwdev, channel, bw, primary_chan_idx); + rtw8821c_set_channel_bb_swing(rtwdev, channel, bw, primary_chan_idx); + rtw_set_channel_mac(rtwdev, channel, bw, primary_chan_idx); + rtw8821c_set_channel_rf(rtwdev, channel, bw); + rtw8821c_set_channel_rxdfir(rtwdev, bw); +} + +static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + s8 min_rx_power = -120; + u8 pwdb = GET_PHY_STAT_P0_PWDB(phy_status); + + pkt_stat->rx_power[RF_PATH_A] = pwdb - 100; + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); + pkt_stat->bw = RTW_CHANNEL_WIDTH_20; + pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], + min_rx_power); +} + +static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + u8 rxsc, bw; + s8 min_rx_power = -120; + + if (pkt_stat->rate > DESC_RATE11M && pkt_stat->rate < DESC_RATEMCS0) + rxsc = GET_PHY_STAT_P1_L_RXSC(phy_status); + else + rxsc = GET_PHY_STAT_P1_HT_RXSC(phy_status); + + if (rxsc >= 1 && rxsc <= 8) + bw = RTW_CHANNEL_WIDTH_20; + else if (rxsc >= 9 && rxsc <= 12) + bw = RTW_CHANNEL_WIDTH_40; + else if (rxsc >= 13) + bw = RTW_CHANNEL_WIDTH_80; + else + bw = GET_PHY_STAT_P1_RF_MODE(phy_status); + + pkt_stat->rx_power[RF_PATH_A] = GET_PHY_STAT_P1_PWDB_A(phy_status) - 110; + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); + pkt_stat->bw = bw; + pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], + min_rx_power); +} + +static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, + struct rtw_rx_pkt_stat *pkt_stat) +{ + u8 page; + + page = *phy_status & 0xf; + + switch (page) { + case 0: + query_phy_status_page0(rtwdev, phy_status, pkt_stat); + break; + case 1: + query_phy_status_page1(rtwdev, phy_status, pkt_stat); + break; + default: + rtw_warn(rtwdev, "unused phy status page (%d)\n", page); + return; + } +} + +static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_hdr *hdr; + u32 desc_sz = rtwdev->chip->rx_pkt_desc_sz; + u8 *phy_status = NULL; + + memset(pkt_stat, 0, sizeof(*pkt_stat)); + + pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); + pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); + pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); + pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc); + pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); + pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); + pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); + pkt_stat->shift = GET_RX_DESC_SHIFT(rx_desc); + pkt_stat->rate = GET_RX_DESC_RX_RATE(rx_desc); + pkt_stat->cam_id = GET_RX_DESC_MACID(rx_desc); + pkt_stat->ppdu_cnt = GET_RX_DESC_PPDU_CNT(rx_desc); + pkt_stat->tsf_low = GET_RX_DESC_TSFL(rx_desc); + + /* drv_info_sz is in unit of 8-bytes */ + pkt_stat->drv_info_sz *= 8; + + /* c2h cmd pkt's rx/phy status is not interested */ + if (pkt_stat->is_c2h) + return; + + hdr = (struct ieee80211_hdr *)(rx_desc + desc_sz + pkt_stat->shift + + pkt_stat->drv_info_sz); + if (pkt_stat->phy_status) { + phy_status = rx_desc + desc_sz + pkt_stat->shift; + query_phy_status(rtwdev, phy_status, pkt_stat); + } + + rtw_rx_fill_rx_status(rtwdev, pkt_stat, hdr, rx_status, phy_status); +} + +static void +rtw8821c_set_tx_power_index_by_rate(struct rtw_dev *rtwdev, u8 path, u8 rs) +{ + struct rtw_hal *hal = &rtwdev->hal; + static const u32 offset_txagc[2] = {0x1d00, 0x1d80}; + static u32 phy_pwr_idx; + u8 rate, rate_idx, pwr_index, shift; + int j; + + for (j = 0; j < rtw_rate_size[rs]; j++) { + rate = rtw_rate_section[rs][j]; + pwr_index = hal->tx_pwr_tbl[path][rate]; + shift = rate & 0x3; + phy_pwr_idx |= ((u32)pwr_index << (shift * 8)); + if (shift == 0x3 || rate == DESC_RATEVHT1SS_MCS9) { + rate_idx = rate & 0xfc; + rtw_write32(rtwdev, offset_txagc[path] + rate_idx, + phy_pwr_idx); + phy_pwr_idx = 0; + } + } +} + +static void rtw8821c_set_tx_power_index(struct rtw_dev *rtwdev) +{ + struct rtw_hal *hal = &rtwdev->hal; + int rs, path; + + for (path = 0; path < hal->rf_path_num; path++) { + for (rs = 0; rs < RTW_RATE_SECTION_MAX; rs++) { + if (rs == RTW_RATE_SECTION_HT_2S || + rs == RTW_RATE_SECTION_VHT_2S) + continue; + rtw8821c_set_tx_power_index_by_rate(rtwdev, path, rs); + } + } +} + +static void rtw8821c_false_alarm_statistics(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u32 cck_enable; + u32 cck_fa_cnt; + u32 ofdm_fa_cnt; + u32 crc32_cnt; + u32 cca32_cnt; + + cck_enable = rtw_read32(rtwdev, REG_RXPSEL) & BIT(28); + cck_fa_cnt = rtw_read16(rtwdev, REG_FA_CCK); + ofdm_fa_cnt = rtw_read16(rtwdev, REG_FA_OFDM); + + dm_info->cck_fa_cnt = cck_fa_cnt; + dm_info->ofdm_fa_cnt = ofdm_fa_cnt; + if (cck_enable) + dm_info->total_fa_cnt += cck_fa_cnt; + dm_info->total_fa_cnt = ofdm_fa_cnt; + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_CCK); + dm_info->cck_ok_cnt = FIELD_GET(GENMASK(15, 0), crc32_cnt); + dm_info->cck_err_cnt = FIELD_GET(GENMASK(31, 16), crc32_cnt); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_OFDM); + dm_info->ofdm_ok_cnt = FIELD_GET(GENMASK(15, 0), crc32_cnt); + dm_info->ofdm_err_cnt = FIELD_GET(GENMASK(31, 16), crc32_cnt); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_HT); + dm_info->ht_ok_cnt = FIELD_GET(GENMASK(15, 0), crc32_cnt); + dm_info->ht_err_cnt = FIELD_GET(GENMASK(31, 16), crc32_cnt); + + crc32_cnt = rtw_read32(rtwdev, REG_CRC_VHT); + dm_info->vht_ok_cnt = FIELD_GET(GENMASK(15, 0), crc32_cnt); + dm_info->vht_err_cnt = FIELD_GET(GENMASK(31, 16), crc32_cnt); + + cca32_cnt = rtw_read32(rtwdev, REG_CCA_OFDM); + dm_info->ofdm_cca_cnt = FIELD_GET(GENMASK(31, 16), cca32_cnt); + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) { + cca32_cnt = rtw_read32(rtwdev, REG_CCA_CCK); + dm_info->cck_cca_cnt = FIELD_GET(GENMASK(15, 0), cca32_cnt); + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + } + + rtw_write32_set(rtwdev, REG_FAS, BIT(17)); + rtw_write32_clr(rtwdev, REG_FAS, BIT(17)); + rtw_write32_clr(rtwdev, REG_RXDESC, BIT(15)); + rtw_write32_set(rtwdev, REG_RXDESC, BIT(15)); + rtw_write32_set(rtwdev, REG_CNTRST, BIT(0)); + rtw_write32_clr(rtwdev, REG_CNTRST, BIT(0)); +} + +static void rtw8821c_do_iqk(struct rtw_dev *rtwdev) +{ + static int do_iqk_cnt; + struct rtw_iqk_para para = {.clear = 0, .segment_iqk = 0}; + u32 rf_reg, iqk_fail_mask; + int counter; + bool reload; + + if (rtw_is_assoc(rtwdev)) + para.segment_iqk = 1; + + rtw_fw_do_iqk(rtwdev, ¶); + + for (counter = 0; counter < 300; counter++) { + rf_reg = rtw_read_rf(rtwdev, RF_PATH_A, RF_DTXLOK, RFREG_MASK); + if (rf_reg == 0xabcde) + break; + msleep(20); + } + rtw_write_rf(rtwdev, RF_PATH_A, RF_DTXLOK, RFREG_MASK, 0x0); + + reload = !!rtw_read32_mask(rtwdev, REG_IQKFAILMSK, BIT(16)); + iqk_fail_mask = rtw_read32_mask(rtwdev, REG_IQKFAILMSK, GENMASK(7, 0)); + rtw_dbg(rtwdev, RTW_DBG_PHY, + "iqk counter=%d reload=%d do_iqk_cnt=%d n_iqk_fail(mask)=0x%02x\n", + counter, reload, ++do_iqk_cnt, iqk_fail_mask); +} + +static void rtw8821c_phy_calibration(struct rtw_dev *rtwdev) +{ + rtw8821c_do_iqk(rtwdev); +} + +/* for coex */ +static void rtw8821c_coex_cfg_init(struct rtw_dev *rtwdev) +{ + /* enable TBTT nterrupt */ + rtw_write8_set(rtwdev, REG_BCN_CTRL, BIT_EN_BCN_FUNCTION); + + /* BT report packet sample rate */ + rtw_write8_mask(rtwdev, REG_BT_TDMA_TIME, SAMPLE_RATE_MASK, + SAMPLE_RATE); + + /* enable BT counter statistics */ + rtw_write8(rtwdev, REG_BT_STAT_CTRL, BT_CNT_ENABLE); + + /* enable PTA (3-wire function form BT side) */ + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_BT_PTA_EN); + rtw_write32_set(rtwdev, REG_GPIO_MUXCFG, BIT_PO_BT_PTA_PINS); + + /* enable PTA (tx/rx signal form WiFi side) */ + rtw_write8_set(rtwdev, REG_QUEUE_CTRL, BIT_PTA_WL_TX_EN); + /* wl tx signal to PTA not case EDCCA */ + rtw_write8_clr(rtwdev, REG_QUEUE_CTRL, BIT_PTA_EDCCA_EN); + /* GNT_BT=1 while select both */ + rtw_write16_set(rtwdev, REG_BT_COEX_V2, BIT_GNT_BT_POLARITY); + + /* beacon queue always hi-pri */ + rtw_write8_mask(rtwdev, REG_BT_COEX_TABLE_H + 3, BIT_BCN_QUEUE, + BCN_PRI_EN); +} + +static void rtw8821c_coex_cfg_ant_switch(struct rtw_dev *rtwdev, u8 ctrl_type, + u8 pos_type) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + u32 switch_status = FIELD_PREP(CTRL_TYPE_MASK, ctrl_type) | pos_type; + bool polarity_inverse; + u8 regval = 0; + + if (switch_status == coex_dm->cur_switch_status) + return; + + coex_dm->cur_switch_status = switch_status; + + if (coex_rfe->ant_switch_diversity && + ctrl_type == COEX_SWITCH_CTRL_BY_BBSW) + ctrl_type = COEX_SWITCH_CTRL_BY_ANTDIV; + + polarity_inverse = (coex_rfe->ant_switch_polarity == 1); + + switch (ctrl_type) { + default: + case COEX_SWITCH_CTRL_BY_BBSW: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + /* BB SW, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */ + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, + DPDT_CTRL_PIN); + + if (pos_type == COEX_SWITCH_TO_WLG_BT) { + if (coex_rfe->rfe_module_type != 0x4 && + coex_rfe->rfe_module_type != 0x2) + regval = 0x3; + else + regval = (!polarity_inverse ? 0x2 : 0x1); + } else if (pos_type == COEX_SWITCH_TO_WLG) { + regval = (!polarity_inverse ? 0x2 : 0x1); + } else { + regval = (!polarity_inverse ? 0x1 : 0x2); + } + + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15, + regval); + break; + case COEX_SWITCH_CTRL_BY_PTA: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + /* PTA, DPDT use RFE_ctrl8 and RFE_ctrl9 as ctrl pin */ + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, + PTA_CTRL_PIN); + + regval = (!polarity_inverse ? 0x2 : 0x1); + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_R_RFE_SEL_15, + regval); + break; + case COEX_SWITCH_CTRL_BY_ANTDIV: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + rtw_write8_mask(rtwdev, REG_RFE_CTRL8, BIT_MASK_RFE_SEL89, + ANTDIC_CTRL_PIN); + break; + case COEX_SWITCH_CTRL_BY_MAC: + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + + regval = (!polarity_inverse ? 0x0 : 0x1); + rtw_write8_mask(rtwdev, REG_PAD_CTRL1, BIT_SW_DPDT_SEL_DATA, + regval); + break; + case COEX_SWITCH_CTRL_BY_FW: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_set(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + break; + case COEX_SWITCH_CTRL_BY_BT: + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_SEL_EN); + rtw_write32_clr(rtwdev, REG_LED_CFG, BIT_DPDT_WL_SEL); + break; + } + + if (ctrl_type == COEX_SWITCH_CTRL_BY_BT) { + rtw_write32_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1); + rtw_write32_clr(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2); + } else { + rtw_write32_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE1); + rtw_write32_set(rtwdev, REG_CTRL_TYPE, BIT_CTRL_TYPE2); + } +} + +static void rtw8821c_coex_cfg_gnt_fix(struct rtw_dev *rtwdev) +{} + +static void rtw8821c_coex_cfg_gnt_debug(struct rtw_dev *rtwdev) +{ + rtw_write32_clr(rtwdev, REG_PAD_CTRL1, BIT_BTGP_SPI_EN); + rtw_write32_clr(rtwdev, REG_PAD_CTRL1, BIT_BTGP_JTAG_EN); + rtw_write32_clr(rtwdev, REG_GPIO_MUXCFG, BIT_FSPI_EN); + rtw_write32_clr(rtwdev, REG_PAD_CTRL1, BIT_LED1DIS); + rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_SDIO_INT); + rtw_write32_clr(rtwdev, REG_SYS_SDIO_CTRL, BIT_DBG_GNT_WL_BT); +} + +static void rtw8821c_coex_cfg_rfe_type(struct rtw_dev *rtwdev) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_rfe *coex_rfe = &coex->rfe; + struct rtw_efuse *efuse = &rtwdev->efuse; + + coex_rfe->rfe_module_type = efuse->rfe_option; + coex_rfe->ant_switch_polarity = 0; + coex_rfe->ant_switch_exist = true; + coex_rfe->wlg_at_btg = false; + + switch (coex_rfe->rfe_module_type) { + case 0: + case 8: + case 1: + case 9: /* 1-Ant, Main, WLG */ + default: /* 2-Ant, DPDT, WLG */ + break; + case 2: + case 10: /* 1-Ant, Main, BTG */ + case 7: + case 15: /* 2-Ant, DPDT, BTG */ + coex_rfe->wlg_at_btg = true; + break; + case 3: + case 11: /* 1-Ant, Aux, WLG */ + coex_rfe->ant_switch_polarity = 1; + break; + case 4: + case 12: /* 1-Ant, Aux, BTG */ + coex_rfe->wlg_at_btg = true; + coex_rfe->ant_switch_polarity = 1; + break; + case 5: + case 13: /* 2-Ant, no switch, WLG */ + case 6: + case 14: /* 2-Ant, no antenna switch, WLG */ + coex_rfe->ant_switch_exist = false; + break; + } +} + +static void rtw8821c_coex_cfg_wl_tx_power(struct rtw_dev *rtwdev, u8 wl_pwr) +{ + struct rtw_coex *coex = &rtwdev->coex; + struct rtw_coex_dm *coex_dm = &coex->dm; + struct rtw_efuse *efuse = &rtwdev->efuse; + bool share_ant = efuse->share_ant; + + if (share_ant) + return; + + if (wl_pwr == coex_dm->cur_wl_pwr_lvl) + return; + + coex_dm->cur_wl_pwr_lvl = wl_pwr; +} + +static void rtw8821c_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) +{} + +static void +rtw8821c_txagc_swing_offset(struct rtw_dev *rtwdev, u8 pwr_idx_offset, + s8 pwr_idx_offset_lower, + s8 *txagc_idx, u8 *swing_idx) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + s8 delta_pwr_idx = dm_info->delta_power_index[RF_PATH_A]; + u8 swing_upper_bound = dm_info->default_ofdm_index + 10; + u8 swing_lower_bound = 0; + u8 max_pwr_idx_offset = 0xf; + s8 agc_index = 0; + u8 swing_index = dm_info->default_ofdm_index; + + pwr_idx_offset = min_t(u8, pwr_idx_offset, max_pwr_idx_offset); + pwr_idx_offset_lower = max_t(s8, pwr_idx_offset_lower, -15); + + if (delta_pwr_idx >= 0) { + if (delta_pwr_idx <= pwr_idx_offset) { + agc_index = delta_pwr_idx; + swing_index = dm_info->default_ofdm_index; + } else if (delta_pwr_idx > pwr_idx_offset) { + agc_index = pwr_idx_offset; + swing_index = dm_info->default_ofdm_index + + delta_pwr_idx - pwr_idx_offset; + swing_index = min_t(u8, swing_index, swing_upper_bound); + } + } else if (delta_pwr_idx < 0) { + if (delta_pwr_idx >= pwr_idx_offset_lower) { + agc_index = delta_pwr_idx; + swing_index = dm_info->default_ofdm_index; + } else if (delta_pwr_idx < pwr_idx_offset_lower) { + if (dm_info->default_ofdm_index > + (pwr_idx_offset_lower - delta_pwr_idx)) + swing_index = dm_info->default_ofdm_index + + delta_pwr_idx - pwr_idx_offset_lower; + else + swing_index = swing_lower_bound; + + agc_index = pwr_idx_offset_lower; + } + } + + if (swing_index >= ARRAY_SIZE(rtw8821c_txscale_tbl)) { + rtw_warn(rtwdev, "swing index overflow\n"); + swing_index = ARRAY_SIZE(rtw8821c_txscale_tbl) - 1; + } + + *txagc_idx = agc_index; + *swing_idx = swing_index; +} + +static void rtw8821c_pwrtrack_set_pwr(struct rtw_dev *rtwdev, u8 pwr_idx_offset, + s8 pwr_idx_offset_lower) +{ + s8 txagc_idx; + u8 swing_idx; + + rtw8821c_txagc_swing_offset(rtwdev, pwr_idx_offset, pwr_idx_offset_lower, + &txagc_idx, &swing_idx); + rtw_write32_mask(rtwdev, REG_TXAGCIDX, GENMASK(6, 1), txagc_idx); + rtw_write32_mask(rtwdev, REG_TXSCALE_A, GENMASK(31, 21), + rtw8821c_txscale_tbl[swing_idx]); +} + +static void rtw8821c_pwrtrack_set(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 pwr_idx_offset, tx_pwr_idx; + s8 pwr_idx_offset_lower; + u8 channel = rtwdev->hal.current_channel; + u8 band_width = rtwdev->hal.current_band_width; + u8 regd = rtwdev->regd.txpwr_regd; + u8 tx_rate = dm_info->tx_rate; + u8 max_pwr_idx = rtwdev->chip->max_power_index; + + tx_pwr_idx = rtw_phy_get_tx_power_index(rtwdev, RF_PATH_A, tx_rate, + band_width, channel, regd); + + tx_pwr_idx = min_t(u8, tx_pwr_idx, max_pwr_idx); + + pwr_idx_offset = max_pwr_idx - tx_pwr_idx; + pwr_idx_offset_lower = 0 - tx_pwr_idx; + + rtw8821c_pwrtrack_set_pwr(rtwdev, pwr_idx_offset, pwr_idx_offset_lower); +} + +static void rtw8821c_phy_pwrtrack(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_swing_table swing_table; + u8 thermal_value, delta; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + if (rtwdev->efuse.thermal_meter[0] == 0xff) + return; + + thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A); + + if (dm_info->pwr_trk_init_trigger) + dm_info->pwr_trk_init_trigger = false; + else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value, + RF_PATH_A)) + goto iqk; + + delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A); + + delta = min_t(u8, delta, RTW_PWR_TRK_TBL_SZ - 1); + + dm_info->delta_power_index[RF_PATH_A] = + rtw_phy_pwrtrack_get_pwridx(rtwdev, &swing_table, RF_PATH_A, + RF_PATH_A, delta); + if (dm_info->delta_power_index[RF_PATH_A] == + dm_info->delta_power_index_last[RF_PATH_A]) + goto iqk; + else + dm_info->delta_power_index_last[RF_PATH_A] = + dm_info->delta_power_index[RF_PATH_A]; + rtw8821c_pwrtrack_set(rtwdev); + +iqk: + if (rtw_phy_pwrtrack_need_iqk(rtwdev)) + rtw8821c_do_iqk(rtwdev); +} + +static void rtw8821c_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (efuse->power_track_type != 0) + return; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw8821c_phy_pwrtrack(rtwdev); + dm_info->pwr_trk_triggered = false; +} + +static void rtw8821c_bf_config_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_su(rtwdev, bfee); +} + +static void rtw8821c_bf_config_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_mu(rtwdev, bfee); +} + +static void rtw8821c_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (bfee->role == RTW_BFEE_SU) + rtw8821c_bf_config_bfee_su(rtwdev, vif, bfee, enable); + else if (bfee->role == RTW_BFEE_MU) + rtw8821c_bf_config_bfee_mu(rtwdev, vif, bfee, enable); + else + rtw_warn(rtwdev, "wrong bfee role\n"); +} + +static void rtw8821c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 pd[CCK_PD_LV_MAX] = {3, 7, 13, 13, 13}; + + if (dm_info->min_rssi > 60) { + new_lvl = 4; + pd[4] = 0x1d; + goto set_cck_pd; + } + + if (dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] == new_lvl) + return; + + dm_info->cck_fa_avg = CCK_FA_AVG_RESET; + +set_cck_pd: + dm_info->cck_pd_lv[RTW_CHANNEL_WIDTH_20][RF_PATH_A] = new_lvl; + rtw_write32_mask(rtwdev, REG_PWRTH, 0x3f0000, pd[new_lvl]); + rtw_write32_mask(rtwdev, REG_PWRTH2, 0x1f0000, + dm_info->cck_pd_default + new_lvl * 2); +} + +static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8821c[] = { + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x004A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(4) | BIT(7), 0}, + {0x0300, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0301, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static struct rtw_pwr_seq_cmd trans_cardemu_to_act_8821c[] = { + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0001, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_DELAY, 1, RTW_PWR_DELAY_MS}, + {0x0000, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, (BIT(4) | BIT(3) | BIT(2)), 0}, + {0x0075, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), BIT(1)}, + {0x0075, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, (BIT(4) | BIT(3)), 0}, + {0x10C3, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(0), 0}, + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), BIT(3)}, + {0x0074, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0x0022, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0062, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, (BIT(7) | BIT(6) | BIT(5)), + (BIT(7) | BIT(6) | BIT(5))}, + {0x0061, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, (BIT(7) | BIT(6) | BIT(5)), 0}, + {0x007C, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static struct rtw_pwr_seq_cmd trans_act_to_cardemu_8821c[] = { + {0x0093, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0x001F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0049, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0006, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0002, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x10C3, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), BIT(1)}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0x0020, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3), 0}, + {0x0000, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), BIT(5)}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static struct rtw_pwr_seq_cmd trans_cardemu_to_carddis_8821c[] = { + {0x0007, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, 0xFF, 0x20}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), BIT(2)}, + {0x004A, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(5), 0}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), 0}, + {0x004F, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(0), 0}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0046, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(6), BIT(6)}, + {0x0067, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(2), 0}, + {0x0046, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7), BIT(7)}, + {0x0062, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(4), BIT(4)}, + {0x0081, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(7) | BIT(6), 0}, + {0x0005, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3)}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, BIT(0), BIT(0)}, + {0x0086, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_POLLING, BIT(1), 0}, + {0x0090, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_USB_MSK | RTW_PWR_INTF_PCI_MSK, + RTW_PWR_ADDR_MAC, + RTW_PWR_CMD_WRITE, BIT(1), 0}, + {0x0044, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, 0xFF, 0}, + {0x0040, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, 0xFF, 0x90}, + {0x0041, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, 0xFF, 0x00}, + {0x0042, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_SDIO_MSK, + RTW_PWR_ADDR_SDIO, + RTW_PWR_CMD_WRITE, 0xFF, 0x04}, + {0xFFFF, + RTW_PWR_CUT_ALL_MSK, + RTW_PWR_INTF_ALL_MSK, + 0, + RTW_PWR_CMD_END, 0, 0}, +}; + +static const struct rtw_pwr_seq_cmd *card_enable_flow_8821c[] = { + trans_carddis_to_cardemu_8821c, + trans_cardemu_to_act_8821c, + NULL +}; + +static const struct rtw_pwr_seq_cmd *card_disable_flow_8821c[] = { + trans_act_to_cardemu_8821c, + trans_cardemu_to_carddis_8821c, + NULL +}; + +static const struct rtw_intf_phy_para usb2_param_8821c[] = { + {0xFFFF, 0x00, + RTW_IP_SEL_PHY, + RTW_INTF_PHY_CUT_ALL, + RTW_INTF_PHY_PLATFORM_ALL}, +}; + +static const struct rtw_intf_phy_para usb3_param_8821c[] = { + {0xFFFF, 0x0000, + RTW_IP_SEL_PHY, + RTW_INTF_PHY_CUT_ALL, + RTW_INTF_PHY_PLATFORM_ALL}, +}; + +static const struct rtw_intf_phy_para pcie_gen1_param_8821c[] = { + {0x0009, 0x6380, + RTW_IP_SEL_PHY, + RTW_INTF_PHY_CUT_ALL, + RTW_INTF_PHY_PLATFORM_ALL}, + {0xFFFF, 0x0000, + RTW_IP_SEL_PHY, + RTW_INTF_PHY_CUT_ALL, + RTW_INTF_PHY_PLATFORM_ALL}, +}; + +static const struct rtw_intf_phy_para pcie_gen2_param_8821c[] = { + {0xFFFF, 0x0000, + RTW_IP_SEL_PHY, + RTW_INTF_PHY_CUT_ALL, + RTW_INTF_PHY_PLATFORM_ALL}, +}; + +static const struct rtw_intf_phy_para_table phy_para_table_8821c = { + .usb2_para = usb2_param_8821c, + .usb3_para = usb3_param_8821c, + .gen1_para = pcie_gen1_param_8821c, + .gen2_para = pcie_gen2_param_8821c, + .n_usb2_para = ARRAY_SIZE(usb2_param_8821c), + .n_usb3_para = ARRAY_SIZE(usb2_param_8821c), + .n_gen1_para = ARRAY_SIZE(pcie_gen1_param_8821c), + .n_gen2_para = ARRAY_SIZE(pcie_gen2_param_8821c), +}; + +static const struct rtw_rfe_def rtw8821c_rfe_defs[] = { + [0] = RTW_DEF_RFE(8821c, 0, 0), +}; + +static struct rtw_hw_reg rtw8821c_dig[] = { + [0] = { .addr = 0xc50, .mask = 0x7f }, +}; + +static const struct rtw_ltecoex_addr rtw8821c_ltecoex_addr = { + .ctrl = LTECOEX_ACCESS_CTRL, + .wdata = LTECOEX_WRITE_DATA, + .rdata = LTECOEX_READ_DATA, +}; + +static struct rtw_page_table page_table_8821c[] = { + /* not sure what [0] stands for */ + {16, 16, 16, 14, 1}, + {16, 16, 16, 14, 1}, + {16, 16, 0, 0, 1}, + {16, 16, 16, 0, 1}, + {16, 16, 16, 14, 1}, +}; + +static struct rtw_rqpn rqpn_table_8821c[] = { + /* not sure what [0] stands for */ + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_HIGH, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_HIGH, RTW_DMA_MAPPING_HIGH}, + {RTW_DMA_MAPPING_NORMAL, RTW_DMA_MAPPING_NORMAL, + RTW_DMA_MAPPING_LOW, RTW_DMA_MAPPING_LOW, + RTW_DMA_MAPPING_EXTRA, RTW_DMA_MAPPING_HIGH}, +}; + +static struct rtw_prioq_addrs prioq_addrs_8821c = { + .prio[RTW_DMA_MAPPING_EXTRA] = { + .rsvd = REG_FIFOPAGE_INFO_4, .avail = REG_FIFOPAGE_INFO_4 + 2, + }, + .prio[RTW_DMA_MAPPING_LOW] = { + .rsvd = REG_FIFOPAGE_INFO_2, .avail = REG_FIFOPAGE_INFO_2 + 2, + }, + .prio[RTW_DMA_MAPPING_NORMAL] = { + .rsvd = REG_FIFOPAGE_INFO_3, .avail = REG_FIFOPAGE_INFO_3 + 2, + }, + .prio[RTW_DMA_MAPPING_HIGH] = { + .rsvd = REG_FIFOPAGE_INFO_1, .avail = REG_FIFOPAGE_INFO_1 + 2, + }, + .wsize = true, +}; + +static struct rtw_chip_ops rtw8821c_ops = { + .phy_set_param = rtw8821c_phy_set_param, + .read_efuse = rtw8821c_read_efuse, + .query_rx_desc = rtw8821c_query_rx_desc, + .set_channel = rtw8821c_set_channel, + .mac_init = rtw8821c_mac_init, + .read_rf = rtw_phy_read_rf, + .write_rf = rtw_phy_write_rf_reg_sipi, + .set_antenna = NULL, + .set_tx_power_index = rtw8821c_set_tx_power_index, + .cfg_ldo25 = rtw8821c_cfg_ldo25, + .false_alarm_statistics = rtw8821c_false_alarm_statistics, + .phy_calibration = rtw8821c_phy_calibration, + .cck_pd_set = rtw8821c_phy_cck_pd_set, + .pwr_track = rtw8821c_pwr_track, + .config_bfee = rtw8821c_bf_config_bfee, + .set_gid_table = rtw_bf_set_gid_table, + .cfg_csi_rate = rtw_bf_cfg_csi_rate, + + .coex_set_init = rtw8821c_coex_cfg_init, + .coex_set_ant_switch = rtw8821c_coex_cfg_ant_switch, + .coex_set_gnt_fix = rtw8821c_coex_cfg_gnt_fix, + .coex_set_gnt_debug = rtw8821c_coex_cfg_gnt_debug, + .coex_set_rfe_type = rtw8821c_coex_cfg_rfe_type, + .coex_set_wl_tx_power = rtw8821c_coex_cfg_wl_tx_power, + .coex_set_wl_rx_gain = rtw8821c_coex_cfg_wl_rx_gain, +}; + +/* rssi in percentage % (dbm = % - 100) */ +static const u8 wl_rssi_step_8821c[] = {101, 45, 101, 40}; +static const u8 bt_rssi_step_8821c[] = {101, 101, 101, 101}; + +/* Shared-Antenna Coex Table */ +static const struct coex_table_para table_sant_8821c[] = { + {0x55555555, 0x55555555}, /* case-0 */ + {0x55555555, 0x55555555}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xfafafafa, 0xfafafafa}, /* case-5 */ + {0x6a5a5555, 0xaaaaaaaa}, + {0x6a5a56aa, 0x6a5a56aa}, + {0x6a5a5a5a, 0x6a5a5a5a}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-10 */ + {0x66555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0x6aaa6aaa}, + {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0xaaaaaaaa}, /* case-15 */ + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x6afa5afa}, + {0xaaffffaa, 0xfafafafa}, + {0xaa5555aa, 0x5a5a5a5a}, + {0xaa5555aa, 0x6a5a5a5a}, /* case-20 */ + {0xaa5555aa, 0xaaaaaaaa}, + {0xffffffff, 0x55555555}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5a5a}, + {0xffffffff, 0x5a5a5aaa}, /* case-25 */ + {0x55555555, 0x5a5a5a5a}, + {0x55555555, 0xaaaaaaaa}, + {0x66555555, 0x6a5a6a5a}, + {0x66556655, 0x66556655}, + {0x66556aaa, 0x6a5a6aaa}, /* case-30 */ + {0xffffffff, 0x5aaa5aaa}, + {0x56555555, 0x5a5a5aaa} +}; + +/* Non-Shared-Antenna Coex Table */ +static const struct coex_table_para table_nsant_8821c[] = { + {0xffffffff, 0xffffffff}, /* case-100 */ + {0xffff55ff, 0xfafafafa}, + {0x66555555, 0x66555555}, + {0xaaaaaaaa, 0xaaaaaaaa}, + {0x5a5a5a5a, 0x5a5a5a5a}, + {0xffffffff, 0xffffffff}, /* case-105 */ + {0x5afa5afa, 0x5afa5afa}, + {0x55555555, 0xfafafafa}, + {0x66555555, 0xfafafafa}, + {0x66555555, 0x5a5a5a5a}, + {0x66555555, 0x6a5a5a5a}, /* case-110 */ + {0x66555555, 0xaaaaaaaa}, + {0xffff55ff, 0xfafafafa}, + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0xaaaaaaaa}, + {0xffff55ff, 0xffff55ff}, /* case-115 */ + {0xaaffffaa, 0x5afa5afa}, + {0xaaffffaa, 0xaaaaaaaa}, + {0xffffffff, 0xfafafafa}, + {0xffff55ff, 0xfafafafa}, + {0xffffffff, 0xaaaaaaaa}, /* case-120 */ + {0xffff55ff, 0x5afa5afa}, + {0xffff55ff, 0x5afa5afa}, + {0x55ff55ff, 0x55ff55ff} +}; + +/* Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_sant_8821c[] = { + { {0x00, 0x00, 0x00, 0x00, 0x00} }, /* case-0 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, /* case-1 */ + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x3a, 0x03, 0x11, 0x11} }, /* case-5 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x35, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-10 */ + { {0x61, 0x08, 0x03, 0x11, 0x15} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-15 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x11, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x10, 0x03, 0x10, 0x50} }, /* case-20 */ + { {0x51, 0x4a, 0x03, 0x10, 0x50} }, + { {0x51, 0x08, 0x03, 0x30, 0x54} }, + { {0x55, 0x08, 0x03, 0x10, 0x54} }, + { {0x65, 0x10, 0x03, 0x11, 0x10} }, + { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } +}; + +/* Non-Shared-Antenna TDMA */ +static const struct coex_tdma_para tdma_nsant_8821c[] = { + { {0x00, 0x00, 0x00, 0x40, 0x00} }, /* case-100 */ + { {0x61, 0x45, 0x03, 0x11, 0x11} }, + { {0x61, 0x25, 0x03, 0x11, 0x11} }, + { {0x61, 0x35, 0x03, 0x11, 0x11} }, + { {0x61, 0x20, 0x03, 0x11, 0x11} }, + { {0x61, 0x10, 0x03, 0x11, 0x11} }, /* case-105 */ + { {0x61, 0x45, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x30, 0x03, 0x11, 0x10} }, + { {0x61, 0x20, 0x03, 0x11, 0x10} }, + { {0x61, 0x10, 0x03, 0x11, 0x10} }, /* case-110 */ + { {0x61, 0x10, 0x03, 0x11, 0x11} }, + { {0x61, 0x08, 0x03, 0x10, 0x14} }, + { {0x51, 0x08, 0x03, 0x10, 0x54} }, + { {0x51, 0x08, 0x03, 0x10, 0x55} }, + { {0x51, 0x08, 0x07, 0x10, 0x54} }, /* case-115 */ + { {0x51, 0x45, 0x03, 0x10, 0x50} }, + { {0x51, 0x3a, 0x03, 0x10, 0x50} }, + { {0x51, 0x30, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, + { {0x51, 0x21, 0x03, 0x10, 0x50} }, /* case-120 */ + { {0x51, 0x10, 0x03, 0x10, 0x50} } +}; + +static const struct coex_5g_afh_map afh_5g_8821c[] = { {0, 0, 0} }; + +/* wl_tx_dec_power, bt_tx_dec_power, wl_rx_gain, bt_rx_lna_constrain */ +static const struct coex_rf_para rf_para_tx_8821c[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {8, 17, true, 4}, + {7, 18, true, 4}, + {6, 19, true, 4}, + {5, 20, true, 4} +}; + +static const struct coex_rf_para rf_para_rx_8821c[] = { + {0, 0, false, 7}, /* for normal */ + {0, 20, false, 7}, /* for WL-CPT */ + {3, 24, true, 5}, + {2, 26, true, 5}, + {1, 27, true, 5}, + {0, 28, true, 5} +}; + +static_assert(ARRAY_SIZE(rf_para_tx_8821c) == ARRAY_SIZE(rf_para_rx_8821c)); + +static const u8 rtw8821c_pwrtrk_5gb_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 9, 10, 10, + 11, 11, 12, 12, 12, 12, 12}, + {0, 1, 1, 1, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 12, 12, 12}, + {0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 12, 12}, +}; + +static const u8 rtw8821c_pwrtrk_5gb_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, + 12, 12, 12, 12, 12, 12, 12}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 11, + 12, 12, 12, 12, 12, 12, 12, 12}, + {0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 12, 12, 12}, +}; + +static const u8 rtw8821c_pwrtrk_5ga_n[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 8, 8, 9, 9, 9, 10, 10, + 11, 11, 12, 12, 12, 12, 12}, + {0, 1, 1, 1, 2, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 12, 12, 12}, + {0, 1, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 12, 12}, +}; + +static const u8 rtw8821c_pwrtrk_5ga_p[][RTW_PWR_TRK_TBL_SZ] = { + {0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, + 12, 12, 12, 12, 12, 12, 12}, + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 6, 7, 7, 8, 8, 9, 10, 10, 11, 11, + 12, 12, 12, 12, 12, 12, 12, 12}, + {0, 1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 6, 6, 7, 7, 8, 8, 9, 10, 10, 11, + 11, 12, 12, 12, 12, 12, 12, 12}, +}; + +static const u8 rtw8821c_pwrtrk_2gb_n[] = { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9 +}; + +static const u8 rtw8821c_pwrtrk_2gb_p[] = { + 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, + 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9 +}; + +static const u8 rtw8821c_pwrtrk_2ga_n[] = { + 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9 +}; + +static const u8 rtw8821c_pwrtrk_2ga_p[] = { + 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, + 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9 +}; + +static const u8 rtw8821c_pwrtrk_2g_cck_b_n[] = { + 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9 +}; + +static const u8 rtw8821c_pwrtrk_2g_cck_b_p[] = { + 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, + 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9 +}; + +static const u8 rtw8821c_pwrtrk_2g_cck_a_n[] = { + 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9 +}; + +static const u8 rtw8821c_pwrtrk_2g_cck_a_p[] = { + 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, + 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9 +}; + +static const struct rtw_pwr_track_tbl rtw8821c_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[0] = rtw8821c_pwrtrk_5gb_n[0], + .pwrtrk_5gb_n[1] = rtw8821c_pwrtrk_5gb_n[1], + .pwrtrk_5gb_n[2] = rtw8821c_pwrtrk_5gb_n[2], + .pwrtrk_5gb_p[0] = rtw8821c_pwrtrk_5gb_p[0], + .pwrtrk_5gb_p[1] = rtw8821c_pwrtrk_5gb_p[1], + .pwrtrk_5gb_p[2] = rtw8821c_pwrtrk_5gb_p[2], + .pwrtrk_5ga_n[0] = rtw8821c_pwrtrk_5ga_n[0], + .pwrtrk_5ga_n[1] = rtw8821c_pwrtrk_5ga_n[1], + .pwrtrk_5ga_n[2] = rtw8821c_pwrtrk_5ga_n[2], + .pwrtrk_5ga_p[0] = rtw8821c_pwrtrk_5ga_p[0], + .pwrtrk_5ga_p[1] = rtw8821c_pwrtrk_5ga_p[1], + .pwrtrk_5ga_p[2] = rtw8821c_pwrtrk_5ga_p[2], + .pwrtrk_2gb_n = rtw8821c_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8821c_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8821c_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8821c_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8821c_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8821c_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8821c_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8821c_pwrtrk_2g_cck_a_p, +}; + +static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = { + {0xCB0, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCB4, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0xCBA, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x430, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x434, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x42a, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0x426, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x45e, BIT(3), RTW_REG_DOMAIN_MAC8}, + {0x454, MASKLWORD, RTW_REG_DOMAIN_MAC16}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x4c, BIT(24) | BIT(23), RTW_REG_DOMAIN_MAC32}, + {0x64, BIT(0), RTW_REG_DOMAIN_MAC8}, + {0x4c6, BIT(4), RTW_REG_DOMAIN_MAC8}, + {0x40, BIT(5), RTW_REG_DOMAIN_MAC8}, + {0x1, RFREG_MASK, RTW_REG_DOMAIN_RF_A}, + {0, 0, RTW_REG_DOMAIN_NL}, + {0x550, MASKDWORD, RTW_REG_DOMAIN_MAC32}, + {0x522, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x953, BIT(1), RTW_REG_DOMAIN_MAC8}, + {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, + {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8}, +}; + +struct rtw_chip_info rtw8821c_hw_spec = { + .ops = &rtw8821c_ops, + .id = RTW_CHIP_TYPE_8821C, + .fw_name = "rtw88/rtw8821c_fw.bin", + .wlan_cpu = RTW_WCPU_11AC, + .tx_pkt_desc_sz = 48, + .tx_buf_desc_sz = 16, + .rx_pkt_desc_sz = 24, + .rx_buf_desc_sz = 8, + .phy_efuse_size = 512, + .log_efuse_size = 512, + .ptct_efuse_size = 96, + .txff_size = 65536, + .rxff_size = 16384, + .txgi_factor = 1, + .is_pwr_by_rate_dec = true, + .max_power_index = 0x3f, + .csi_buf_pg_num = 0, + .band = RTW_BAND_2G | RTW_BAND_5G, + .page_size = 128, + .dig_min = 0x1c, + .ht_supported = true, + .vht_supported = true, + .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), + .sys_func_en = 0xD8, + .pwr_on_seq = card_enable_flow_8821c, + .pwr_off_seq = card_disable_flow_8821c, + .page_table = page_table_8821c, + .rqpn_table = rqpn_table_8821c, + .prioq_addrs = &prioq_addrs_8821c, + .intf_table = &phy_para_table_8821c, + .dig = rtw8821c_dig, + .rf_base_addr = {0x2800, 0x2c00}, + .rf_sipi_addr = {0xc90, 0xe90}, + .ltecoex_addr = &rtw8821c_ltecoex_addr, + .mac_tbl = &rtw8821c_mac_tbl, + .agc_tbl = &rtw8821c_agc_tbl, + .bb_tbl = &rtw8821c_bb_tbl, + .rf_tbl = {&rtw8821c_rf_a_tbl}, + .rfe_defs = rtw8821c_rfe_defs, + .rfe_defs_size = ARRAY_SIZE(rtw8821c_rfe_defs), + .rx_ldpc = false, + .pwr_track_tbl = &rtw8821c_rtw_pwr_track_tbl, + .iqk_threshold = 8, + .bfer_su_max_num = 2, + .bfer_mu_max_num = 1, + + .coex_para_ver = 0x19092746, + .bt_desired_ver = 0x46, + .scbd_support = true, + .new_scbd10_def = false, + .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, + .bt_rssi_type = COEX_BTRSSI_RATIO, + .ant_isolation = 15, + .rssi_tolerance = 2, + .wl_rssi_step = wl_rssi_step_8821c, + .bt_rssi_step = bt_rssi_step_8821c, + .table_sant_num = ARRAY_SIZE(table_sant_8821c), + .table_sant = table_sant_8821c, + .table_nsant_num = ARRAY_SIZE(table_nsant_8821c), + .table_nsant = table_nsant_8821c, + .tdma_sant_num = ARRAY_SIZE(tdma_sant_8821c), + .tdma_sant = tdma_sant_8821c, + .tdma_nsant_num = ARRAY_SIZE(tdma_nsant_8821c), + .tdma_nsant = tdma_nsant_8821c, + .wl_rf_para_num = ARRAY_SIZE(rf_para_tx_8821c), + .wl_rf_para_tx = rf_para_tx_8821c, + .wl_rf_para_rx = rf_para_rx_8821c, + .bt_afh_span_bw20 = 0x24, + .bt_afh_span_bw40 = 0x36, + .afh_5g_num = ARRAY_SIZE(afh_5g_8821c), + .afh_5g = afh_5g_8821c, + + .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8821c), + .coex_info_hw_regs = coex_info_hw_regs_8821c, +}; +EXPORT_SYMBOL(rtw8821c_hw_spec); + +MODULE_FIRMWARE("rtw88/rtw8821c_fw.bin"); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821c driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.h b/drivers/net/wireless/realtek/rtw88/rtw8821c.h new file mode 100644 index 000000000000..bd01e82b6bcd --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW8821C_H__ +#define __RTW8821C_H__ + +#include <asm/byteorder.h> + +#define RCR_VHT_ACK BIT(26) + +struct rtw8821ce_efuse { + u8 mac_addr[ETH_ALEN]; /* 0xd0 */ + u8 vender_id[2]; + u8 device_id[2]; + u8 sub_vender_id[2]; + u8 sub_device_id[2]; + u8 pmc[2]; + u8 exp_device_cap[2]; + u8 msi_cap; + u8 ltr_cap; /* 0xe3 */ + u8 exp_link_control[2]; + u8 link_cap[4]; + u8 link_control[2]; + u8 serial_number[8]; + u8 res0:2; /* 0xf4 */ + u8 ltr_en:1; + u8 res1:2; + u8 obff:2; + u8 res2:3; + u8 obff_cap:2; + u8 res3:4; + u8 res4[3]; + u8 class_code[3]; + u8 pci_pm_L1_2_supp:1; + u8 pci_pm_L1_1_supp:1; + u8 aspm_pm_L1_2_supp:1; + u8 aspm_pm_L1_1_supp:1; + u8 L1_pm_substates_supp:1; + u8 res5:3; + u8 port_common_mode_restore_time; + u8 port_t_power_on_scale:2; + u8 res6:1; + u8 port_t_power_on_value:5; + u8 res7; +}; + +struct rtw8821c_efuse { + __le16 rtl_id; + u8 res0[0x0e]; + + /* power index for four RF paths */ + struct rtw_txpwr_idx txpwr_idx_table[4]; + + u8 channel_plan; /* 0xb8 */ + u8 xtal_k; + u8 thermal_meter; + u8 iqk_lck; + u8 pa_type; /* 0xbc */ + u8 lna_type_2g[2]; /* 0xbd */ + u8 lna_type_5g[2]; + u8 rf_board_option; + u8 rf_feature_option; + u8 rf_bt_setting; + u8 eeprom_version; + u8 eeprom_customer_id; + u8 tx_bb_swing_setting_2g; + u8 tx_bb_swing_setting_5g; + u8 tx_pwr_calibrate_rate; + u8 rf_antenna_option; /* 0xc9 */ + u8 rfe_option; + u8 country_code[2]; + u8 res[3]; + union { + struct rtw8821ce_efuse e; + }; +}; + +static inline void +_rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) +{ + /* 0xC00-0xCFF and 0xE00-0xEFF have the same layout */ + rtw_write32_mask(rtwdev, addr, mask, data); + rtw_write32_mask(rtwdev, addr + 0x200, mask, data); +} + +#define rtw_write32s_mask(rtwdev, addr, mask, data) \ + do { \ + BUILD_BUG_ON((addr) < 0xC00 || (addr) >= 0xD00); \ + \ + _rtw_write32s_mask(rtwdev, addr, mask, data); \ + } while (0) + +#define BIT_FEN_PCIEA BIT(6) +#define WLAN_SLOT_TIME 0x09 +#define WLAN_PIFS_TIME 0x19 +#define WLAN_SIFS_CCK_CONT_TX 0xA +#define WLAN_SIFS_OFDM_CONT_TX 0xE +#define WLAN_SIFS_CCK_TRX 0x10 +#define WLAN_SIFS_OFDM_TRX 0x10 +#define WLAN_VO_TXOP_LIMIT 0x186 +#define WLAN_VI_TXOP_LIMIT 0x3BC +#define WLAN_RDG_NAV 0x05 +#define WLAN_TXOP_NAV 0x1B +#define WLAN_CCK_RX_TSF 0x30 +#define WLAN_OFDM_RX_TSF 0x30 +#define WLAN_TBTT_PROHIBIT 0x04 +#define WLAN_TBTT_HOLD_TIME 0x064 +#define WLAN_DRV_EARLY_INT 0x04 +#define WLAN_BCN_DMA_TIME 0x02 + +#define WLAN_RX_FILTER0 0x0FFFFFFF +#define WLAN_RX_FILTER2 0xFFFF +#define WLAN_RCR_CFG 0xE400220E +#define WLAN_RXPKT_MAX_SZ 12288 +#define WLAN_RXPKT_MAX_SZ_512 (WLAN_RXPKT_MAX_SZ >> 9) + +#define WLAN_AMPDU_MAX_TIME 0x70 +#define WLAN_RTS_LEN_TH 0xFF +#define WLAN_RTS_TX_TIME_TH 0x08 +#define WLAN_MAX_AGG_PKT_LIMIT 0x20 +#define WLAN_RTS_MAX_AGG_PKT_LIMIT 0x20 +#define FAST_EDCA_VO_TH 0x06 +#define FAST_EDCA_VI_TH 0x06 +#define FAST_EDCA_BE_TH 0x06 +#define FAST_EDCA_BK_TH 0x06 +#define WLAN_BAR_RETRY_LIMIT 0x01 +#define WLAN_RA_TRY_RATE_AGG_LIMIT 0x08 + +#define WLAN_TX_FUNC_CFG1 0x30 +#define WLAN_TX_FUNC_CFG2 0x30 +#define WLAN_MAC_OPT_NORM_FUNC1 0x98 +#define WLAN_MAC_OPT_LB_FUNC1 0x80 +#define WLAN_MAC_OPT_FUNC2 0x30810041 + +#define WLAN_SIFS_CFG (WLAN_SIFS_CCK_CONT_TX | \ + (WLAN_SIFS_OFDM_CONT_TX << BIT_SHIFT_SIFS_OFDM_CTX) | \ + (WLAN_SIFS_CCK_TRX << BIT_SHIFT_SIFS_CCK_TRX) | \ + (WLAN_SIFS_OFDM_TRX << BIT_SHIFT_SIFS_OFDM_TRX)) + +#define WLAN_TBTT_TIME (WLAN_TBTT_PROHIBIT |\ + (WLAN_TBTT_HOLD_TIME << BIT_SHIFT_TBTT_HOLD_TIME_AP)) + +#define WLAN_NAV_CFG (WLAN_RDG_NAV | (WLAN_TXOP_NAV << 16)) +#define WLAN_RX_TSF_CFG (WLAN_CCK_RX_TSF | (WLAN_OFDM_RX_TSF) << 8) +#define WLAN_PRE_TXCNT_TIME_TH 0x1E4 + +/* phy status page0 */ +#define GET_PHY_STAT_P0_PWDB(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8)) + +/* phy status page1 */ +#define GET_PHY_STAT_P1_PWDB_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_PWDB_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(23, 16)) +#define GET_PHY_STAT_P1_RF_MODE(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x03), GENMASK(29, 28)) +#define GET_PHY_STAT_P1_L_RXSC(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8)) +#define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12)) +#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8)) + +#define REG_INIRTS_RATE_SEL 0x0480 +#define REG_HTSTFWT 0x800 +#define REG_RXPSEL 0x808 +#define BIT_RX_PSEL_RST (BIT(28) | BIT(29)) +#define REG_TXPSEL 0x80c +#define REG_RXCCAMSK 0x814 +#define REG_CCASEL 0x82c +#define REG_PDMFTH 0x830 +#define REG_CCA2ND 0x838 +#define REG_L1WT 0x83c +#define REG_L1PKWT 0x840 +#define REG_MRC 0x850 +#define REG_CLKTRK 0x860 +#define REG_ADCCLK 0x8ac +#define REG_ADC160 0x8c4 +#define REG_ADC40 0x8c8 +#define REG_CHFIR 0x8f0 +#define REG_CDDTXP 0x93c +#define REG_TXPSEL1 0x940 +#define REG_ACBB0 0x948 +#define REG_ACBBRXFIR 0x94c +#define REG_ACGG2TBL 0x958 +#define REG_FAS 0x9a4 +#define REG_RXSB 0xa00 +#define REG_ADCINI 0xa04 +#define REG_PWRTH 0xa08 +#define REG_TXSF2 0xa24 +#define REG_TXSF6 0xa28 +#define REG_FA_CCK 0xa5c +#define REG_RXDESC 0xa2c +#define REG_ENTXCCK 0xa80 +#define REG_PWRTH2 0xaa8 +#define REG_CSRATIO 0xaaa +#define REG_TXFILTER 0xaac +#define REG_CNTRST 0xb58 +#define REG_AGCTR_A 0xc08 +#define REG_TXSCALE_A 0xc1c +#define REG_TXDFIR 0xc20 +#define REG_RXIGI_A 0xc50 +#define REG_TXAGCIDX 0xc94 +#define REG_TRSW 0xca0 +#define REG_RFESEL0 0xcb0 +#define REG_RFESEL8 0xcb4 +#define REG_RFECTL 0xcb8 +#define REG_RFEINV 0xcbc +#define REG_AGCTR_B 0xe08 +#define REG_RXIGI_B 0xe50 +#define REG_CRC_CCK 0xf04 +#define REG_CRC_OFDM 0xf14 +#define REG_CRC_HT 0xf10 +#define REG_CRC_VHT 0xf0c +#define REG_CCA_OFDM 0xf08 +#define REG_FA_OFDM 0xf48 +#define REG_CCA_CCK 0xfcc +#define REG_ANTWT 0x1904 +#define REG_IQKFAILMSK 0x1bf0 +#define BIT_MASK_R_RFE_SEL_15 GENMASK(31, 28) +#define BIT_SDIO_INT BIT(18) +#define SAMPLE_RATE_MASK GENMASK(5, 0) +#define SAMPLE_RATE 0x5 +#define BT_CNT_ENABLE 0x1 +#define BIT_BCN_QUEUE BIT(3) +#define BCN_PRI_EN 0x1 +#define PTA_CTRL_PIN 0x66 +#define DPDT_CTRL_PIN 0x77 +#define ANTDIC_CTRL_PIN 0x88 +#define REG_CTRL_TYPE 0x67 +#define BIT_CTRL_TYPE1 BIT(5) +#define BIT_CTRL_TYPE2 BIT(4) +#define CTRL_TYPE_MASK GENMASK(15, 8) + +#define RF18_BAND_MASK (BIT(16) | BIT(9) | BIT(8)) +#define RF18_BAND_2G (0) +#define RF18_BAND_5G (BIT(16) | BIT(8)) +#define RF18_CHANNEL_MASK (MASKBYTE0) +#define RF18_RFSI_MASK (BIT(18) | BIT(17)) +#define RF18_RFSI_GE (BIT(17)) +#define RF18_RFSI_GT (BIT(18)) +#define RF18_BW_MASK (BIT(11) | BIT(10)) +#define RF18_BW_20M (BIT(11) | BIT(10)) +#define RF18_BW_40M (BIT(11)) +#define RF18_BW_80M (BIT(10)) + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8821c_table.c new file mode 100644 index 000000000000..970f903f7dc7 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c_table.c @@ -0,0 +1,6611 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include "main.h" +#include "phy.h" +#include "rtw8821c_table.h" + +static const u32 rtw8821c_mac[] = { + 0x010, 0x00000043, + 0x025, 0x0000001D, + 0x026, 0x000000CE, + 0x04F, 0x00000001, + 0x029, 0x000000F9, + 0x420, 0x00000080, + 0x421, 0x0000000F, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, + 0x431, 0x00000000, + 0x432, 0x00000000, + 0x433, 0x00000001, + 0x434, 0x00000004, + 0x435, 0x00000005, + 0x436, 0x00000007, + 0x437, 0x00000008, + 0x43C, 0x00000004, + 0x43D, 0x00000005, + 0x43E, 0x00000007, + 0x43F, 0x00000008, + 0x440, 0x0000005D, + 0x441, 0x00000001, + 0x442, 0x00000000, + 0x444, 0x00000010, + 0x445, 0x000000F0, + 0x446, 0x00000001, + 0x447, 0x000000FE, + 0x448, 0x00000000, + 0x449, 0x00000000, + 0x44A, 0x00000000, + 0x44B, 0x00000040, + 0x44C, 0x00000010, + 0x44D, 0x000000F0, + 0x44E, 0x0000003F, + 0x44F, 0x00000000, + 0x450, 0x00000000, + 0x451, 0x00000000, + 0x452, 0x00000000, + 0x453, 0x00000040, + 0x455, 0x00000070, + 0x45E, 0x00000004, + 0x49C, 0x00000010, + 0x49D, 0x000000F0, + 0x49E, 0x00000000, + 0x49F, 0x00000006, + 0x4A0, 0x000000E0, + 0x4A1, 0x00000003, + 0x4A2, 0x00000000, + 0x4A3, 0x00000040, + 0x4A4, 0x00000015, + 0x4A5, 0x000000F0, + 0x4A6, 0x00000000, + 0x4A7, 0x00000006, + 0x4A8, 0x000000E0, + 0x4A9, 0x00000000, + 0x4AA, 0x00000000, + 0x4AB, 0x00000000, + 0x7DA, 0x00000008, + 0x1448, 0x00000006, + 0x144A, 0x00000006, + 0x144C, 0x00000006, + 0x144E, 0x00000006, + 0x4C8, 0x000000FF, + 0x4C9, 0x00000008, + 0x4CC, 0x000000FF, + 0x4CD, 0x000000FF, + 0x4CE, 0x00000001, + 0x4CF, 0x00000008, + 0x500, 0x00000026, + 0x501, 0x000000A2, + 0x502, 0x0000002F, + 0x503, 0x00000000, + 0x504, 0x00000028, + 0x505, 0x000000A3, + 0x506, 0x0000005E, + 0x507, 0x00000000, + 0x508, 0x0000002B, + 0x509, 0x000000A4, + 0x50A, 0x0000005E, + 0x50B, 0x00000000, + 0x50C, 0x0000004F, + 0x50D, 0x000000A4, + 0x50E, 0x00000000, + 0x50F, 0x00000000, + 0x512, 0x0000001C, + 0x514, 0x0000000A, + 0x516, 0x0000000A, + 0x521, 0x0000002F, + 0x525, 0x0000004F, + 0x551, 0x00000010, + 0x559, 0x00000002, + 0x55C, 0x00000050, + 0x55D, 0x000000FF, + 0x577, 0x0000000B, + 0x578, 0x00000014, + 0x579, 0x00000014, + 0x57A, 0x00000014, + 0x5BE, 0x00000064, + 0x605, 0x00000030, + 0x608, 0x0000000E, + 0x609, 0x00000022, + 0x60C, 0x00000018, + 0x6A0, 0x000000FF, + 0x6A1, 0x000000FF, + 0x6A2, 0x000000FF, + 0x6A3, 0x000000FF, + 0x6A4, 0x000000FF, + 0x6A5, 0x000000FF, + 0x6DE, 0x00000084, + 0x620, 0x000000FF, + 0x621, 0x000000FF, + 0x622, 0x000000FF, + 0x623, 0x000000FF, + 0x624, 0x000000FF, + 0x625, 0x000000FF, + 0x626, 0x000000FF, + 0x627, 0x000000FF, + 0x638, 0x00000050, + 0x63C, 0x0000000A, + 0x63D, 0x0000000A, + 0x63E, 0x0000000E, + 0x63F, 0x0000000E, + 0x640, 0x00000040, + 0x642, 0x00000040, + 0x643, 0x00000000, + 0x652, 0x000000C8, + 0x66E, 0x00000005, + 0x700, 0x00000021, + 0x701, 0x00000043, + 0x702, 0x00000065, + 0x703, 0x00000087, + 0x708, 0x00000021, + 0x709, 0x00000043, + 0x70A, 0x00000065, + 0x70B, 0x00000087, + 0x718, 0x00000040, + 0x7D4, 0x00000098, + +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821c_mac, rtw_phy_cfg_mac); + +static const u32 rtw8821c_agc[] = { + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000003, + 0x81C, 0xFA020003, + 0x81C, 0xF9040003, + 0x81C, 0xF8060003, + 0x81C, 0xF7080003, + 0x81C, 0xF60A0003, + 0x81C, 0xF50C0003, + 0x81C, 0xF40E0003, + 0x81C, 0xF3100003, + 0x81C, 0xF2120003, + 0x81C, 0xF1140003, + 0x81C, 0xF0160003, + 0x81C, 0xEF180003, + 0x81C, 0xEE1A0003, + 0x81C, 0xED1C0003, + 0x81C, 0xEC1E0003, + 0x81C, 0xEB200003, + 0x81C, 0xEA220003, + 0x81C, 0xE9240003, + 0x81C, 0xE8260003, + 0x81C, 0xE7280003, + 0x81C, 0xE62A0003, + 0x81C, 0xE52C0003, + 0x81C, 0xE42E0003, + 0x81C, 0xE3300003, + 0x81C, 0xE2320003, + 0x81C, 0xE1340003, + 0x81C, 0xC4360003, + 0x81C, 0xC3380003, + 0x81C, 0xC23A0003, + 0x81C, 0xC13C0003, + 0x81C, 0x883E0003, + 0x81C, 0x87400003, + 0x81C, 0x86420003, + 0x81C, 0x85440003, + 0x81C, 0x84460003, + 0x81C, 0x83480003, + 0x81C, 0x824A0003, + 0x81C, 0x814C0003, + 0x81C, 0x804E0003, + 0x81C, 0x64500003, + 0x81C, 0x63520003, + 0x81C, 0x62540003, + 0x81C, 0x61560003, + 0x81C, 0x60580003, + 0x81C, 0x475A0003, + 0x81C, 0x465C0003, + 0x81C, 0x455E0003, + 0x81C, 0x44600003, + 0x81C, 0x43620003, + 0x81C, 0x42640003, + 0x81C, 0x41660003, + 0x81C, 0x40680003, + 0x81C, 0x236A0003, + 0x81C, 0x226C0003, + 0x81C, 0x056E0003, + 0x81C, 0x04700003, + 0x81C, 0x03720003, + 0x81C, 0x02740003, + 0x81C, 0x01760003, + 0x81C, 0x01780003, + 0x81C, 0x017A0003, + 0x81C, 0x017C0003, + 0x81C, 0x017E0003, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000003, + 0x81C, 0xFA020003, + 0x81C, 0xF9040003, + 0x81C, 0xF8060003, + 0x81C, 0xF7080003, + 0x81C, 0xF60A0003, + 0x81C, 0xF50C0003, + 0x81C, 0xF40E0003, + 0x81C, 0xF3100003, + 0x81C, 0xF2120003, + 0x81C, 0xF1140003, + 0x81C, 0xF0160003, + 0x81C, 0xEF180003, + 0x81C, 0xEE1A0003, + 0x81C, 0xED1C0003, + 0x81C, 0xEC1E0003, + 0x81C, 0xEB200003, + 0x81C, 0xEA220003, + 0x81C, 0xE9240003, + 0x81C, 0xE8260003, + 0x81C, 0xE7280003, + 0x81C, 0xE62A0003, + 0x81C, 0xE52C0003, + 0x81C, 0xE42E0003, + 0x81C, 0xE3300003, + 0x81C, 0xE2320003, + 0x81C, 0xE1340003, + 0x81C, 0xC4360003, + 0x81C, 0xC3380003, + 0x81C, 0xC23A0003, + 0x81C, 0xC13C0003, + 0x81C, 0x883E0003, + 0x81C, 0x87400003, + 0x81C, 0x86420003, + 0x81C, 0x85440003, + 0x81C, 0x84460003, + 0x81C, 0x83480003, + 0x81C, 0x824A0003, + 0x81C, 0x814C0003, + 0x81C, 0x804E0003, + 0x81C, 0x64500003, + 0x81C, 0x63520003, + 0x81C, 0x62540003, + 0x81C, 0x61560003, + 0x81C, 0x60580003, + 0x81C, 0x475A0003, + 0x81C, 0x465C0003, + 0x81C, 0x455E0003, + 0x81C, 0x44600003, + 0x81C, 0x43620003, + 0x81C, 0x42640003, + 0x81C, 0x41660003, + 0x81C, 0x40680003, + 0x81C, 0x236A0003, + 0x81C, 0x226C0003, + 0x81C, 0x056E0003, + 0x81C, 0x04700003, + 0x81C, 0x03720003, + 0x81C, 0x02740003, + 0x81C, 0x01760003, + 0x81C, 0x01780003, + 0x81C, 0x017A0003, + 0x81C, 0x017C0003, + 0x81C, 0x017E0003, + 0xA0000000, 0x00000000, + 0x81C, 0xFB000003, + 0x81C, 0xFA020003, + 0x81C, 0xF9040003, + 0x81C, 0xF8060003, + 0x81C, 0xF7080003, + 0x81C, 0xF60A0003, + 0x81C, 0xF50C0003, + 0x81C, 0xF40E0003, + 0x81C, 0xF3100003, + 0x81C, 0xF2120003, + 0x81C, 0xF1140003, + 0x81C, 0xF0160003, + 0x81C, 0xEF180003, + 0x81C, 0xEE1A0003, + 0x81C, 0xED1C0003, + 0x81C, 0xEC1E0003, + 0x81C, 0xEB200003, + 0x81C, 0xEA220003, + 0x81C, 0xE9240003, + 0x81C, 0xE8260003, + 0x81C, 0xE7280003, + 0x81C, 0xE62A0003, + 0x81C, 0xCA2C0003, + 0x81C, 0xC92E0003, + 0x81C, 0xC8300003, + 0x81C, 0xC7320003, + 0x81C, 0xC6340003, + 0x81C, 0xC5360003, + 0x81C, 0xC4380003, + 0x81C, 0xC33A0003, + 0x81C, 0xC23C0003, + 0x81C, 0xC13E0003, + 0x81C, 0x88400003, + 0x81C, 0x87420003, + 0x81C, 0x86440003, + 0x81C, 0x85460003, + 0x81C, 0x84480003, + 0x81C, 0x834A0003, + 0x81C, 0x674C0003, + 0x81C, 0x664E0003, + 0x81C, 0x65500003, + 0x81C, 0x64520003, + 0x81C, 0x63540003, + 0x81C, 0x62560003, + 0x81C, 0x61580003, + 0x81C, 0x455A0003, + 0x81C, 0x445C0003, + 0x81C, 0x435E0003, + 0x81C, 0x42600003, + 0x81C, 0x41620003, + 0x81C, 0x25640003, + 0x81C, 0x24660003, + 0x81C, 0x23680003, + 0x81C, 0x226A0003, + 0x81C, 0x216C0003, + 0x81C, 0x016E0003, + 0x81C, 0x01700003, + 0x81C, 0x01720003, + 0x81C, 0x01740003, + 0x81C, 0x01760003, + 0x81C, 0x01780003, + 0x81C, 0x017A0003, + 0x81C, 0x017C0003, + 0x81C, 0x017E0003, + 0xB0000000, 0x00000000, + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFD000103, + 0x81C, 0xFC020103, + 0x81C, 0xFB040103, + 0x81C, 0xFA060103, + 0x81C, 0xF9080103, + 0x81C, 0xF80A0103, + 0x81C, 0xF70C0103, + 0x81C, 0xF60E0103, + 0x81C, 0xF5100103, + 0x81C, 0xF4120103, + 0x81C, 0xF3140103, + 0x81C, 0xF2160103, + 0x81C, 0xF1180103, + 0x81C, 0xF01A0103, + 0x81C, 0xEF1C0103, + 0x81C, 0xEE1E0103, + 0x81C, 0xED200103, + 0x81C, 0xEC220103, + 0x81C, 0xEB240103, + 0x81C, 0xEA260103, + 0x81C, 0xE9280103, + 0x81C, 0xE82A0103, + 0x81C, 0xE72C0103, + 0x81C, 0xE62E0103, + 0x81C, 0xE5300103, + 0x81C, 0xE4320103, + 0x81C, 0xE3340103, + 0x81C, 0xE2360103, + 0x81C, 0xE1380103, + 0x81C, 0xE03A0103, + 0x81C, 0xC33C0103, + 0x81C, 0xC23E0103, + 0x81C, 0xC1400103, + 0x81C, 0xC0420103, + 0x81C, 0xA3440103, + 0x81C, 0xA2460103, + 0x81C, 0xA1480103, + 0x81C, 0xA04A0103, + 0x81C, 0x824C0103, + 0x81C, 0x814E0103, + 0x81C, 0x80500103, + 0x81C, 0x62520103, + 0x81C, 0x61540103, + 0x81C, 0x60560103, + 0x81C, 0x24580103, + 0x81C, 0x235A0103, + 0x81C, 0x225C0103, + 0x81C, 0x215E0103, + 0x81C, 0x20600103, + 0x81C, 0x03620103, + 0x81C, 0x02640103, + 0x81C, 0x01660103, + 0x81C, 0x01680103, + 0x81C, 0x016A0103, + 0x81C, 0x016C0103, + 0x81C, 0x016E0103, + 0x81C, 0x01700103, + 0x81C, 0x01720103, + 0x81C, 0x01740103, + 0x81C, 0x01760103, + 0x81C, 0x01780103, + 0x81C, 0x017A0103, + 0x81C, 0x017C0103, + 0x81C, 0x017E0103, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xF6000103, + 0x81C, 0xF5020103, + 0x81C, 0xF4040103, + 0x81C, 0xF3060103, + 0x81C, 0xF2080103, + 0x81C, 0xF10A0103, + 0x81C, 0xF00C0103, + 0x81C, 0xEF0E0103, + 0x81C, 0xEE100103, + 0x81C, 0xED120103, + 0x81C, 0xEC140103, + 0x81C, 0xCE160103, + 0x81C, 0xEA180103, + 0x81C, 0xE91A0103, + 0x81C, 0xE81C0103, + 0x81C, 0xE71E0103, + 0x81C, 0xE6200103, + 0x81C, 0xE5220103, + 0x81C, 0xE4240103, + 0x81C, 0xE3260103, + 0x81C, 0xE2280103, + 0x81C, 0xE12A0103, + 0x81C, 0xC32C0103, + 0x81C, 0xA62E0103, + 0x81C, 0xC1300103, + 0x81C, 0xA4320103, + 0x81C, 0xA3340103, + 0x81C, 0xA2360103, + 0x81C, 0xA1380103, + 0x81C, 0x833A0103, + 0x81C, 0x823C0103, + 0x81C, 0x813E0103, + 0x81C, 0x63400103, + 0x81C, 0x62420103, + 0x81C, 0x61440103, + 0x81C, 0x60460103, + 0x81C, 0x25480103, + 0x81C, 0x244A0103, + 0x81C, 0x234C0103, + 0x81C, 0x064E0103, + 0x81C, 0x21500103, + 0x81C, 0x04520103, + 0x81C, 0x03540103, + 0x81C, 0x02560103, + 0x81C, 0x01580103, + 0x81C, 0x005A0103, + 0x81C, 0x005C0103, + 0x81C, 0x005E0103, + 0x81C, 0x00600103, + 0x81C, 0x00620103, + 0x81C, 0x00640103, + 0x81C, 0x00660103, + 0x81C, 0x00680103, + 0x81C, 0x006A0103, + 0x81C, 0x006C0103, + 0x81C, 0x006E0103, + 0x81C, 0x00700103, + 0x81C, 0x00720103, + 0x81C, 0x00740103, + 0x81C, 0x00760103, + 0x81C, 0x00780103, + 0x81C, 0x007A0103, + 0x81C, 0x007C0103, + 0x81C, 0x007E0103, + 0xA0000000, 0x00000000, + 0x81C, 0xFD000103, + 0x81C, 0xFC020103, + 0x81C, 0xFB040103, + 0x81C, 0xFA060103, + 0x81C, 0xF9080103, + 0x81C, 0xF80A0103, + 0x81C, 0xF70C0103, + 0x81C, 0xF60E0103, + 0x81C, 0xF5100103, + 0x81C, 0xF4120103, + 0x81C, 0xF3140103, + 0x81C, 0xF2160103, + 0x81C, 0xF1180103, + 0x81C, 0xF01A0103, + 0x81C, 0xEF1C0103, + 0x81C, 0xEE1E0103, + 0x81C, 0xED200103, + 0x81C, 0xEC220103, + 0x81C, 0xEB240103, + 0x81C, 0xEA260103, + 0x81C, 0xE9280103, + 0x81C, 0xE82A0103, + 0x81C, 0xE72C0103, + 0x81C, 0xE62E0103, + 0x81C, 0xE5300103, + 0x81C, 0xE4320103, + 0x81C, 0xE3340103, + 0x81C, 0xE2360103, + 0x81C, 0xE1380103, + 0x81C, 0xE03A0103, + 0x81C, 0xA83C0103, + 0x81C, 0xA73E0103, + 0x81C, 0xA6400103, + 0x81C, 0xA5420103, + 0x81C, 0xA4440103, + 0x81C, 0xA3460103, + 0x81C, 0xA2480103, + 0x81C, 0xA14A0103, + 0x81C, 0x834C0103, + 0x81C, 0x824E0103, + 0x81C, 0x81500103, + 0x81C, 0x63520103, + 0x81C, 0x62540103, + 0x81C, 0x61560103, + 0x81C, 0x25580103, + 0x81C, 0x245A0103, + 0x81C, 0x235C0103, + 0x81C, 0x225E0103, + 0x81C, 0x04600103, + 0x81C, 0x03620103, + 0x81C, 0x02640103, + 0x81C, 0x01660103, + 0x81C, 0x01680103, + 0x81C, 0x016A0103, + 0x81C, 0x016C0103, + 0x81C, 0x016E0103, + 0x81C, 0x01700103, + 0x81C, 0x01720103, + 0x81C, 0x01740103, + 0x81C, 0x01760103, + 0x81C, 0x01780103, + 0x81C, 0x017A0103, + 0x81C, 0x017C0103, + 0x81C, 0x017E0103, + 0xB0000000, 0x00000000, + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000203, + 0x81C, 0xFA020203, + 0x81C, 0xF9040203, + 0x81C, 0xF8060203, + 0x81C, 0xF7080203, + 0x81C, 0xF60A0203, + 0x81C, 0xF50C0203, + 0x81C, 0xF40E0203, + 0x81C, 0xF3100203, + 0x81C, 0xF2120203, + 0x81C, 0xF1140203, + 0x81C, 0xF0160203, + 0x81C, 0xEF180203, + 0x81C, 0xEE1A0203, + 0x81C, 0xED1C0203, + 0x81C, 0xEC1E0203, + 0x81C, 0xEB200203, + 0x81C, 0xEA220203, + 0x81C, 0xE9240203, + 0x81C, 0xE8260203, + 0x81C, 0xE7280203, + 0x81C, 0xE62A0203, + 0x81C, 0xE52C0203, + 0x81C, 0xE42E0203, + 0x81C, 0xE3300203, + 0x81C, 0xE2320203, + 0x81C, 0xE1340203, + 0x81C, 0xC5360203, + 0x81C, 0xC4380203, + 0x81C, 0xC33A0203, + 0x81C, 0xC23C0203, + 0x81C, 0xC13E0203, + 0x81C, 0xA4400203, + 0x81C, 0xA3420203, + 0x81C, 0xA2440203, + 0x81C, 0xA1460203, + 0x81C, 0xA0480203, + 0x81C, 0x834A0203, + 0x81C, 0x824C0203, + 0x81C, 0x814E0203, + 0x81C, 0x63500203, + 0x81C, 0x62520203, + 0x81C, 0x61540203, + 0x81C, 0x60560203, + 0x81C, 0x23580203, + 0x81C, 0x225A0203, + 0x81C, 0x215C0203, + 0x81C, 0x205E0203, + 0x81C, 0x04600203, + 0x81C, 0x03620203, + 0x81C, 0x02640203, + 0x81C, 0x01660203, + 0x81C, 0x01680203, + 0x81C, 0x016A0203, + 0x81C, 0x016C0203, + 0x81C, 0x016E0203, + 0x81C, 0x01700203, + 0x81C, 0x01720203, + 0x81C, 0x01740203, + 0x81C, 0x01760203, + 0x81C, 0x01780203, + 0x81C, 0x017A0203, + 0x81C, 0x017C0203, + 0x81C, 0x017E0203, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xF6000203, + 0x81C, 0xF5020203, + 0x81C, 0xF4040203, + 0x81C, 0xF3060203, + 0x81C, 0xF2080203, + 0x81C, 0xF10A0203, + 0x81C, 0xF00C0203, + 0x81C, 0xEF0E0203, + 0x81C, 0xEE100203, + 0x81C, 0xED120203, + 0x81C, 0xEC140203, + 0x81C, 0xEB160203, + 0x81C, 0xEA180203, + 0x81C, 0xE91A0203, + 0x81C, 0xE81C0203, + 0x81C, 0xE71E0203, + 0x81C, 0xE6200203, + 0x81C, 0xE5220203, + 0x81C, 0xE4240203, + 0x81C, 0xE3260203, + 0x81C, 0xE2280203, + 0x81C, 0xE12A0203, + 0x81C, 0xE02C0203, + 0x81C, 0xC22E0203, + 0x81C, 0xC1300203, + 0x81C, 0xC0320203, + 0x81C, 0xA3340203, + 0x81C, 0xA2360203, + 0x81C, 0xA1380203, + 0x81C, 0xA03A0203, + 0x81C, 0x833C0203, + 0x81C, 0x823E0203, + 0x81C, 0x81400203, + 0x81C, 0x80420203, + 0x81C, 0x62440203, + 0x81C, 0x61460203, + 0x81C, 0x42480203, + 0x81C, 0x414A0203, + 0x81C, 0x234C0203, + 0x81C, 0x224E0203, + 0x81C, 0x21500203, + 0x81C, 0x20520203, + 0x81C, 0x03540203, + 0x81C, 0x02560203, + 0x81C, 0x01580203, + 0x81C, 0x005A0203, + 0x81C, 0x005C0203, + 0x81C, 0x005E0203, + 0x81C, 0x00600203, + 0x81C, 0x00620203, + 0x81C, 0x00640203, + 0x81C, 0x00660203, + 0x81C, 0x00680203, + 0x81C, 0x006A0203, + 0x81C, 0x006C0203, + 0x81C, 0x006E0203, + 0x81C, 0x00700203, + 0x81C, 0x00720203, + 0x81C, 0x00740203, + 0x81C, 0x00760203, + 0x81C, 0x00780203, + 0x81C, 0x007A0203, + 0x81C, 0x007C0203, + 0x81C, 0x007E0203, + 0xA0000000, 0x00000000, + 0x81C, 0xFC000203, + 0x81C, 0xFB020203, + 0x81C, 0xFA040203, + 0x81C, 0xF9060203, + 0x81C, 0xF8080203, + 0x81C, 0xF70A0203, + 0x81C, 0xF60C0203, + 0x81C, 0xF50E0203, + 0x81C, 0xF4100203, + 0x81C, 0xF3120203, + 0x81C, 0xF2140203, + 0x81C, 0xF1160203, + 0x81C, 0xF0180203, + 0x81C, 0xEF1A0203, + 0x81C, 0xEE1C0203, + 0x81C, 0xED1E0203, + 0x81C, 0xEC200203, + 0x81C, 0xEB220203, + 0x81C, 0xEA240203, + 0x81C, 0xE9260203, + 0x81C, 0xE8280203, + 0x81C, 0xE72A0203, + 0x81C, 0xE62C0203, + 0x81C, 0xE52E0203, + 0x81C, 0xE4300203, + 0x81C, 0xE3320203, + 0x81C, 0xE2340203, + 0x81C, 0xE1360203, + 0x81C, 0xC5380203, + 0x81C, 0xC43A0203, + 0x81C, 0xC33C0203, + 0x81C, 0xC23E0203, + 0x81C, 0xA6400203, + 0x81C, 0xA5420203, + 0x81C, 0xA4440203, + 0x81C, 0xA3460203, + 0x81C, 0xA2480203, + 0x81C, 0x844A0203, + 0x81C, 0x834C0203, + 0x81C, 0x824E0203, + 0x81C, 0x64500203, + 0x81C, 0x63520203, + 0x81C, 0x62540203, + 0x81C, 0x61560203, + 0x81C, 0x60580203, + 0x81C, 0x235A0203, + 0x81C, 0x225C0203, + 0x81C, 0x215E0203, + 0x81C, 0x04600203, + 0x81C, 0x03620203, + 0x81C, 0x02640203, + 0x81C, 0x01660203, + 0x81C, 0x01680203, + 0x81C, 0x016A0203, + 0x81C, 0x016C0203, + 0x81C, 0x016E0203, + 0x81C, 0x01700203, + 0x81C, 0x01720203, + 0x81C, 0x01740203, + 0x81C, 0x01760203, + 0x81C, 0x01780203, + 0x81C, 0x017A0203, + 0x81C, 0x017C0203, + 0x81C, 0x017E0203, + 0xB0000000, 0x00000000, + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000303, + 0x81C, 0xFA020303, + 0x81C, 0xF9040303, + 0x81C, 0xF8060303, + 0x81C, 0xF7080303, + 0x81C, 0xF60A0303, + 0x81C, 0xF50C0303, + 0x81C, 0xF40E0303, + 0x81C, 0xF3100303, + 0x81C, 0xF2120303, + 0x81C, 0xF1140303, + 0x81C, 0xF0160303, + 0x81C, 0xEF180303, + 0x81C, 0xEE1A0303, + 0x81C, 0xED1C0303, + 0x81C, 0xEC1E0303, + 0x81C, 0xEB200303, + 0x81C, 0xEA220303, + 0x81C, 0xE9240303, + 0x81C, 0xE8260303, + 0x81C, 0xE7280303, + 0x81C, 0xE62A0303, + 0x81C, 0xE52C0303, + 0x81C, 0xE42E0303, + 0x81C, 0xE3300303, + 0x81C, 0xE2320303, + 0x81C, 0xE1340303, + 0x81C, 0xC4360303, + 0x81C, 0xC3380303, + 0x81C, 0xC23A0303, + 0x81C, 0xC13C0303, + 0x81C, 0xA53E0303, + 0x81C, 0xA4400303, + 0x81C, 0xA3420303, + 0x81C, 0xA2440303, + 0x81C, 0xA1460303, + 0x81C, 0x83480303, + 0x81C, 0x824A0303, + 0x81C, 0x814C0303, + 0x81C, 0x644E0303, + 0x81C, 0x63500303, + 0x81C, 0x62520303, + 0x81C, 0x61540303, + 0x81C, 0x60560303, + 0x81C, 0x23580303, + 0x81C, 0x225A0303, + 0x81C, 0x215C0303, + 0x81C, 0x045E0303, + 0x81C, 0x03600303, + 0x81C, 0x02620303, + 0x81C, 0x01640303, + 0x81C, 0x01660303, + 0x81C, 0x01680303, + 0x81C, 0x016A0303, + 0x81C, 0x016C0303, + 0x81C, 0x016E0303, + 0x81C, 0x01700303, + 0x81C, 0x01720303, + 0x81C, 0x01740303, + 0x81C, 0x01760303, + 0x81C, 0x01780303, + 0x81C, 0x017A0303, + 0x81C, 0x017C0303, + 0x81C, 0x017E0303, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xF5000303, + 0x81C, 0xF4020303, + 0x81C, 0xF3040303, + 0x81C, 0xF2060303, + 0x81C, 0xF1080303, + 0x81C, 0xF00A0303, + 0x81C, 0xEF0C0303, + 0x81C, 0xEE0E0303, + 0x81C, 0xED100303, + 0x81C, 0xEC120303, + 0x81C, 0xEB140303, + 0x81C, 0xEA160303, + 0x81C, 0xE9180303, + 0x81C, 0xE81A0303, + 0x81C, 0xE71C0303, + 0x81C, 0xE61E0303, + 0x81C, 0xE5200303, + 0x81C, 0xE4220303, + 0x81C, 0xE3240303, + 0x81C, 0xE2260303, + 0x81C, 0xE1280303, + 0x81C, 0xE02A0303, + 0x81C, 0xA72C0303, + 0x81C, 0xA62E0303, + 0x81C, 0xA5300303, + 0x81C, 0xA4320303, + 0x81C, 0xA3340303, + 0x81C, 0xA2360303, + 0x81C, 0xA1380303, + 0x81C, 0xA03A0303, + 0x81C, 0x823C0303, + 0x81C, 0x643E0303, + 0x81C, 0x63400303, + 0x81C, 0x62420303, + 0x81C, 0x61440303, + 0x81C, 0x60460303, + 0x81C, 0x24480303, + 0x81C, 0x234A0303, + 0x81C, 0x224C0303, + 0x81C, 0x054E0303, + 0x81C, 0x04500303, + 0x81C, 0x03520303, + 0x81C, 0x02540303, + 0x81C, 0x01560303, + 0x81C, 0x00580303, + 0x81C, 0x005A0303, + 0x81C, 0x005C0303, + 0x81C, 0x005E0303, + 0x81C, 0x00600303, + 0x81C, 0x00620303, + 0x81C, 0x00640303, + 0x81C, 0x00660303, + 0x81C, 0x00680303, + 0x81C, 0x006A0303, + 0x81C, 0x006C0303, + 0x81C, 0x006E0303, + 0x81C, 0x00700303, + 0x81C, 0x00720303, + 0x81C, 0x00740303, + 0x81C, 0x00760303, + 0x81C, 0x00780303, + 0x81C, 0x007A0303, + 0x81C, 0x007C0303, + 0x81C, 0x007E0303, + 0xA0000000, 0x00000000, + 0x81C, 0xFC000303, + 0x81C, 0xFB020303, + 0x81C, 0xFA040303, + 0x81C, 0xF9060303, + 0x81C, 0xF8080303, + 0x81C, 0xF70A0303, + 0x81C, 0xF60C0303, + 0x81C, 0xF50E0303, + 0x81C, 0xF4100303, + 0x81C, 0xF3120303, + 0x81C, 0xF2140303, + 0x81C, 0xF1160303, + 0x81C, 0xF0180303, + 0x81C, 0xEF1A0303, + 0x81C, 0xEE1C0303, + 0x81C, 0xED1E0303, + 0x81C, 0xEC200303, + 0x81C, 0xEB220303, + 0x81C, 0xEA240303, + 0x81C, 0xE9260303, + 0x81C, 0xE8280303, + 0x81C, 0xE72A0303, + 0x81C, 0xE62C0303, + 0x81C, 0xE52E0303, + 0x81C, 0xE4300303, + 0x81C, 0xE3320303, + 0x81C, 0xE2340303, + 0x81C, 0xE1360303, + 0x81C, 0xC4380303, + 0x81C, 0xC33A0303, + 0x81C, 0xC23C0303, + 0x81C, 0xC13E0303, + 0x81C, 0xA5400303, + 0x81C, 0xA4420303, + 0x81C, 0xA3440303, + 0x81C, 0xA2460303, + 0x81C, 0xA1480303, + 0x81C, 0x834A0303, + 0x81C, 0x824C0303, + 0x81C, 0x814E0303, + 0x81C, 0x64500303, + 0x81C, 0x63520303, + 0x81C, 0x62540303, + 0x81C, 0x61560303, + 0x81C, 0x24580303, + 0x81C, 0x235A0303, + 0x81C, 0x225C0303, + 0x81C, 0x215E0303, + 0x81C, 0x04600303, + 0x81C, 0x03620303, + 0x81C, 0x02640303, + 0x81C, 0x01660303, + 0x81C, 0x01680303, + 0x81C, 0x016A0303, + 0x81C, 0x016C0303, + 0x81C, 0x016E0303, + 0x81C, 0x01700303, + 0x81C, 0x01720303, + 0x81C, 0x01740303, + 0x81C, 0x01760303, + 0x81C, 0x01780303, + 0x81C, 0x017A0303, + 0x81C, 0x017C0303, + 0x81C, 0x017E0303, + 0xB0000000, 0x00000000, + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFC000803, + 0x81C, 0xFB020803, + 0x81C, 0xFA040803, + 0x81C, 0xF9060803, + 0x81C, 0xF8080803, + 0x81C, 0xF70A0803, + 0x81C, 0xF60C0803, + 0x81C, 0xF50E0803, + 0x81C, 0xF4100803, + 0x81C, 0xF3120803, + 0x81C, 0xF2140803, + 0x81C, 0xF1160803, + 0x81C, 0xF0180803, + 0x81C, 0xEF1A0803, + 0x81C, 0xEE1C0803, + 0x81C, 0xED1E0803, + 0x81C, 0xB5200803, + 0x81C, 0xB4220803, + 0x81C, 0xB3240803, + 0x81C, 0xB2260803, + 0x81C, 0xB1280803, + 0x81C, 0xB02A0803, + 0x81C, 0xAF2C0803, + 0x81C, 0xAE2E0803, + 0x81C, 0xAD300803, + 0x81C, 0xAC320803, + 0x81C, 0xAB340803, + 0x81C, 0xAA360803, + 0x81C, 0xA9380803, + 0x81C, 0xA83A0803, + 0x81C, 0xA73C0803, + 0x81C, 0xA63E0803, + 0x81C, 0x88400803, + 0x81C, 0x87420803, + 0x81C, 0x86440803, + 0x81C, 0x85460803, + 0x81C, 0x84480803, + 0x81C, 0x834A0803, + 0x81C, 0x674C0803, + 0x81C, 0x664E0803, + 0x81C, 0x65500803, + 0x81C, 0x64520803, + 0x81C, 0x63540803, + 0x81C, 0x62560803, + 0x81C, 0x61580803, + 0x81C, 0x455A0803, + 0x81C, 0x445C0803, + 0x81C, 0x435E0803, + 0x81C, 0x42600803, + 0x81C, 0x41620803, + 0x81C, 0x25640803, + 0x81C, 0x24660803, + 0x81C, 0x23680803, + 0x81C, 0x226A0803, + 0x81C, 0x216C0803, + 0x81C, 0x016E0803, + 0x81C, 0x01700803, + 0x81C, 0x01720803, + 0x81C, 0x01740803, + 0x81C, 0x01760803, + 0x81C, 0x01780803, + 0x81C, 0x017A0803, + 0x81C, 0x017C0803, + 0x81C, 0x017E0803, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFC000803, + 0x81C, 0xFB020803, + 0x81C, 0xFA040803, + 0x81C, 0xF9060803, + 0x81C, 0xF8080803, + 0x81C, 0xF70A0803, + 0x81C, 0xF60C0803, + 0x81C, 0xF50E0803, + 0x81C, 0xF4100803, + 0x81C, 0xF3120803, + 0x81C, 0xF2140803, + 0x81C, 0xF1160803, + 0x81C, 0xF0180803, + 0x81C, 0xEF1A0803, + 0x81C, 0xEE1C0803, + 0x81C, 0xED1E0803, + 0x81C, 0xB5200803, + 0x81C, 0xB4220803, + 0x81C, 0xB3240803, + 0x81C, 0xB2260803, + 0x81C, 0xB1280803, + 0x81C, 0xB02A0803, + 0x81C, 0xAF2C0803, + 0x81C, 0xAE2E0803, + 0x81C, 0xAD300803, + 0x81C, 0xAC320803, + 0x81C, 0xAB340803, + 0x81C, 0xAA360803, + 0x81C, 0xA9380803, + 0x81C, 0xA83A0803, + 0x81C, 0xA73C0803, + 0x81C, 0xA63E0803, + 0x81C, 0x88400803, + 0x81C, 0x87420803, + 0x81C, 0x86440803, + 0x81C, 0x85460803, + 0x81C, 0x84480803, + 0x81C, 0x834A0803, + 0x81C, 0x674C0803, + 0x81C, 0x664E0803, + 0x81C, 0x65500803, + 0x81C, 0x64520803, + 0x81C, 0x63540803, + 0x81C, 0x62560803, + 0x81C, 0x61580803, + 0x81C, 0x455A0803, + 0x81C, 0x445C0803, + 0x81C, 0x435E0803, + 0x81C, 0x42600803, + 0x81C, 0x41620803, + 0x81C, 0x25640803, + 0x81C, 0x24660803, + 0x81C, 0x23680803, + 0x81C, 0x226A0803, + 0x81C, 0x216C0803, + 0x81C, 0x016E0803, + 0x81C, 0x01700803, + 0x81C, 0x01720803, + 0x81C, 0x01740803, + 0x81C, 0x01760803, + 0x81C, 0x01780803, + 0x81C, 0x017A0803, + 0x81C, 0x017C0803, + 0x81C, 0x017E0803, + 0xA0000000, 0x00000000, + 0x81C, 0xFC000803, + 0x81C, 0xFB020803, + 0x81C, 0xFA040803, + 0x81C, 0xF9060803, + 0x81C, 0xF8080803, + 0x81C, 0xF70A0803, + 0x81C, 0xF60C0803, + 0x81C, 0xF50E0803, + 0x81C, 0xF4100803, + 0x81C, 0xF3120803, + 0x81C, 0xF2140803, + 0x81C, 0xF1160803, + 0x81C, 0xF0180803, + 0x81C, 0xEF1A0803, + 0x81C, 0xEE1C0803, + 0x81C, 0xED1E0803, + 0x81C, 0xB5200803, + 0x81C, 0xB4220803, + 0x81C, 0xB3240803, + 0x81C, 0xB2260803, + 0x81C, 0xB1280803, + 0x81C, 0xB02A0803, + 0x81C, 0xAF2C0803, + 0x81C, 0xAE2E0803, + 0x81C, 0xAD300803, + 0x81C, 0xAC320803, + 0x81C, 0xAB340803, + 0x81C, 0xAA360803, + 0x81C, 0xA9380803, + 0x81C, 0xA83A0803, + 0x81C, 0xA73C0803, + 0x81C, 0xA63E0803, + 0x81C, 0x88400803, + 0x81C, 0x87420803, + 0x81C, 0x86440803, + 0x81C, 0x85460803, + 0x81C, 0x84480803, + 0x81C, 0x834A0803, + 0x81C, 0x674C0803, + 0x81C, 0x664E0803, + 0x81C, 0x65500803, + 0x81C, 0x64520803, + 0x81C, 0x63540803, + 0x81C, 0x62560803, + 0x81C, 0x61580803, + 0x81C, 0x455A0803, + 0x81C, 0x445C0803, + 0x81C, 0x435E0803, + 0x81C, 0x42600803, + 0x81C, 0x41620803, + 0x81C, 0x25640803, + 0x81C, 0x24660803, + 0x81C, 0x23680803, + 0x81C, 0x226A0803, + 0x81C, 0x216C0803, + 0x81C, 0x016E0803, + 0x81C, 0x01700803, + 0x81C, 0x01720803, + 0x81C, 0x01740803, + 0x81C, 0x01760803, + 0x81C, 0x01780803, + 0x81C, 0x017A0803, + 0x81C, 0x017C0803, + 0x81C, 0x017E0803, + 0xB0000000, 0x00000000, + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000913, + 0x81C, 0xFE020913, + 0x81C, 0xFD040913, + 0x81C, 0xFC060913, + 0x81C, 0xFB080913, + 0x81C, 0xFA0A0913, + 0x81C, 0xF90C0913, + 0x81C, 0xF80E0913, + 0x81C, 0xF7100913, + 0x81C, 0xF6120913, + 0x81C, 0xF5140913, + 0x81C, 0xF4160913, + 0x81C, 0xF3180913, + 0x81C, 0xF21A0913, + 0x81C, 0xF11C0913, + 0x81C, 0x941E0913, + 0x81C, 0x93200913, + 0x81C, 0x92220913, + 0x81C, 0x91240913, + 0x81C, 0x90260913, + 0x81C, 0x8F280913, + 0x81C, 0x8E2A0913, + 0x81C, 0x8D2C0913, + 0x81C, 0x8C2E0913, + 0x81C, 0x8B300913, + 0x81C, 0x8A320913, + 0x81C, 0x89340913, + 0x81C, 0x88360913, + 0x81C, 0x87380913, + 0x81C, 0x863A0913, + 0x81C, 0x853C0913, + 0x81C, 0x843E0913, + 0x81C, 0x83400913, + 0x81C, 0x82420913, + 0x81C, 0x81440913, + 0x81C, 0x07460913, + 0x81C, 0x06480913, + 0x81C, 0x054A0913, + 0x81C, 0x044C0913, + 0x81C, 0x034E0913, + 0x81C, 0x02500913, + 0x81C, 0x01520913, + 0x81C, 0x88540903, + 0x81C, 0x87560903, + 0x81C, 0x86580903, + 0x81C, 0x855A0903, + 0x81C, 0x845C0903, + 0x81C, 0x835E0903, + 0x81C, 0x82600903, + 0x81C, 0x81620903, + 0x81C, 0x07640903, + 0x81C, 0x06660903, + 0x81C, 0x05680903, + 0x81C, 0x046A0903, + 0x81C, 0x036C0903, + 0x81C, 0x026E0903, + 0x81C, 0x01700903, + 0x81C, 0x01720903, + 0x81C, 0x01740903, + 0x81C, 0x01760903, + 0x81C, 0x01780903, + 0x81C, 0x017A0903, + 0x81C, 0x017C0903, + 0x81C, 0x017E0903, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFF000913, + 0x81C, 0xFE020913, + 0x81C, 0xFD040913, + 0x81C, 0xFC060913, + 0x81C, 0xFB080913, + 0x81C, 0xFA0A0913, + 0x81C, 0xF90C0913, + 0x81C, 0xF80E0913, + 0x81C, 0xF7100913, + 0x81C, 0xF6120913, + 0x81C, 0xF5140913, + 0x81C, 0xF4160913, + 0x81C, 0xF3180913, + 0x81C, 0xF21A0913, + 0x81C, 0xF11C0913, + 0x81C, 0x941E0913, + 0x81C, 0x93200913, + 0x81C, 0x92220913, + 0x81C, 0x91240913, + 0x81C, 0x90260913, + 0x81C, 0x8F280913, + 0x81C, 0x8E2A0913, + 0x81C, 0x8D2C0913, + 0x81C, 0x8C2E0913, + 0x81C, 0x8B300913, + 0x81C, 0x8A320913, + 0x81C, 0x89340913, + 0x81C, 0x88360913, + 0x81C, 0x87380913, + 0x81C, 0x863A0913, + 0x81C, 0x853C0913, + 0x81C, 0x843E0913, + 0x81C, 0x83400913, + 0x81C, 0x82420913, + 0x81C, 0x81440913, + 0x81C, 0x07460913, + 0x81C, 0x06480913, + 0x81C, 0x054A0913, + 0x81C, 0x044C0913, + 0x81C, 0x034E0913, + 0x81C, 0x02500913, + 0x81C, 0x01520913, + 0x81C, 0x88540903, + 0x81C, 0x87560903, + 0x81C, 0x86580903, + 0x81C, 0x855A0903, + 0x81C, 0x845C0903, + 0x81C, 0x835E0903, + 0x81C, 0x82600903, + 0x81C, 0x81620903, + 0x81C, 0x07640903, + 0x81C, 0x06660903, + 0x81C, 0x05680903, + 0x81C, 0x046A0903, + 0x81C, 0x036C0903, + 0x81C, 0x026E0903, + 0x81C, 0x01700903, + 0x81C, 0x01720903, + 0x81C, 0x01740903, + 0x81C, 0x01760903, + 0x81C, 0x01780903, + 0x81C, 0x017A0903, + 0x81C, 0x017C0903, + 0x81C, 0x017E0903, + 0xA0000000, 0x00000000, + 0x81C, 0xFF000913, + 0x81C, 0xFE020913, + 0x81C, 0xFD040913, + 0x81C, 0xFC060913, + 0x81C, 0xFB080913, + 0x81C, 0xFA0A0913, + 0x81C, 0xF90C0913, + 0x81C, 0xF80E0913, + 0x81C, 0xF7100913, + 0x81C, 0xF6120913, + 0x81C, 0xF5140913, + 0x81C, 0xF4160913, + 0x81C, 0xF3180913, + 0x81C, 0xF21A0913, + 0x81C, 0xF11C0913, + 0x81C, 0x941E0913, + 0x81C, 0x93200913, + 0x81C, 0x92220913, + 0x81C, 0x91240913, + 0x81C, 0x90260913, + 0x81C, 0x8F280913, + 0x81C, 0x8E2A0913, + 0x81C, 0x8D2C0913, + 0x81C, 0x8C2E0913, + 0x81C, 0x8B300913, + 0x81C, 0x8A320913, + 0x81C, 0x89340913, + 0x81C, 0x88360913, + 0x81C, 0x87380913, + 0x81C, 0x863A0913, + 0x81C, 0x853C0913, + 0x81C, 0x843E0913, + 0x81C, 0x83400913, + 0x81C, 0x82420913, + 0x81C, 0x81440913, + 0x81C, 0x07460913, + 0x81C, 0x06480913, + 0x81C, 0x054A0913, + 0x81C, 0x044C0913, + 0x81C, 0x034E0913, + 0x81C, 0x02500913, + 0x81C, 0x01520913, + 0x81C, 0x88540903, + 0x81C, 0x87560903, + 0x81C, 0x86580903, + 0x81C, 0x855A0903, + 0x81C, 0x845C0903, + 0x81C, 0x835E0903, + 0x81C, 0x82600903, + 0x81C, 0x81620903, + 0x81C, 0x07640903, + 0x81C, 0x06660903, + 0x81C, 0x05680903, + 0x81C, 0x046A0903, + 0x81C, 0x036C0903, + 0x81C, 0x026E0903, + 0x81C, 0x01700903, + 0x81C, 0x01720903, + 0x81C, 0x01740903, + 0x81C, 0x01760903, + 0x81C, 0x01780903, + 0x81C, 0x017A0903, + 0x81C, 0x017C0903, + 0x81C, 0x017E0903, + 0xB0000000, 0x00000000, + 0x80001004, 0x00000000, 0x40000000, 0x00000000, + 0xC50, 0x00000022, + 0xC50, 0x00000020, + 0x90001005, 0x00000000, 0x40000000, 0x00000000, + 0xC50, 0x00000022, + 0xC50, 0x00000022, + 0xA0000000, 0x00000000, + 0xC50, 0x00000022, + 0xC50, 0x00000020, + 0xB0000000, 0x00000000, + +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821c_agc, rtw_phy_cfg_agc); + +static const u32 rtw8821c_bb[] = { + 0x800, 0x9020D010, + 0x804, 0x80018180, + 0x808, 0x04028211, + 0x80C, 0x13D10011, + 0x810, 0x21104255, + 0x814, 0x020C3D10, + 0x818, 0x84A10385, + 0x81C, 0x1E1E081F, + 0x820, 0x0001AAAA, + 0x824, 0x00030FE0, + 0x828, 0x0000CCCC, + 0x82C, 0x75CB7010, + 0x830, 0x79A0EAAA, + 0x834, 0x072E698A, + 0x838, 0x87766461, + 0x83C, 0x9194B2B6, + 0x840, 0x171740E0, + 0x844, 0x4D3D7CDB, + 0x848, 0x4AD0408B, + 0x84C, 0x6AFBF7A5, + 0x850, 0x28A74706, + 0x854, 0x0001520C, + 0x858, 0x4060C000, + 0x85C, 0x74010160, + 0x860, 0x68A7C321, + 0x864, 0x79F27432, + 0x868, 0x8CA7A314, + 0x86C, 0x558C2878, + 0x870, 0x55555555, + 0x874, 0x27612C2E, + 0x878, 0xC0003152, + 0x87C, 0x5C8FC000, + 0x880, 0x00000000, + 0x884, 0x00000000, + 0x888, 0x00000000, + 0x88C, 0x00000000, + 0x890, 0x00000000, + 0x894, 0x00000000, + 0x898, 0x00000000, + 0x89C, 0x00000000, + 0x8A0, 0x00000013, + 0x8A4, 0x7F7F7F7F, + 0x8A8, 0x2202033E, + 0x8AC, 0xF00F000A, + 0x8B0, 0x00000600, + 0x8B4, 0x000FC080, + 0x8B8, 0xEC0057FF, + 0x8BC, 0x2CB520A3, + 0x8C0, 0xFFE04020, + 0x8C4, 0x47C00000, + 0x8C8, 0x00025165, + 0x8CC, 0x08188492, + 0x8D0, 0x0000B800, + 0x8D4, 0x860308A0, + 0x8D8, 0x290B5612, + 0x8DC, 0x00000000, + 0x8E0, 0x32D16777, + 0x8E4, 0x49092925, + 0x8E8, 0xFFFFC42C, + 0x8EC, 0x99999999, + 0x8F0, 0x00009999, + 0x8F4, 0x00D80FA1, + 0x8F8, 0x400000C0, + 0x8FC, 0x00000130, + 0x900, 0x00C00000, + 0x904, 0x0FFF0FFF, + 0x908, 0x00000000, + 0x90C, 0x13000000, + 0x910, 0x0000FC00, + 0x914, 0xC6380000, + 0x918, 0x1C1028C0, + 0x91C, 0x64B11A1C, + 0x920, 0xE0767233, + 0x924, 0x855A2500, + 0x928, 0x4AB0E4E4, + 0x92C, 0xFFFEB200, + 0x930, 0xFFFFFFFE, + 0x934, 0x001FFFFF, + 0x938, 0x00008480, + 0x93C, 0xE41C0642, + 0x940, 0x0E470430, + 0x944, 0x00000000, + 0x948, 0xAC000000, + 0x94C, 0x10000083, + 0x950, 0xB2010080, + 0x954, 0x86510080, + 0x958, 0x00000181, + 0x95C, 0x04248000, + 0x960, 0x00000000, + 0x964, 0x00000000, + 0x968, 0x00000000, + 0x96C, 0x00000000, + 0x970, 0x00001FFF, + 0x974, 0x04000FFF, + 0x978, 0x00000000, + 0x97C, 0x00000000, + 0x980, 0x00000000, + 0x984, 0x00000000, + 0x988, 0x00000000, + 0x98C, 0x23440000, + 0x990, 0x27100000, + 0x994, 0xFFFF0100, + 0x998, 0xFFFFFF5C, + 0x99C, 0xFFFFFFFF, + 0x9A0, 0x000000FF, + 0x9A4, 0x80000088, + 0x9A8, 0x0C2F0000, + 0x9AC, 0x01560000, + 0x9B0, 0x70000000, + 0x9B4, 0x00000000, + 0x9B8, 0x00000000, + 0x9BC, 0x00000000, + 0x9C0, 0x00000000, + 0x9C4, 0x00000000, + 0x9C8, 0x00000000, + 0x9CC, 0x00000000, + 0x9D0, 0x00000000, + 0x9D4, 0x00000000, + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E0, 0x00000000, + 0x9E4, 0x02000402, + 0x9E8, 0x000022D4, + 0x9EC, 0x00000000, + 0x9F0, 0x00000000, + 0x9F4, 0x00000000, + 0x9F8, 0x00000000, + 0x9FC, 0xEFFFF7FF, + 0xA00, 0x00D040C8, + 0xA04, 0x80FF800C, + 0xA08, 0x9C838300, + 0xA0C, 0x297E000F, + 0xA10, 0x9500BB78, + 0xA14, 0x1114D028, + 0xA18, 0x00881117, + 0xA1C, 0x89140F00, + 0xA20, 0xE82C0000, + 0xA24, 0x64B80C1C, + 0xA28, 0x00008810, + 0xA2C, 0x00D20000, + 0xA70, 0x101FBF00, + 0xA74, 0x00000107, + 0xA78, 0x00008900, + 0xA7C, 0x225B0606, + 0xA80, 0x21807532, + 0xA84, 0x80120000, + 0xA88, 0x048C0000, + 0xA8C, 0x12345678, + 0xA90, 0xABCDEF00, + 0xA94, 0x001B1B89, + 0xA98, 0x00000000, + 0xA9C, 0x3F000000, + 0xAA0, 0x00000000, + 0xAA4, 0x00080000, + 0xAA8, 0xEACF0004, + 0xAAC, 0x01235667, + 0xAB0, 0x00000000, + 0xB00, 0xE1000440, + 0xB04, 0x00800000, + 0xB08, 0xFF02030B, + 0xB0C, 0x01EAA406, + 0xB10, 0x00030690, + 0xB14, 0x006000FA, + 0xB18, 0x00000002, + 0xB1C, 0x00000002, + 0xB20, 0x4B00001F, + 0xB24, 0x4E8E3E40, + 0xB28, 0x03020100, + 0xB2C, 0x07060504, + 0xB30, 0x0B0A0908, + 0xB34, 0x0F0E0D0C, + 0xB38, 0x13121110, + 0xB3C, 0x0000003A, + 0xB40, 0x00000000, + 0xB44, 0x80000000, + 0xB48, 0x3F0000FA, + 0xB4C, 0x88C80020, + 0xB50, 0x00000000, + 0xB54, 0x00004241, + 0xB58, 0xE0008208, + 0xB5C, 0x41EFFFF9, + 0xB60, 0x00000000, + 0xB64, 0x00200063, + 0xB68, 0x0000003A, + 0xB6C, 0x00000102, + 0xB70, 0x4E6D1870, + 0xB74, 0x03020100, + 0xB78, 0x07060504, + 0xB7C, 0x0B0A0908, + 0xB80, 0x0F0E0D0C, + 0xB84, 0x13121110, + 0xB88, 0x00000000, + 0xB8C, 0x00000000, + 0xC00, 0x00000007, + 0xC04, 0x03050020, + 0xC08, 0x60403231, + 0xC0C, 0x00012345, + 0xC10, 0x00000100, + 0xC14, 0x01000000, + 0xC18, 0x00000000, + 0xC1C, 0x40040053, + 0xC20, 0x400503A3, + 0xC24, 0x00000000, + 0xC28, 0x00000000, + 0xC2C, 0x00000000, + 0xC30, 0x00000000, + 0xC34, 0x00000000, + 0xC38, 0x00000000, + 0xC3C, 0x00000000, + 0xC40, 0x00000000, + 0xC44, 0x00000000, + 0xC48, 0x00000000, + 0xC4C, 0x00000000, + 0xC50, 0x00000020, + 0xC54, 0x00000000, + 0xC58, 0xD8020402, + 0xC5C, 0xDE000120, + 0xC68, 0x0000003F, + 0xC6C, 0x0000122A, + 0xC70, 0x00000000, + 0xC74, 0x00000000, + 0xC78, 0x00000000, + 0xC7C, 0x00000000, + 0xC80, 0x00000000, + 0xC84, 0x00000000, + 0xC88, 0x00000000, + 0xC8C, 0x07000000, + 0xC94, 0x01000100, + 0xC98, 0x201C8000, + 0xC9C, 0x00000000, + 0xCA0, 0x0000A555, + 0xCA4, 0x08040201, + 0xCA8, 0x80402010, + 0xCAC, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0xCB0, 0x77777717, + 0xCB4, 0x00000073, + 0xA0000000, 0x00000000, + 0xCB0, 0x77775747, + 0xCB4, 0x10000077, + 0xB0000000, 0x00000000, + 0xCB8, 0x00000000, + 0xCBC, 0x00000000, + 0xCC0, 0x00000000, + 0xCC4, 0x00000000, + 0xCC8, 0x00000000, + 0xCCC, 0x00000000, + 0xCD0, 0x00000000, + 0xCD4, 0x00000000, + 0xCD8, 0x00000000, + 0xCDC, 0x00000000, + 0xCE0, 0x00000000, + 0xCE4, 0x00000000, + 0xCE8, 0x00000000, + 0xCEC, 0x00000000, + 0xE00, 0x00000007, + 0xE04, 0x00000020, + 0xE08, 0x60403231, + 0xE0C, 0x00012345, + 0xE10, 0x00000100, + 0xE14, 0x01000000, + 0xE18, 0x00000000, + 0xE1C, 0x40040053, + 0xE20, 0x00020103, + 0xE24, 0x00000000, + 0xE28, 0x00000000, + 0xE2C, 0x00000000, + 0xE30, 0x00000000, + 0xE34, 0x00000000, + 0xE38, 0x00000000, + 0xE3C, 0x00000000, + 0xE40, 0x00000000, + 0xE44, 0x00000000, + 0xE48, 0x00000000, + 0xE4C, 0x00000000, + 0xE50, 0x00000020, + 0xE54, 0x00000000, + 0xE58, 0xD8020402, + 0xE5C, 0xDE000120, + 0xE68, 0x59799979, + 0xE6C, 0x0000122A, + 0xE70, 0x99795979, + 0xE74, 0x99795979, + 0xE78, 0x99799979, + 0xE7C, 0x99791979, + 0xE80, 0x19791979, + 0xE84, 0x19791979, + 0xE88, 0x00000000, + 0xE8C, 0x07000000, + 0xE94, 0x01000100, + 0xE98, 0x201C8000, + 0xE9C, 0x00000000, + 0xEA0, 0x0000A555, + 0xEA4, 0x08040201, + 0xEA8, 0x80402010, + 0xEAC, 0x00000000, + 0xEB0, 0x98543210, + 0xEB4, 0x000000BA, + 0xEB8, 0x00000000, + 0xEBC, 0x00000000, + 0xEC0, 0x00000000, + 0xEC4, 0x00000000, + 0xEC8, 0x00000000, + 0xECC, 0x00000000, + 0xED0, 0x00000000, + 0xED4, 0x00000000, + 0xED8, 0x00000000, + 0xEDC, 0x00000000, + 0xEE0, 0x00000000, + 0xEE4, 0x00000000, + 0xEE8, 0x00000000, + 0xEEC, 0x00000000, + 0x1900, 0x00000000, + 0x1904, 0x00238000, + 0x1908, 0x00000000, + 0x190C, 0x00000000, + 0x1910, 0x00001800, + 0x1914, 0x00000000, + 0x1918, 0x00000000, + 0x191C, 0x00000000, + 0x1920, 0x00000000, + 0x1924, 0x00000000, + 0x1928, 0x00000000, + 0x192C, 0x00000000, + 0x1930, 0x00000000, + 0x1934, 0x00000000, + 0x1938, 0x00000000, + 0x193C, 0x00000000, + 0x1940, 0x00000000, + 0x1944, 0x00000000, + 0x1948, 0x00000000, + 0x194C, 0x00000000, + 0x1950, 0x00000000, + 0x1954, 0x00000000, + 0x1958, 0x00000000, + 0x195C, 0x00000000, + 0x1960, 0x00000000, + 0x1964, 0x00000000, + 0x1968, 0x00000000, + 0x196C, 0x00000000, + 0x1970, 0x00000000, + 0x1974, 0x00000000, + 0x1978, 0x00000000, + 0x197C, 0x00000000, + 0x1980, 0x00000000, + 0x1984, 0x03000000, + 0x1988, 0x21401E88, + 0x198C, 0x00004000, + 0x1990, 0x00000000, + 0x1994, 0x00000000, + 0x1998, 0x00000053, + 0x199C, 0x00000000, + 0x19A0, 0x00000000, + 0x19A4, 0x00000000, + 0x19A8, 0x010A0000, + 0x19AC, 0x0E47E47F, + 0x19B0, 0x00008000, + 0x19B4, 0x0E47E47F, + 0x19B8, 0x00000000, + 0x19BC, 0x00000000, + 0x19C0, 0x00000000, + 0x19C4, 0x00000000, + 0x19C8, 0x00000000, + 0x19CC, 0x00000000, + 0x19D0, 0x00000000, + 0x19D4, 0x77777777, + 0x19D8, 0x00000777, + 0x19DC, 0x133E0F37, + 0x19E0, 0x00000000, + 0x19E4, 0x00000000, + 0x19E8, 0x00000000, + 0x19EC, 0x00000000, + 0x19F0, 0x00000000, + 0x19F4, 0x00000000, + 0x19F8, 0x01A00000, + 0x19FC, 0x00000000, + 0x1C00, 0x00000100, + 0x1C04, 0x01000000, + 0x1C08, 0x00000100, + 0x1C0C, 0x01000000, + 0x1C10, 0x00000100, + 0x1C14, 0x01000000, + 0x1C18, 0x00000100, + 0x1C1C, 0x01000000, + 0x1C20, 0x00000100, + 0x1C24, 0x01000000, + 0x1C28, 0x00000100, + 0x1C2C, 0x01000000, + 0x1C30, 0x00000100, + 0x1C34, 0x01000000, + 0x1C38, 0x00000000, + 0x1C3C, 0x00008000, + 0x1C40, 0x000C0100, + 0x1C44, 0x000000F3, + 0x1C48, 0x1A8249A8, + 0x1C4C, 0x1461C826, + 0x1C50, 0x0001469E, + 0x1C54, 0x58D158D1, + 0x1C58, 0x04490088, + 0x1C5C, 0x04004400, + 0x1C60, 0x00000000, + 0x1C64, 0x04004400, + 0x1C68, 0x0B7B7B75, + 0x1C6C, 0x01000000, + 0x1C70, 0x00A08145, + 0x1C74, 0x2080E0E0, + 0x1C78, 0x00000000, + 0x1C7C, 0x00000010, + 0x1C80, 0x00000100, + 0x1C84, 0x01000000, + 0x1C88, 0x00000100, + 0x1C8C, 0x01000000, + 0x1C90, 0x00000100, + 0x1C94, 0x01000000, + 0x1C98, 0x00000100, + 0x1C9C, 0x01000000, + 0x1CA0, 0x00000100, + 0x1CA4, 0x01000000, + 0x1CA8, 0x00000100, + 0x1CAC, 0x01000000, + 0x1CB0, 0x00000100, + 0x1CB4, 0x01000000, + 0x1CB8, 0x00000000, + 0x1CBC, 0x00000000, + 0x1CC0, 0x201B0100, + 0x1CC4, 0x00308000, + 0x1CC8, 0x5B74B6E9, + 0x1CCC, 0x01000000, + 0x1CD0, 0x00000400, + 0x1CD4, 0x01000000, + 0x1CD8, 0x01B8ADEB, + 0x1CDC, 0x01000000, + 0x1CE0, 0x00030003, + 0x1CE4, 0x4E4A0306, + 0x1CE8, 0x00000100, + 0x1CEC, 0x01000000, + 0x1CF0, 0x00000100, + 0x1CF4, 0x01000000, + 0x1CF8, 0x01B8ADEB, + 0x1CFC, 0x00000000, + 0xC60, 0x700B8040, + 0xC60, 0x700B8040, + 0xC60, 0x70146040, + 0xC60, 0x70246040, + 0xC60, 0x70346040, + 0xC60, 0x70446040, + 0xC60, 0x705B2040, + 0xC60, 0x70646040, + 0xC60, 0x707B8040, + 0xC60, 0x708B8040, + 0xC60, 0x709B8040, + 0xC60, 0x70AB8040, + 0xC60, 0x70BB6040, + 0xC60, 0x70C06040, + 0xC60, 0x70D06040, + 0xC60, 0x70EF6040, + 0xC60, 0x70F06040, + 0xE60, 0x700B8040, + 0xE60, 0x700B8040, + 0xE60, 0x70146040, + 0xE60, 0x70246040, + 0xE60, 0x70346040, + 0xE60, 0x70446040, + 0xE60, 0x705B2040, + 0xE60, 0x70646040, + 0xE60, 0x707B8040, + 0xE60, 0x708B8040, + 0xE60, 0x709B8040, + 0xE60, 0x70AB8040, + 0xE60, 0x70BB6040, + 0xE60, 0x70C06040, + 0xE60, 0x70D06040, + 0xE60, 0x70EF6040, + 0xE60, 0x70F06040, + 0xC64, 0x00800000, + 0xC64, 0x08800001, + 0xC64, 0x00800002, + 0xC64, 0x00800003, + 0xC64, 0x00800004, + 0xC64, 0x00800005, + 0xC64, 0x00800006, + 0xC64, 0x08800007, + 0xC64, 0x00004000, + 0xE64, 0x00800000, + 0xE64, 0x08800001, + 0xE64, 0x00800002, + 0xE64, 0x00800003, + 0xE64, 0x00800004, + 0xE64, 0x00800005, + 0xE64, 0x00800006, + 0xE64, 0x08800007, + 0xE64, 0x00004000, + 0x1B00, 0xF8000008, + 0x1B00, 0xF80A7008, + 0x1B00, 0xF8015008, + 0x1B00, 0xF8000008, + 0x1B04, 0xE24629D2, + 0x1B08, 0x00000080, + 0x1B0C, 0x00000000, + 0x1B10, 0x00011C00, + 0x1B14, 0x00000000, + 0x1B18, 0x00292903, + 0x1B1C, 0xA2193C32, + 0x1B20, 0x01840008, + 0x1B24, 0x01860008, + 0x1B28, 0x80060300, + 0x1B2C, 0x00000003, + 0x1B30, 0x20000000, + 0x1B34, 0x00000800, + 0x1B3C, 0x20000000, + 0x1BC0, 0x01000000, + 0x1BCC, 0x00000000, + 0x1B90, 0x0001E018, + 0x1B94, 0xF76D9F84, + 0x1BC8, 0x000C44AA, + 0x1BCC, 0x11978200, + 0x1B8C, 0x00002000, + 0x1B9C, 0x5B554F48, + 0x1BA0, 0x6F6B6661, + 0x1BA4, 0x817D7874, + 0x1BA8, 0x908C8884, + 0x1BAC, 0x9D9A9793, + 0x1BB0, 0xAAA7A4A1, + 0x1BB4, 0xB6B3B0AD, + 0x1B40, 0x02CE03E8, + 0x1B44, 0x01FD024C, + 0x1B48, 0x01A101C9, + 0x1B4C, 0x016A0183, + 0x1B50, 0x01430153, + 0x1B54, 0x01280134, + 0x1B58, 0x0112011C, + 0x1B5C, 0x01000107, + 0x1B60, 0x00F200F9, + 0x1B64, 0x00E500EB, + 0x1B68, 0x00DA00E0, + 0x1B6C, 0x00D200D6, + 0x1B70, 0x00C900CD, + 0x1B74, 0x00C200C5, + 0x1B78, 0x00BB00BE, + 0x1B7C, 0x00B500B8, + 0x1BDC, 0x40CAFFE1, + 0x1BDC, 0x4080A1E3, + 0x1BDC, 0x405165E5, + 0x1BDC, 0x403340E7, + 0x1BDC, 0x402028E9, + 0x1BDC, 0x401419EB, + 0x1BDC, 0x400D10ED, + 0x1BDC, 0x40080AEF, + 0x1BDC, 0x400506F1, + 0x1BDC, 0x400304F3, + 0x1BDC, 0x400203F5, + 0x1BDC, 0x400102F7, + 0x1BDC, 0x400101F9, + 0x1BDC, 0x400101FB, + 0x1BDC, 0x400101FD, + 0x1BDC, 0x400101FF, + 0x1BDC, 0x40CAFF81, + 0x1BDC, 0x4080A183, + 0x1BDC, 0x40516585, + 0x1BDC, 0x40334087, + 0x1BDC, 0x40202889, + 0x1BDC, 0x4014198B, + 0x1BDC, 0x400D108D, + 0x1BDC, 0x40080A8F, + 0x1BDC, 0x40050691, + 0x1BDC, 0x40030493, + 0x1BDC, 0x40020395, + 0x1BDC, 0x40010297, + 0x1BDC, 0x40010199, + 0x1BDC, 0x4001019B, + 0x1BDC, 0x4001019D, + 0x1BDC, 0x4001019F, + 0x1BDC, 0x00000000, + 0x1BDC, 0xD0000001, + 0x1BDC, 0xD0000003, + 0x1BDC, 0xD0000005, + 0x1BDC, 0xD0000007, + 0x1BDC, 0xD0000009, + 0x1BDC, 0xD000000B, + 0x1BDC, 0xD000000D, + 0x1BDC, 0xD000000F, + 0x1BDC, 0xD0000011, + 0x1BDC, 0xD0000013, + 0x1BDC, 0xD0000015, + 0x1BDC, 0xD0000017, + 0x1BDC, 0xD0000019, + 0x1BDC, 0xD000001B, + 0x1BDC, 0xD000001D, + 0x1BDC, 0xD000001F, + 0x1BDC, 0xD0000021, + 0x1BDC, 0xD0000023, + 0x1BDC, 0xD0000025, + 0x1BDC, 0xD0000027, + 0x1BDC, 0xD0000029, + 0x1BDC, 0xD000002B, + 0x1BDC, 0xD000002D, + 0x1BDC, 0xD000002F, + 0x1BDC, 0xD0000031, + 0x1BDC, 0xD0000033, + 0x1BDC, 0xD0000035, + 0x1BDC, 0xD0000037, + 0x1BDC, 0xD0000039, + 0x1BDC, 0xD000003B, + 0x1BDC, 0xD000003D, + 0x1BDC, 0xD000003F, + 0x1BDC, 0xD0000041, + 0x1BDC, 0xD0000043, + 0x1BDC, 0xD0000045, + 0x1BDC, 0xD0000047, + 0x1BDC, 0xD0000049, + 0x1BDC, 0xD000004B, + 0x1BDC, 0xD000004D, + 0x1BDC, 0xD000004F, + 0x1BDC, 0xD0000051, + 0x1BDC, 0xD0000053, + 0x1BDC, 0xD0000055, + 0x1BDC, 0xD0000057, + 0x1BDC, 0xD0000059, + 0x1BDC, 0xD000005B, + 0x1BDC, 0xD000005D, + 0x1BDC, 0xD000005F, + 0x1BDC, 0xD0000061, + 0x1BDC, 0xD0000063, + 0x1BDC, 0xD0000065, + 0x1BDC, 0xD0000067, + 0x1BDC, 0xD0000069, + 0x1BDC, 0xD000006B, + 0x1BDC, 0xD000006D, + 0x1BDC, 0xD000006F, + 0x1BDC, 0xD0000071, + 0x1BDC, 0xD0000073, + 0x1BDC, 0xD0000075, + 0x1BDC, 0xD0000077, + 0x1BDC, 0xD0000079, + 0x1BDC, 0xD000007B, + 0x1BDC, 0xD000007D, + 0x1BDC, 0xD000007F, + 0x1BDC, 0x90000081, + 0x1BDC, 0x90000083, + 0x1BDC, 0x90000085, + 0x1BDC, 0x90000087, + 0x1BDC, 0x90000089, + 0x1BDC, 0x9000008B, + 0x1BDC, 0x9000008D, + 0x1BDC, 0x9000008F, + 0x1BDC, 0x90000091, + 0x1BDC, 0x90000093, + 0x1BDC, 0x90000095, + 0x1BDC, 0x90000097, + 0x1BDC, 0x90000099, + 0x1BDC, 0x9000009B, + 0x1BDC, 0x9000009D, + 0x1BDC, 0x9000009F, + 0x1BDC, 0x900000A1, + 0x1BDC, 0x900000A3, + 0x1BDC, 0x900000A5, + 0x1BDC, 0x900000A7, + 0x1BDC, 0x900000A9, + 0x1BDC, 0x900000AB, + 0x1BDC, 0x900000AD, + 0x1BDC, 0x900000AF, + 0x1BDC, 0x900000B1, + 0x1BDC, 0x900000B3, + 0x1BDC, 0x900000B5, + 0x1BDC, 0x900000B7, + 0x1BDC, 0x900000B9, + 0x1BDC, 0x900000BB, + 0x1BDC, 0x900000BD, + 0x1BDC, 0x900000BF, + 0x1BDC, 0x900000C1, + 0x1BDC, 0x900000C3, + 0x1BDC, 0x900000C5, + 0x1BDC, 0x900000C7, + 0x1BDC, 0x900000C9, + 0x1BDC, 0x900000CB, + 0x1BDC, 0x900000CD, + 0x1BDC, 0x900000CF, + 0x1BDC, 0x900000D1, + 0x1BDC, 0x900000D3, + 0x1BDC, 0x900000D5, + 0x1BDC, 0x900000D7, + 0x1BDC, 0x900000D9, + 0x1BDC, 0x900000DB, + 0x1BDC, 0x900000DD, + 0x1BDC, 0x900000DF, + 0x1BDC, 0x900000E1, + 0x1BDC, 0x900000E3, + 0x1BDC, 0x900000E5, + 0x1BDC, 0x900000E7, + 0x1BDC, 0x900000E9, + 0x1BDC, 0x900000EB, + 0x1BDC, 0x900000ED, + 0x1BDC, 0x900000EF, + 0x1BDC, 0x900000F1, + 0x1BDC, 0x900000F3, + 0x1BDC, 0x900000F5, + 0x1BDC, 0x900000F7, + 0x1BDC, 0x900000F9, + 0x1BDC, 0x900000FB, + 0x1BDC, 0x900000FD, + 0x1BDC, 0x900000FF, + 0x1BDC, 0x00000000, + 0x1B00, 0xF8000000, + 0x1B80, 0x00000007, + 0x1B80, 0x090A0005, + 0x1B80, 0x090A0007, + 0x1B80, 0x0FFE0015, + 0x1B80, 0x0FFE0017, + 0x1B80, 0x00220025, + 0x1B80, 0x00220027, + 0x1B80, 0x00040035, + 0x1B80, 0x00040037, + 0x1B80, 0x05C00045, + 0x1B80, 0x05C00047, + 0x1B80, 0x00070055, + 0x1B80, 0x00070057, + 0x1B80, 0x64000065, + 0x1B80, 0x64000067, + 0x1B80, 0x00020075, + 0x1B80, 0x00020077, + 0x1B80, 0x00080085, + 0x1B80, 0x00080087, + 0x1B80, 0x80000095, + 0x1B80, 0x80000097, + 0x1B80, 0x090800A5, + 0x1B80, 0x090800A7, + 0x1B80, 0x0F0200B5, + 0x1B80, 0x0F0200B7, + 0x1B80, 0x002200C5, + 0x1B80, 0x002200C7, + 0x1B80, 0x000400D5, + 0x1B80, 0x000400D7, + 0x1B80, 0x05C000E5, + 0x1B80, 0x05C000E7, + 0x1B80, 0x000700F5, + 0x1B80, 0x000700F7, + 0x1B80, 0x64020105, + 0x1B80, 0x64020107, + 0x1B80, 0x00020115, + 0x1B80, 0x00020117, + 0x1B80, 0x00040125, + 0x1B80, 0x00040127, + 0x1B80, 0x4A000135, + 0x1B80, 0x4A000137, + 0x1B80, 0x4B040145, + 0x1B80, 0x4B040147, + 0x1B80, 0x85030155, + 0x1B80, 0x85030157, + 0x1B80, 0x40090165, + 0x1B80, 0x40090167, + 0x1B80, 0xE02A0175, + 0x1B80, 0xE02A0177, + 0x1B80, 0x4B050185, + 0x1B80, 0x4B050187, + 0x1B80, 0x86030195, + 0x1B80, 0x86030197, + 0x1B80, 0x400B01A5, + 0x1B80, 0x400B01A7, + 0x1B80, 0xE02A01B5, + 0x1B80, 0xE02A01B7, + 0x1B80, 0x4B0001C5, + 0x1B80, 0x4B0001C7, + 0x1B80, 0x000701D5, + 0x1B80, 0x000701D7, + 0x1B80, 0x4C0001E5, + 0x1B80, 0x4C0001E7, + 0x1B80, 0x000401F5, + 0x1B80, 0x000401F7, + 0x1B80, 0x4D040205, + 0x1B80, 0x4D040207, + 0x1B80, 0x2EE00215, + 0x1B80, 0x2EE00217, + 0x1B80, 0x00000225, + 0x1B80, 0x00000227, + 0x1B80, 0x2EF00235, + 0x1B80, 0x2EF00237, + 0x1B80, 0x00000245, + 0x1B80, 0x00000247, + 0x1B80, 0x20810255, + 0x1B80, 0x20810257, + 0x1B80, 0x23450265, + 0x1B80, 0x23450267, + 0x1B80, 0x4D000275, + 0x1B80, 0x4D000277, + 0x1B80, 0x00040285, + 0x1B80, 0x00040287, + 0x1B80, 0x30000295, + 0x1B80, 0x30000297, + 0x1B80, 0xE1D602A5, + 0x1B80, 0xE1D602A7, + 0x1B80, 0xF01102B5, + 0x1B80, 0xF01102B7, + 0x1B80, 0xF11102C5, + 0x1B80, 0xF11102C7, + 0x1B80, 0xF21102D5, + 0x1B80, 0xF21102D7, + 0x1B80, 0xF31102E5, + 0x1B80, 0xF31102E7, + 0x1B80, 0xF41102F5, + 0x1B80, 0xF41102F7, + 0x1B80, 0xF5110305, + 0x1B80, 0xF5110307, + 0x1B80, 0xF6110315, + 0x1B80, 0xF6110317, + 0x1B80, 0xF7110325, + 0x1B80, 0xF7110327, + 0x1B80, 0xF8110335, + 0x1B80, 0xF8110337, + 0x1B80, 0xF9110345, + 0x1B80, 0xF9110347, + 0x1B80, 0xFA110355, + 0x1B80, 0xFA110357, + 0x1B80, 0xFB110365, + 0x1B80, 0xFB110367, + 0x1B80, 0xFC110375, + 0x1B80, 0xFC110377, + 0x1B80, 0xFD110385, + 0x1B80, 0xFD110387, + 0x1B80, 0xFE110395, + 0x1B80, 0xFE110397, + 0x1B80, 0xFF1103A5, + 0x1B80, 0xFF1103A7, + 0x1B80, 0x000103B5, + 0x1B80, 0x000103B7, + 0x1B80, 0x305503C5, + 0x1B80, 0x305503C7, + 0x1B80, 0x306D03D5, + 0x1B80, 0x306D03D7, + 0x1B80, 0x30B803E5, + 0x1B80, 0x30B803E7, + 0x1B80, 0x30BB03F5, + 0x1B80, 0x30BB03F7, + 0x1B80, 0x306F0405, + 0x1B80, 0x306F0407, + 0x1B80, 0x307A0415, + 0x1B80, 0x307A0417, + 0x1B80, 0x30850425, + 0x1B80, 0x30850427, + 0x1B80, 0x30C50435, + 0x1B80, 0x30C50437, + 0x1B80, 0x30BF0445, + 0x1B80, 0x30BF0447, + 0x1B80, 0x30D30455, + 0x1B80, 0x30D30457, + 0x1B80, 0x30DE0465, + 0x1B80, 0x30DE0467, + 0x1B80, 0x30E90475, + 0x1B80, 0x30E90477, + 0x1B80, 0x304C0485, + 0x1B80, 0x304C0487, + 0x1B80, 0x31180495, + 0x1B80, 0x31180497, + 0x1B80, 0x312904A5, + 0x1B80, 0x312904A7, + 0x1B80, 0x313E04B5, + 0x1B80, 0x313E04B7, + 0x1B80, 0x4D0404C5, + 0x1B80, 0x4D0404C7, + 0x1B80, 0x2EE004D5, + 0x1B80, 0x2EE004D7, + 0x1B80, 0x000004E5, + 0x1B80, 0x000004E7, + 0x1B80, 0x2EF004F5, + 0x1B80, 0x2EF004F7, + 0x1B80, 0x00000505, + 0x1B80, 0x00000507, + 0x1B80, 0x20810515, + 0x1B80, 0x20810517, + 0x1B80, 0xA3B50525, + 0x1B80, 0xA3B50527, + 0x1B80, 0x4D000535, + 0x1B80, 0x4D000537, + 0x1B80, 0x30000545, + 0x1B80, 0x30000547, + 0x1B80, 0xE1690555, + 0x1B80, 0xE1690557, + 0x1B80, 0x4D040565, + 0x1B80, 0x4D040567, + 0x1B80, 0x20800575, + 0x1B80, 0x20800577, + 0x1B80, 0x00000585, + 0x1B80, 0x00000587, + 0x1B80, 0x4D000595, + 0x1B80, 0x4D000597, + 0x1B80, 0x550705A5, + 0x1B80, 0x550705A7, + 0x1B80, 0xE16105B5, + 0x1B80, 0xE16105B7, + 0x1B80, 0xE16105C5, + 0x1B80, 0xE16105C7, + 0x1B80, 0x4D0405D5, + 0x1B80, 0x4D0405D7, + 0x1B80, 0x208805E5, + 0x1B80, 0x208805E7, + 0x1B80, 0x020005F5, + 0x1B80, 0x020005F7, + 0x1B80, 0x4D000605, + 0x1B80, 0x4D000607, + 0x1B80, 0x550F0615, + 0x1B80, 0x550F0617, + 0x1B80, 0xE1610625, + 0x1B80, 0xE1610627, + 0x1B80, 0x4F020635, + 0x1B80, 0x4F020637, + 0x1B80, 0x4E000645, + 0x1B80, 0x4E000647, + 0x1B80, 0x53020655, + 0x1B80, 0x53020657, + 0x1B80, 0x52010665, + 0x1B80, 0x52010667, + 0x1B80, 0xE1650675, + 0x1B80, 0xE1650677, + 0x1B80, 0x4D080685, + 0x1B80, 0x4D080687, + 0x1B80, 0x57100695, + 0x1B80, 0x57100697, + 0x1B80, 0x570006A5, + 0x1B80, 0x570006A7, + 0x1B80, 0x4D0006B5, + 0x1B80, 0x4D0006B7, + 0x1B80, 0x000106C5, + 0x1B80, 0x000106C7, + 0x1B80, 0xE16906D5, + 0x1B80, 0xE16906D7, + 0x1B80, 0x000106E5, + 0x1B80, 0x000106E7, + 0x1B80, 0x308F06F5, + 0x1B80, 0x308F06F7, + 0x1B80, 0x00230705, + 0x1B80, 0x00230707, + 0x1B80, 0xE1C90715, + 0x1B80, 0xE1C90717, + 0x1B80, 0x00020725, + 0x1B80, 0x00020727, + 0x1B80, 0x54E90735, + 0x1B80, 0x54E90737, + 0x1B80, 0x0BA60745, + 0x1B80, 0x0BA60747, + 0x1B80, 0x00230755, + 0x1B80, 0x00230757, + 0x1B80, 0xE1C90765, + 0x1B80, 0xE1C90767, + 0x1B80, 0x00020775, + 0x1B80, 0x00020777, + 0x1B80, 0x4D300785, + 0x1B80, 0x4D300787, + 0x1B80, 0x30A80795, + 0x1B80, 0x30A80797, + 0x1B80, 0x308B07A5, + 0x1B80, 0x308B07A7, + 0x1B80, 0x002207B5, + 0x1B80, 0x002207B7, + 0x1B80, 0xE1C907C5, + 0x1B80, 0xE1C907C7, + 0x1B80, 0x000207D5, + 0x1B80, 0x000207D7, + 0x1B80, 0x54E807E5, + 0x1B80, 0x54E807E7, + 0x1B80, 0x0BA607F5, + 0x1B80, 0x0BA607F7, + 0x1B80, 0x00220805, + 0x1B80, 0x00220807, + 0x1B80, 0xE1C90815, + 0x1B80, 0xE1C90817, + 0x1B80, 0x00020825, + 0x1B80, 0x00020827, + 0x1B80, 0x4D300835, + 0x1B80, 0x4D300837, + 0x1B80, 0x30A80845, + 0x1B80, 0x30A80847, + 0x1B80, 0x63F10855, + 0x1B80, 0x63F10857, + 0x1B80, 0xE1690865, + 0x1B80, 0xE1690867, + 0x1B80, 0xE1C90875, + 0x1B80, 0xE1C90877, + 0x1B80, 0x63F40885, + 0x1B80, 0x63F40887, + 0x1B80, 0xE1690895, + 0x1B80, 0xE1690897, + 0x1B80, 0xE1C908A5, + 0x1B80, 0xE1C908A7, + 0x1B80, 0x0BA808B5, + 0x1B80, 0x0BA808B7, + 0x1B80, 0x63F808C5, + 0x1B80, 0x63F808C7, + 0x1B80, 0xE16908D5, + 0x1B80, 0xE16908D7, + 0x1B80, 0xE1C908E5, + 0x1B80, 0xE1C908E7, + 0x1B80, 0x0BA908F5, + 0x1B80, 0x0BA908F7, + 0x1B80, 0x63FC0905, + 0x1B80, 0x63FC0907, + 0x1B80, 0xE1690915, + 0x1B80, 0xE1690917, + 0x1B80, 0xE1C90925, + 0x1B80, 0xE1C90927, + 0x1B80, 0x63FF0935, + 0x1B80, 0x63FF0937, + 0x1B80, 0xE1690945, + 0x1B80, 0xE1690947, + 0x1B80, 0xE1C90955, + 0x1B80, 0xE1C90957, + 0x1B80, 0x63000965, + 0x1B80, 0x63000967, + 0x1B80, 0xE1690975, + 0x1B80, 0xE1690977, + 0x1B80, 0xE1C90985, + 0x1B80, 0xE1C90987, + 0x1B80, 0x63030995, + 0x1B80, 0x63030997, + 0x1B80, 0xE16909A5, + 0x1B80, 0xE16909A7, + 0x1B80, 0xE1C909B5, + 0x1B80, 0xE1C909B7, + 0x1B80, 0xF4D409C5, + 0x1B80, 0xF4D409C7, + 0x1B80, 0x630709D5, + 0x1B80, 0x630709D7, + 0x1B80, 0xE16909E5, + 0x1B80, 0xE16909E7, + 0x1B80, 0xE1C909F5, + 0x1B80, 0xE1C909F7, + 0x1B80, 0xF5DB0A05, + 0x1B80, 0xF5DB0A07, + 0x1B80, 0x630B0A15, + 0x1B80, 0x630B0A17, + 0x1B80, 0xE1690A25, + 0x1B80, 0xE1690A27, + 0x1B80, 0xE1C90A35, + 0x1B80, 0xE1C90A37, + 0x1B80, 0x630E0A45, + 0x1B80, 0x630E0A47, + 0x1B80, 0xE1690A55, + 0x1B80, 0xE1690A57, + 0x1B80, 0xE1C90A65, + 0x1B80, 0xE1C90A67, + 0x1B80, 0x4D300A75, + 0x1B80, 0x4D300A77, + 0x1B80, 0x55010A85, + 0x1B80, 0x55010A87, + 0x1B80, 0x57040A95, + 0x1B80, 0x57040A97, + 0x1B80, 0x57000AA5, + 0x1B80, 0x57000AA7, + 0x1B80, 0x96000AB5, + 0x1B80, 0x96000AB7, + 0x1B80, 0x57080AC5, + 0x1B80, 0x57080AC7, + 0x1B80, 0x57000AD5, + 0x1B80, 0x57000AD7, + 0x1B80, 0x95000AE5, + 0x1B80, 0x95000AE7, + 0x1B80, 0x4D000AF5, + 0x1B80, 0x4D000AF7, + 0x1B80, 0x6C070B05, + 0x1B80, 0x6C070B07, + 0x1B80, 0x7B200B15, + 0x1B80, 0x7B200B17, + 0x1B80, 0x7A000B25, + 0x1B80, 0x7A000B27, + 0x1B80, 0x79000B35, + 0x1B80, 0x79000B37, + 0x1B80, 0x7F200B45, + 0x1B80, 0x7F200B47, + 0x1B80, 0x7E000B55, + 0x1B80, 0x7E000B57, + 0x1B80, 0x7D000B65, + 0x1B80, 0x7D000B67, + 0x1B80, 0x00010B75, + 0x1B80, 0x00010B77, + 0x1B80, 0x62850B85, + 0x1B80, 0x62850B87, + 0x1B80, 0xE1690B95, + 0x1B80, 0xE1690B97, + 0x1B80, 0x00010BA5, + 0x1B80, 0x00010BA7, + 0x1B80, 0x5C320BB5, + 0x1B80, 0x5C320BB7, + 0x1B80, 0xE1C50BC5, + 0x1B80, 0xE1C50BC7, + 0x1B80, 0xE1950BD5, + 0x1B80, 0xE1950BD7, + 0x1B80, 0x00010BE5, + 0x1B80, 0x00010BE7, + 0x1B80, 0x5C320BF5, + 0x1B80, 0x5C320BF7, + 0x1B80, 0x63F40C05, + 0x1B80, 0x63F40C07, + 0x1B80, 0x62850C15, + 0x1B80, 0x62850C17, + 0x1B80, 0x0BB00C25, + 0x1B80, 0x0BB00C27, + 0x1B80, 0xE1690C35, + 0x1B80, 0xE1690C37, + 0x1B80, 0xE1C90C45, + 0x1B80, 0xE1C90C47, + 0x1B80, 0x5C320C55, + 0x1B80, 0x5C320C57, + 0x1B80, 0x63FC0C65, + 0x1B80, 0x63FC0C67, + 0x1B80, 0x62850C75, + 0x1B80, 0x62850C77, + 0x1B80, 0x0BB10C85, + 0x1B80, 0x0BB10C87, + 0x1B80, 0xE1690C95, + 0x1B80, 0xE1690C97, + 0x1B80, 0xE1C90CA5, + 0x1B80, 0xE1C90CA7, + 0x1B80, 0x63030CB5, + 0x1B80, 0x63030CB7, + 0x1B80, 0xE1690CC5, + 0x1B80, 0xE1690CC7, + 0x1B80, 0xE1C90CD5, + 0x1B80, 0xE1C90CD7, + 0x1B80, 0xF7040CE5, + 0x1B80, 0xF7040CE7, + 0x1B80, 0x630B0CF5, + 0x1B80, 0x630B0CF7, + 0x1B80, 0xE1690D05, + 0x1B80, 0xE1690D07, + 0x1B80, 0xE1C90D15, + 0x1B80, 0xE1C90D17, + 0x1B80, 0x00010D25, + 0x1B80, 0x00010D27, + 0x1B80, 0x30F70D35, + 0x1B80, 0x30F70D37, + 0x1B80, 0x00230D45, + 0x1B80, 0x00230D47, + 0x1B80, 0xE1CE0D55, + 0x1B80, 0xE1CE0D57, + 0x1B80, 0x00020D65, + 0x1B80, 0x00020D67, + 0x1B80, 0x54E90D75, + 0x1B80, 0x54E90D77, + 0x1B80, 0x0BA60D85, + 0x1B80, 0x0BA60D87, + 0x1B80, 0x00230D95, + 0x1B80, 0x00230D97, + 0x1B80, 0xE1CE0DA5, + 0x1B80, 0xE1CE0DA7, + 0x1B80, 0x00020DB5, + 0x1B80, 0x00020DB7, + 0x1B80, 0x4D100DC5, + 0x1B80, 0x4D100DC7, + 0x1B80, 0x30A80DD5, + 0x1B80, 0x30A80DD7, + 0x1B80, 0x30F10DE5, + 0x1B80, 0x30F10DE7, + 0x1B80, 0x00220DF5, + 0x1B80, 0x00220DF7, + 0x1B80, 0xE1CE0E05, + 0x1B80, 0xE1CE0E07, + 0x1B80, 0x00020E15, + 0x1B80, 0x00020E17, + 0x1B80, 0x54E80E25, + 0x1B80, 0x54E80E27, + 0x1B80, 0x0BA60E35, + 0x1B80, 0x0BA60E37, + 0x1B80, 0x00220E45, + 0x1B80, 0x00220E47, + 0x1B80, 0xE1CE0E55, + 0x1B80, 0xE1CE0E57, + 0x1B80, 0x00020E65, + 0x1B80, 0x00020E67, + 0x1B80, 0x4D100E75, + 0x1B80, 0x4D100E77, + 0x1B80, 0x30A80E85, + 0x1B80, 0x30A80E87, + 0x1B80, 0x5C320E95, + 0x1B80, 0x5C320E97, + 0x1B80, 0x54F00EA5, + 0x1B80, 0x54F00EA7, + 0x1B80, 0x67F10EB5, + 0x1B80, 0x67F10EB7, + 0x1B80, 0xE1950EC5, + 0x1B80, 0xE1950EC7, + 0x1B80, 0xE1CE0ED5, + 0x1B80, 0xE1CE0ED7, + 0x1B80, 0x67F40EE5, + 0x1B80, 0x67F40EE7, + 0x1B80, 0xE1950EF5, + 0x1B80, 0xE1950EF7, + 0x1B80, 0xE1CE0F05, + 0x1B80, 0xE1CE0F07, + 0x1B80, 0x5C320F15, + 0x1B80, 0x5C320F17, + 0x1B80, 0x54F10F25, + 0x1B80, 0x54F10F27, + 0x1B80, 0x0BA80F35, + 0x1B80, 0x0BA80F37, + 0x1B80, 0x67F80F45, + 0x1B80, 0x67F80F47, + 0x1B80, 0xE1950F55, + 0x1B80, 0xE1950F57, + 0x1B80, 0xE1CE0F65, + 0x1B80, 0xE1CE0F67, + 0x1B80, 0x5C320F75, + 0x1B80, 0x5C320F77, + 0x1B80, 0x54F10F85, + 0x1B80, 0x54F10F87, + 0x1B80, 0x0BA90F95, + 0x1B80, 0x0BA90F97, + 0x1B80, 0x67FC0FA5, + 0x1B80, 0x67FC0FA7, + 0x1B80, 0xE1950FB5, + 0x1B80, 0xE1950FB7, + 0x1B80, 0xE1CE0FC5, + 0x1B80, 0xE1CE0FC7, + 0x1B80, 0x67FF0FD5, + 0x1B80, 0x67FF0FD7, + 0x1B80, 0xE1950FE5, + 0x1B80, 0xE1950FE7, + 0x1B80, 0xE1CE0FF5, + 0x1B80, 0xE1CE0FF7, + 0x1B80, 0x5C321005, + 0x1B80, 0x5C321007, + 0x1B80, 0x54F21015, + 0x1B80, 0x54F21017, + 0x1B80, 0x67001025, + 0x1B80, 0x67001027, + 0x1B80, 0xE1951035, + 0x1B80, 0xE1951037, + 0x1B80, 0xE1CE1045, + 0x1B80, 0xE1CE1047, + 0x1B80, 0x67031055, + 0x1B80, 0x67031057, + 0x1B80, 0xE1951065, + 0x1B80, 0xE1951067, + 0x1B80, 0xE1CE1075, + 0x1B80, 0xE1CE1077, + 0x1B80, 0xF9CC1085, + 0x1B80, 0xF9CC1087, + 0x1B80, 0x67071095, + 0x1B80, 0x67071097, + 0x1B80, 0xE19510A5, + 0x1B80, 0xE19510A7, + 0x1B80, 0xE1CE10B5, + 0x1B80, 0xE1CE10B7, + 0x1B80, 0xFAD310C5, + 0x1B80, 0xFAD310C7, + 0x1B80, 0x5C3210D5, + 0x1B80, 0x5C3210D7, + 0x1B80, 0x54F310E5, + 0x1B80, 0x54F310E7, + 0x1B80, 0x670B10F5, + 0x1B80, 0x670B10F7, + 0x1B80, 0xE1951105, + 0x1B80, 0xE1951107, + 0x1B80, 0xE1CE1115, + 0x1B80, 0xE1CE1117, + 0x1B80, 0x670E1125, + 0x1B80, 0x670E1127, + 0x1B80, 0xE1951135, + 0x1B80, 0xE1951137, + 0x1B80, 0xE1CE1145, + 0x1B80, 0xE1CE1147, + 0x1B80, 0x4D101155, + 0x1B80, 0x4D101157, + 0x1B80, 0x30A81165, + 0x1B80, 0x30A81167, + 0x1B80, 0x00011175, + 0x1B80, 0x00011177, + 0x1B80, 0x6C001185, + 0x1B80, 0x6C001187, + 0x1B80, 0x00061195, + 0x1B80, 0x00061197, + 0x1B80, 0x530011A5, + 0x1B80, 0x530011A7, + 0x1B80, 0x57F711B5, + 0x1B80, 0x57F711B7, + 0x1B80, 0x582111C5, + 0x1B80, 0x582111C7, + 0x1B80, 0x592E11D5, + 0x1B80, 0x592E11D7, + 0x1B80, 0x5A3811E5, + 0x1B80, 0x5A3811E7, + 0x1B80, 0x5B4111F5, + 0x1B80, 0x5B4111F7, + 0x1B80, 0x00071205, + 0x1B80, 0x00071207, + 0x1B80, 0x5C001215, + 0x1B80, 0x5C001217, + 0x1B80, 0x4B001225, + 0x1B80, 0x4B001227, + 0x1B80, 0x4E8F1235, + 0x1B80, 0x4E8F1237, + 0x1B80, 0x4F151245, + 0x1B80, 0x4F151247, + 0x1B80, 0x00041255, + 0x1B80, 0x00041257, + 0x1B80, 0xE1B31265, + 0x1B80, 0xE1B31267, + 0x1B80, 0xAB001275, + 0x1B80, 0xAB001277, + 0x1B80, 0x00011285, + 0x1B80, 0x00011287, + 0x1B80, 0x6C001295, + 0x1B80, 0x6C001297, + 0x1B80, 0x000612A5, + 0x1B80, 0x000612A7, + 0x1B80, 0x530012B5, + 0x1B80, 0x530012B7, + 0x1B80, 0x57F712C5, + 0x1B80, 0x57F712C7, + 0x1B80, 0x582112D5, + 0x1B80, 0x582112D7, + 0x1B80, 0x592E12E5, + 0x1B80, 0x592E12E7, + 0x1B80, 0x5A3812F5, + 0x1B80, 0x5A3812F7, + 0x1B80, 0x5B411305, + 0x1B80, 0x5B411307, + 0x1B80, 0x00071315, + 0x1B80, 0x00071317, + 0x1B80, 0x5C001325, + 0x1B80, 0x5C001327, + 0x1B80, 0x4B401335, + 0x1B80, 0x4B401337, + 0x1B80, 0x4E971345, + 0x1B80, 0x4E971347, + 0x1B80, 0x4F111355, + 0x1B80, 0x4F111357, + 0x1B80, 0x00041365, + 0x1B80, 0x00041367, + 0x1B80, 0xE1B31375, + 0x1B80, 0xE1B31377, + 0x1B80, 0xAB001385, + 0x1B80, 0xAB001387, + 0x1B80, 0x8B001395, + 0x1B80, 0x8B001397, + 0x1B80, 0xAB0013A5, + 0x1B80, 0xAB0013A7, + 0x1B80, 0x8A1913B5, + 0x1B80, 0x8A1913B7, + 0x1B80, 0x301D13C5, + 0x1B80, 0x301D13C7, + 0x1B80, 0x000113D5, + 0x1B80, 0x000113D7, + 0x1B80, 0x6C0113E5, + 0x1B80, 0x6C0113E7, + 0x1B80, 0x000613F5, + 0x1B80, 0x000613F7, + 0x1B80, 0x53011405, + 0x1B80, 0x53011407, + 0x1B80, 0x57F71415, + 0x1B80, 0x57F71417, + 0x1B80, 0x58211425, + 0x1B80, 0x58211427, + 0x1B80, 0x592E1435, + 0x1B80, 0x592E1437, + 0x1B80, 0x5A381445, + 0x1B80, 0x5A381447, + 0x1B80, 0x5B411455, + 0x1B80, 0x5B411457, + 0x1B80, 0x00071465, + 0x1B80, 0x00071467, + 0x1B80, 0x5C001475, + 0x1B80, 0x5C001477, + 0x1B80, 0x4B001485, + 0x1B80, 0x4B001487, + 0x1B80, 0x4E871495, + 0x1B80, 0x4E871497, + 0x1B80, 0x4F1114A5, + 0x1B80, 0x4F1114A7, + 0x1B80, 0x000414B5, + 0x1B80, 0x000414B7, + 0x1B80, 0xE1B314C5, + 0x1B80, 0xE1B314C7, + 0x1B80, 0xAB0014D5, + 0x1B80, 0xAB0014D7, + 0x1B80, 0x000614E5, + 0x1B80, 0x000614E7, + 0x1B80, 0x577714F5, + 0x1B80, 0x577714F7, + 0x1B80, 0x00071505, + 0x1B80, 0x00071507, + 0x1B80, 0x4E861515, + 0x1B80, 0x4E861517, + 0x1B80, 0x00041525, + 0x1B80, 0x00041527, + 0x1B80, 0x00011535, + 0x1B80, 0x00011537, + 0x1B80, 0x00011545, + 0x1B80, 0x00011547, + 0x1B80, 0x7B241555, + 0x1B80, 0x7B241557, + 0x1B80, 0x7A401565, + 0x1B80, 0x7A401567, + 0x1B80, 0x79001575, + 0x1B80, 0x79001577, + 0x1B80, 0x55031585, + 0x1B80, 0x55031587, + 0x1B80, 0x31611595, + 0x1B80, 0x31611597, + 0x1B80, 0x7B1C15A5, + 0x1B80, 0x7B1C15A7, + 0x1B80, 0x7A4015B5, + 0x1B80, 0x7A4015B7, + 0x1B80, 0x550B15C5, + 0x1B80, 0x550B15C7, + 0x1B80, 0x316115D5, + 0x1B80, 0x316115D7, + 0x1B80, 0x7B2015E5, + 0x1B80, 0x7B2015E7, + 0x1B80, 0x7A0015F5, + 0x1B80, 0x7A0015F7, + 0x1B80, 0x55131605, + 0x1B80, 0x55131607, + 0x1B80, 0x74011615, + 0x1B80, 0x74011617, + 0x1B80, 0x74001625, + 0x1B80, 0x74001627, + 0x1B80, 0x8E001635, + 0x1B80, 0x8E001637, + 0x1B80, 0x00011645, + 0x1B80, 0x00011647, + 0x1B80, 0x57021655, + 0x1B80, 0x57021657, + 0x1B80, 0x57001665, + 0x1B80, 0x57001667, + 0x1B80, 0x97001675, + 0x1B80, 0x97001677, + 0x1B80, 0x00011685, + 0x1B80, 0x00011687, + 0x1B80, 0x4F781695, + 0x1B80, 0x4F781697, + 0x1B80, 0x538816A5, + 0x1B80, 0x538816A7, + 0x1B80, 0xE17516B5, + 0x1B80, 0xE17516B7, + 0x1B80, 0x548016C5, + 0x1B80, 0x548016C7, + 0x1B80, 0x540016D5, + 0x1B80, 0x540016D7, + 0x1B80, 0x548116E5, + 0x1B80, 0x548116E7, + 0x1B80, 0x540016F5, + 0x1B80, 0x540016F7, + 0x1B80, 0x54821705, + 0x1B80, 0x54821707, + 0x1B80, 0x54001715, + 0x1B80, 0x54001717, + 0x1B80, 0xE1801725, + 0x1B80, 0xE1801727, + 0x1B80, 0xBF1D1735, + 0x1B80, 0xBF1D1737, + 0x1B80, 0x301D1745, + 0x1B80, 0x301D1747, + 0x1B80, 0xE1551755, + 0x1B80, 0xE1551757, + 0x1B80, 0xE15A1765, + 0x1B80, 0xE15A1767, + 0x1B80, 0xE15E1775, + 0x1B80, 0xE15E1777, + 0x1B80, 0xE1651785, + 0x1B80, 0xE1651787, + 0x1B80, 0xE1C51795, + 0x1B80, 0xE1C51797, + 0x1B80, 0x551317A5, + 0x1B80, 0x551317A7, + 0x1B80, 0xE16117B5, + 0x1B80, 0xE16117B7, + 0x1B80, 0x551517C5, + 0x1B80, 0x551517C7, + 0x1B80, 0xE16517D5, + 0x1B80, 0xE16517D7, + 0x1B80, 0xE1C517E5, + 0x1B80, 0xE1C517E7, + 0x1B80, 0x000117F5, + 0x1B80, 0x000117F7, + 0x1B80, 0x54BF1805, + 0x1B80, 0x54BF1807, + 0x1B80, 0x54C01815, + 0x1B80, 0x54C01817, + 0x1B80, 0x54A31825, + 0x1B80, 0x54A31827, + 0x1B80, 0x54C11835, + 0x1B80, 0x54C11837, + 0x1B80, 0x54A41845, + 0x1B80, 0x54A41847, + 0x1B80, 0x4C181855, + 0x1B80, 0x4C181857, + 0x1B80, 0xBF071865, + 0x1B80, 0xBF071867, + 0x1B80, 0x54C21875, + 0x1B80, 0x54C21877, + 0x1B80, 0x54A41885, + 0x1B80, 0x54A41887, + 0x1B80, 0xBF041895, + 0x1B80, 0xBF041897, + 0x1B80, 0x54C118A5, + 0x1B80, 0x54C118A7, + 0x1B80, 0x54A318B5, + 0x1B80, 0x54A318B7, + 0x1B80, 0xBF0118C5, + 0x1B80, 0xBF0118C7, + 0x1B80, 0xE1D318D5, + 0x1B80, 0xE1D318D7, + 0x1B80, 0x54DF18E5, + 0x1B80, 0x54DF18E7, + 0x1B80, 0x000118F5, + 0x1B80, 0x000118F7, + 0x1B80, 0x54BF1905, + 0x1B80, 0x54BF1907, + 0x1B80, 0x54E51915, + 0x1B80, 0x54E51917, + 0x1B80, 0x050A1925, + 0x1B80, 0x050A1927, + 0x1B80, 0x54DF1935, + 0x1B80, 0x54DF1937, + 0x1B80, 0x00011945, + 0x1B80, 0x00011947, + 0x1B80, 0x7F201955, + 0x1B80, 0x7F201957, + 0x1B80, 0x7E001965, + 0x1B80, 0x7E001967, + 0x1B80, 0x7D001975, + 0x1B80, 0x7D001977, + 0x1B80, 0x55011985, + 0x1B80, 0x55011987, + 0x1B80, 0x5C311995, + 0x1B80, 0x5C311997, + 0x1B80, 0xE16119A5, + 0x1B80, 0xE16119A7, + 0x1B80, 0xE16519B5, + 0x1B80, 0xE16519B7, + 0x1B80, 0x548019C5, + 0x1B80, 0x548019C7, + 0x1B80, 0x540019D5, + 0x1B80, 0x540019D7, + 0x1B80, 0x548119E5, + 0x1B80, 0x548119E7, + 0x1B80, 0x540019F5, + 0x1B80, 0x540019F7, + 0x1B80, 0x54821A05, + 0x1B80, 0x54821A07, + 0x1B80, 0x54001A15, + 0x1B80, 0x54001A17, + 0x1B80, 0xE1801A25, + 0x1B80, 0xE1801A27, + 0x1B80, 0xBFED1A35, + 0x1B80, 0xBFED1A37, + 0x1B80, 0x301D1A45, + 0x1B80, 0x301D1A47, + 0x1B80, 0x00231A55, + 0x1B80, 0x00231A57, + 0x1B80, 0x7B201A65, + 0x1B80, 0x7B201A67, + 0x1B80, 0x7A001A75, + 0x1B80, 0x7A001A77, + 0x1B80, 0x79001A85, + 0x1B80, 0x79001A87, + 0x1B80, 0xE1C91A95, + 0x1B80, 0xE1C91A97, + 0x1B80, 0x00021AA5, + 0x1B80, 0x00021AA7, + 0x1B80, 0x00011AB5, + 0x1B80, 0x00011AB7, + 0x1B80, 0x00221AC5, + 0x1B80, 0x00221AC7, + 0x1B80, 0x7B201AD5, + 0x1B80, 0x7B201AD7, + 0x1B80, 0x7A001AE5, + 0x1B80, 0x7A001AE7, + 0x1B80, 0x79001AF5, + 0x1B80, 0x79001AF7, + 0x1B80, 0xE1C91B05, + 0x1B80, 0xE1C91B07, + 0x1B80, 0x00021B15, + 0x1B80, 0x00021B17, + 0x1B80, 0x00011B25, + 0x1B80, 0x00011B27, + 0x1B80, 0x74021B35, + 0x1B80, 0x74021B37, + 0x1B80, 0x003F1B45, + 0x1B80, 0x003F1B47, + 0x1B80, 0x74001B55, + 0x1B80, 0x74001B57, + 0x1B80, 0x00021B65, + 0x1B80, 0x00021B67, + 0x1B80, 0x00011B75, + 0x1B80, 0x00011B77, + 0x1B80, 0x4D041B85, + 0x1B80, 0x4D041B87, + 0x1B80, 0x2EF81B95, + 0x1B80, 0x2EF81B97, + 0x1B80, 0x00001BA5, + 0x1B80, 0x00001BA7, + 0x1B80, 0x23301BB5, + 0x1B80, 0x23301BB7, + 0x1B80, 0x00241BC5, + 0x1B80, 0x00241BC7, + 0x1B80, 0x23E01BD5, + 0x1B80, 0x23E01BD7, + 0x1B80, 0x003F1BE5, + 0x1B80, 0x003F1BE7, + 0x1B80, 0x23FC1BF5, + 0x1B80, 0x23FC1BF7, + 0x1B80, 0xBFCE1C05, + 0x1B80, 0xBFCE1C07, + 0x1B80, 0x2EF01C15, + 0x1B80, 0x2EF01C17, + 0x1B80, 0x00001C25, + 0x1B80, 0x00001C27, + 0x1B80, 0x4D001C35, + 0x1B80, 0x4D001C37, + 0x1B80, 0x00011C45, + 0x1B80, 0x00011C47, + 0x1B80, 0x549F1C55, + 0x1B80, 0x549F1C57, + 0x1B80, 0x54FF1C65, + 0x1B80, 0x54FF1C67, + 0x1B80, 0x54001C75, + 0x1B80, 0x54001C77, + 0x1B80, 0x00011C85, + 0x1B80, 0x00011C87, + 0x1B80, 0x5C311C95, + 0x1B80, 0x5C311C97, + 0x1B80, 0x07141CA5, + 0x1B80, 0x07141CA7, + 0x1B80, 0x54001CB5, + 0x1B80, 0x54001CB7, + 0x1B80, 0x5C321CC5, + 0x1B80, 0x5C321CC7, + 0x1B80, 0x00011CD5, + 0x1B80, 0x00011CD7, + 0x1B80, 0x5C321CE5, + 0x1B80, 0x5C321CE7, + 0x1B80, 0x07141CF5, + 0x1B80, 0x07141CF7, + 0x1B80, 0x54001D05, + 0x1B80, 0x54001D07, + 0x1B80, 0x5C311D15, + 0x1B80, 0x5C311D17, + 0x1B80, 0x00011D25, + 0x1B80, 0x00011D27, + 0x1B80, 0x4C981D35, + 0x1B80, 0x4C981D37, + 0x1B80, 0x4C181D45, + 0x1B80, 0x4C181D47, + 0x1B80, 0x00011D55, + 0x1B80, 0x00011D57, + 0x1B80, 0x5C321D65, + 0x1B80, 0x5C321D67, + 0x1B80, 0x62841D75, + 0x1B80, 0x62841D77, + 0x1B80, 0x66861D85, + 0x1B80, 0x66861D87, + 0x1B80, 0x6C031D95, + 0x1B80, 0x6C031D97, + 0x1B80, 0x7B201DA5, + 0x1B80, 0x7B201DA7, + 0x1B80, 0x7A001DB5, + 0x1B80, 0x7A001DB7, + 0x1B80, 0x79001DC5, + 0x1B80, 0x79001DC7, + 0x1B80, 0x7F201DD5, + 0x1B80, 0x7F201DD7, + 0x1B80, 0x7E001DE5, + 0x1B80, 0x7E001DE7, + 0x1B80, 0x7D001DF5, + 0x1B80, 0x7D001DF7, + 0x1B80, 0x09011E05, + 0x1B80, 0x09011E07, + 0x1B80, 0x0C011E15, + 0x1B80, 0x0C011E17, + 0x1B80, 0x0BA61E25, + 0x1B80, 0x0BA61E27, + 0x1B80, 0x00011E35, + 0x1B80, 0x00011E37, + 0x1B80, 0x00000006, + 0x1B80, 0x00000002, + +}; + +RTW_DECL_TABLE_PHY_COND(rtw8821c_bb, rtw_phy_cfg_bb); + +static const struct rtw_phy_pg_cfg_pair rtw8821c_bb_pg_type0[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36363636, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363636, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363636, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x22222224, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34343434, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343434, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343434, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x20202022, }, +}; + +RTW_DECL_TABLE_BB_PG(rtw8821c_bb_pg_type0); + +static const u32 rtw8821c_rf_a[] = { + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x000, 0x00010000, + 0x018, 0x00010D24, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x000, 0x00010000, + 0x018, 0x00010D24, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x000, 0x00010000, + 0x018, 0x00010D24, + 0xA0000000, 0x00000000, + 0x000, 0x00010000, + 0x018, 0x00010D24, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000002, + 0x03E, 0x0000003F, + 0x03F, 0x000C0F4E, + 0x033, 0x00000001, + 0x03E, 0x00000034, + 0x03F, 0x0004080E, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000002, + 0x03E, 0x0000003F, + 0x03F, 0x000C0F4E, + 0x033, 0x00000001, + 0x03E, 0x00000034, + 0x03F, 0x0004080E, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000002, + 0x03E, 0x0000003F, + 0x03F, 0x000C0F4E, + 0x033, 0x00000001, + 0x03E, 0x00000034, + 0x03F, 0x0004080E, + 0xA0000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000002, + 0x03E, 0x0000003F, + 0x03F, 0x000C0F4E, + 0x033, 0x00000001, + 0x03E, 0x00000034, + 0x03F, 0x0004080E, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x000005DF, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0x0B1, 0x0007DBE4, + 0x0B2, 0x000225D1, + 0x0B3, 0x000FC760, + 0x0B4, 0x00099DD0, + 0x0B5, 0x000400FC, + 0x0B6, 0x000187F0, + 0x0B7, 0x00030018, + 0x0B8, 0x00080800, + 0x0B9, 0x00000000, + 0x0BA, 0x00008000, + 0x0BB, 0x00000004, + 0x0BC, 0x00040000, + 0x0BD, 0x00000000, + 0x0BE, 0x00000000, + 0x0BF, 0x00000000, + 0x0C0, 0x00000000, + 0x0C1, 0x00000000, + 0x0C2, 0x00000000, + 0x0C3, 0x00000000, + 0x0C4, 0x00002402, + 0x0C5, 0x00000009, + 0x0C6, 0x00040299, + 0x0C7, 0x00055555, + 0x0C8, 0x0000C16C, + 0x0C9, 0x0001C140, + 0x0CA, 0x00000000, + 0x0CB, 0x00000000, + 0x0CC, 0x00000000, + 0x0CD, 0x00000000, + 0x0CE, 0x00090C00, + 0x0CF, 0x0006D200, + 0x0DF, 0x00000009, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0x0B1, 0x0007DBE4, + 0x0B2, 0x000225D1, + 0x0B3, 0x000FC760, + 0x0B4, 0x00099DD0, + 0x0B5, 0x000400FC, + 0x0B6, 0x000187F0, + 0x0B7, 0x00030018, + 0x0B8, 0x00080800, + 0x0B9, 0x00000000, + 0x0BA, 0x00008000, + 0x0BB, 0x00000004, + 0x0BC, 0x00040000, + 0x0BD, 0x00000000, + 0x0BE, 0x00000000, + 0x0BF, 0x00000000, + 0x0C0, 0x00000000, + 0x0C1, 0x00000000, + 0x0C2, 0x00000000, + 0x0C3, 0x00000000, + 0x0C4, 0x00002402, + 0x0C5, 0x00000009, + 0x0C6, 0x00040299, + 0x0C7, 0x00055555, + 0x0C8, 0x0000C16C, + 0x0C9, 0x0001C140, + 0x0CA, 0x00000000, + 0x0CB, 0x00000000, + 0x0CC, 0x00000000, + 0x0CD, 0x00000000, + 0x0CE, 0x00090C00, + 0x0CF, 0x0006D200, + 0x0DF, 0x00000009, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0x0B1, 0x0007DBE4, + 0x0B2, 0x000225D1, + 0x0B3, 0x000FC760, + 0x0B4, 0x00099DD0, + 0x0B5, 0x000400FC, + 0x0B6, 0x000187F0, + 0x0B7, 0x00030018, + 0x0B8, 0x00080800, + 0x0B9, 0x00000000, + 0x0BA, 0x00008000, + 0x0BB, 0x00000004, + 0x0BC, 0x00040000, + 0x0BD, 0x00000000, + 0x0BE, 0x00000000, + 0x0BF, 0x00000000, + 0x0C0, 0x00000000, + 0x0C1, 0x00000000, + 0x0C2, 0x00000000, + 0x0C3, 0x00000000, + 0x0C4, 0x00002402, + 0x0C5, 0x00000009, + 0x0C6, 0x00040299, + 0x0C7, 0x00055555, + 0x0C8, 0x0000C16C, + 0x0C9, 0x0001C140, + 0x0CA, 0x00000000, + 0x0CB, 0x00000000, + 0x0CC, 0x00000000, + 0x0CD, 0x00000000, + 0x0CE, 0x00090C00, + 0x0CF, 0x0006D200, + 0x0DF, 0x00000009, + 0xA0000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0x0B1, 0x0007DBE4, + 0x0B2, 0x000225D1, + 0x0B3, 0x000FC760, + 0x0B4, 0x00099DD0, + 0x0B5, 0x000400FC, + 0x0B6, 0x000187F0, + 0x0B7, 0x00030018, + 0x0B8, 0x00080800, + 0x0B9, 0x00000000, + 0x0BA, 0x00008000, + 0x0BB, 0x00000004, + 0x0BC, 0x00040000, + 0x0BD, 0x00000000, + 0x0BE, 0x00000000, + 0x0BF, 0x00000000, + 0x0C0, 0x00000000, + 0x0C1, 0x00000000, + 0x0C2, 0x00000000, + 0x0C3, 0x00000000, + 0x0C4, 0x00002402, + 0x0C5, 0x00000009, + 0x0C6, 0x00040299, + 0x0C7, 0x00055555, + 0x0C8, 0x0000C16C, + 0x0C9, 0x0001C140, + 0x0CA, 0x00000000, + 0x0CB, 0x00000000, + 0x0CC, 0x00000000, + 0x0CD, 0x00000000, + 0x0CE, 0x00090C00, + 0x0CF, 0x0006D200, + 0x0DF, 0x00000009, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00010000, + 0x033, 0x00000058, + 0x03F, 0x0000001C, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00010000, + 0x033, 0x00000058, + 0x03F, 0x0000001C, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00010000, + 0x033, 0x00000058, + 0x03F, 0x0000001C, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00010000, + 0x033, 0x00000058, + 0x03F, 0x0000001C, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00010524, + 0x081, 0x0000FCC1, + 0x089, 0x00000004, + 0x08A, 0x0008A186, + 0x08B, 0x0006FFFC, + 0x08C, 0x000312C7, + 0x08D, 0x00020888, + 0x08E, 0x00064140, + 0x08F, 0x000A8010, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00010524, + 0x081, 0x0000FCC1, + 0x089, 0x00000004, + 0x08A, 0x0008A186, + 0x08B, 0x0006FFFC, + 0x08C, 0x000312C7, + 0x08D, 0x00020888, + 0x08E, 0x00064140, + 0x08F, 0x000A8010, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00010524, + 0x081, 0x0000FCC1, + 0x089, 0x00000004, + 0x08A, 0x0008A186, + 0x08B, 0x0007060C, + 0x08C, 0x000312C7, + 0x08D, 0x00020888, + 0x08E, 0x00064140, + 0x08F, 0x000A8010, + 0xA0000000, 0x00000000, + 0x018, 0x00010524, + 0x081, 0x0000FCC1, + 0x089, 0x00000004, + 0x08A, 0x0008A186, + 0x08B, 0x0007060C, + 0x08C, 0x000312C7, + 0x08D, 0x00020888, + 0x08E, 0x00064140, + 0x08F, 0x000A8010, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0DD, 0x00000020, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0DD, 0x00000020, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0DD, 0x00000020, + 0xA0000000, 0x00000000, + 0x0DD, 0x00000020, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00020000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00020000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00020000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00020000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000007, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000006, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000005, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000004, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000003, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000002, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000001, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000000, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000007, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000006, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000005, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000004, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000003, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000002, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000001, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000000, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000007, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000006, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000005, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000004, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000003, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000002, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000001, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000000, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0xA0000000, 0x00000000, + 0x033, 0x00000007, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000006, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000005, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000004, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000003, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000002, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000001, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000000, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x0000000F, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x0000000E, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x0000000D, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x0000000C, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x0000000B, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x0000000A, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000009, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000008, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x0000000F, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x0000000E, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x0000000D, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x0000000C, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x0000000B, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x0000000A, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000009, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000008, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x0000000F, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x0000000E, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x0000000D, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x0000000C, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x0000000B, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x0000000A, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000009, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000008, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0xA0000000, 0x00000000, + 0x033, 0x0000000F, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x0000000E, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x0000000D, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x0000000C, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x0000000B, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x0000000A, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000009, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000008, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000017, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000016, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000015, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000014, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000013, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000012, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000011, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000010, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000017, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000016, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000015, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000014, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000013, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000012, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000011, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000010, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000017, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000016, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000015, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000014, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000013, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000012, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000011, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000010, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x033, 0x00000017, + 0x03E, 0x00038000, + 0x03F, 0x000C3186, + 0x033, 0x00000016, + 0x03E, 0x00038080, + 0x03F, 0x000C3186, + 0x033, 0x00000015, + 0x03E, 0x000380C8, + 0x03F, 0x000C3186, + 0x033, 0x00000014, + 0x03E, 0x00038190, + 0x03F, 0x000C3186, + 0x033, 0x00000013, + 0x03E, 0x00038998, + 0x03F, 0x000C3186, + 0x033, 0x00000012, + 0x03E, 0x00039840, + 0x03F, 0x000C3186, + 0x033, 0x00000011, + 0x03E, 0x000398C4, + 0x03F, 0x000C3186, + 0x033, 0x00000010, + 0x03E, 0x00039930, + 0x03F, 0x000C3186, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x0000000F, + 0x033, 0x00000001, + 0x03F, 0x0000000A, + 0x033, 0x00000002, + 0x03F, 0x00000005, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x0000000F, + 0x033, 0x00000001, + 0x03F, 0x0000000A, + 0x033, 0x00000002, + 0x03F, 0x00000005, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x0000000F, + 0x033, 0x00000001, + 0x03F, 0x0000000A, + 0x033, 0x00000002, + 0x03F, 0x00000005, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x0000000F, + 0x033, 0x00000001, + 0x03F, 0x0000000A, + 0x033, 0x00000002, + 0x03F, 0x00000005, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00000401, + 0x084, 0x00001209, + 0x086, 0x000001A0, + 0x087, 0x000E8180, + 0x088, 0x00006020, + 0x0DF, 0x00008009, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00000401, + 0x084, 0x00001209, + 0x086, 0x000001A0, + 0x087, 0x000E8180, + 0x088, 0x00006020, + 0x0DF, 0x00008009, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00000401, + 0x084, 0x00001209, + 0x086, 0x000001A0, + 0x087, 0x000E8180, + 0x088, 0x00006020, + 0x0DF, 0x00008009, + 0xA0000000, 0x00000000, + 0x018, 0x00000401, + 0x084, 0x00001209, + 0x086, 0x000001A0, + 0x087, 0x000E8180, + 0x088, 0x00006020, + 0x0DF, 0x00008009, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00008000, + 0x033, 0x0000000F, + 0x03F, 0x0000003C, + 0x033, 0x0000000E, + 0x03F, 0x00000038, + 0x033, 0x0000000D, + 0x03F, 0x00000030, + 0x033, 0x0000000C, + 0x03F, 0x00000028, + 0x033, 0x0000000B, + 0x03F, 0x00000020, + 0x033, 0x0000000A, + 0x03F, 0x00000018, + 0x033, 0x00000009, + 0x03F, 0x00000010, + 0x033, 0x00000008, + 0x03F, 0x00000008, + 0x033, 0x00000007, + 0x03F, 0x0000003C, + 0x033, 0x00000006, + 0x03F, 0x00000038, + 0x033, 0x00000005, + 0x03F, 0x00000030, + 0x033, 0x00000004, + 0x03F, 0x00000028, + 0x033, 0x00000003, + 0x03F, 0x00000020, + 0x033, 0x00000002, + 0x03F, 0x00000018, + 0x033, 0x00000001, + 0x03F, 0x00000010, + 0x033, 0x00000000, + 0x03F, 0x00000008, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00008000, + 0x033, 0x0000000F, + 0x03F, 0x0000003C, + 0x033, 0x0000000E, + 0x03F, 0x00000038, + 0x033, 0x0000000D, + 0x03F, 0x00000030, + 0x033, 0x0000000C, + 0x03F, 0x00000028, + 0x033, 0x0000000B, + 0x03F, 0x00000020, + 0x033, 0x0000000A, + 0x03F, 0x00000018, + 0x033, 0x00000009, + 0x03F, 0x00000010, + 0x033, 0x00000008, + 0x03F, 0x00000008, + 0x033, 0x00000007, + 0x03F, 0x0000003C, + 0x033, 0x00000006, + 0x03F, 0x00000038, + 0x033, 0x00000005, + 0x03F, 0x00000030, + 0x033, 0x00000004, + 0x03F, 0x00000028, + 0x033, 0x00000003, + 0x03F, 0x00000020, + 0x033, 0x00000002, + 0x03F, 0x00000018, + 0x033, 0x00000001, + 0x03F, 0x00000010, + 0x033, 0x00000000, + 0x03F, 0x00000008, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00008000, + 0x033, 0x0000000F, + 0x03F, 0x0000003C, + 0x033, 0x0000000E, + 0x03F, 0x00000038, + 0x033, 0x0000000D, + 0x03F, 0x00000030, + 0x033, 0x0000000C, + 0x03F, 0x00000028, + 0x033, 0x0000000B, + 0x03F, 0x00000020, + 0x033, 0x0000000A, + 0x03F, 0x00000018, + 0x033, 0x00000009, + 0x03F, 0x00000010, + 0x033, 0x00000008, + 0x03F, 0x00000008, + 0x033, 0x00000007, + 0x03F, 0x0000003C, + 0x033, 0x00000006, + 0x03F, 0x00000038, + 0x033, 0x00000005, + 0x03F, 0x00000030, + 0x033, 0x00000004, + 0x03F, 0x00000028, + 0x033, 0x00000003, + 0x03F, 0x00000020, + 0x033, 0x00000002, + 0x03F, 0x00000018, + 0x033, 0x00000001, + 0x03F, 0x00000010, + 0x033, 0x00000000, + 0x03F, 0x00000008, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00008000, + 0x033, 0x0000000F, + 0x03F, 0x0000003C, + 0x033, 0x0000000E, + 0x03F, 0x00000038, + 0x033, 0x0000000D, + 0x03F, 0x00000030, + 0x033, 0x0000000C, + 0x03F, 0x00000028, + 0x033, 0x0000000B, + 0x03F, 0x00000020, + 0x033, 0x0000000A, + 0x03F, 0x00000018, + 0x033, 0x00000009, + 0x03F, 0x00000010, + 0x033, 0x00000008, + 0x03F, 0x00000008, + 0x033, 0x00000007, + 0x03F, 0x0000003C, + 0x033, 0x00000006, + 0x03F, 0x00000038, + 0x033, 0x00000005, + 0x03F, 0x00000030, + 0x033, 0x00000004, + 0x03F, 0x00000028, + 0x033, 0x00000003, + 0x03F, 0x00000020, + 0x033, 0x00000002, + 0x03F, 0x00000018, + 0x033, 0x00000001, + 0x03F, 0x00000010, + 0x033, 0x00000000, + 0x03F, 0x00000008, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00000002, + 0x033, 0x0000001E, + 0x03F, 0x00000000, + 0x033, 0x0000001C, + 0x03F, 0x00000000, + 0x033, 0x0000000E, + 0x03F, 0x00000000, + 0x033, 0x0000000C, + 0x03F, 0x00000000, + 0x033, 0x0000000A, + 0x03F, 0x00000002, + 0x033, 0x00000008, + 0x03F, 0x00000000, + 0x033, 0x00000036, + 0x03F, 0x00000000, + 0x033, 0x00000037, + 0x03F, 0x00000000, + 0x033, 0x00000034, + 0x03F, 0x00000000, + 0x033, 0x00000026, + 0x03F, 0x00000006, + 0x033, 0x00000027, + 0x03F, 0x00000006, + 0x033, 0x00000024, + 0x03F, 0x00000006, + 0x033, 0x00000022, + 0x03F, 0x00000006, + 0x033, 0x00000020, + 0x03F, 0x00000006, + 0x033, 0x00000006, + 0x03F, 0x00000000, + 0x033, 0x00000007, + 0x03F, 0x00000006, + 0x033, 0x00000004, + 0x03F, 0x00000006, + 0x033, 0x00000002, + 0x03F, 0x00000006, + 0x033, 0x00000000, + 0x03F, 0x00000006, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00000002, + 0x033, 0x0000001E, + 0x03F, 0x00000000, + 0x033, 0x0000001C, + 0x03F, 0x00000000, + 0x033, 0x0000000E, + 0x03F, 0x00000000, + 0x033, 0x0000000C, + 0x03F, 0x00000000, + 0x033, 0x0000000A, + 0x03F, 0x00000002, + 0x033, 0x00000008, + 0x03F, 0x00000000, + 0x033, 0x00000036, + 0x03F, 0x00000000, + 0x033, 0x00000037, + 0x03F, 0x00000000, + 0x033, 0x00000034, + 0x03F, 0x00000000, + 0x033, 0x00000026, + 0x03F, 0x00000006, + 0x033, 0x00000027, + 0x03F, 0x00000006, + 0x033, 0x00000024, + 0x03F, 0x00000006, + 0x033, 0x00000022, + 0x03F, 0x00000006, + 0x033, 0x00000020, + 0x03F, 0x00000006, + 0x033, 0x00000006, + 0x03F, 0x00000000, + 0x033, 0x00000007, + 0x03F, 0x00000006, + 0x033, 0x00000004, + 0x03F, 0x00000006, + 0x033, 0x00000002, + 0x03F, 0x00000006, + 0x033, 0x00000000, + 0x03F, 0x00000006, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00000002, + 0x033, 0x0000001E, + 0x03F, 0x00000000, + 0x033, 0x0000001C, + 0x03F, 0x00000000, + 0x033, 0x0000000E, + 0x03F, 0x00000000, + 0x033, 0x0000000C, + 0x03F, 0x00000000, + 0x033, 0x0000000A, + 0x03F, 0x00000002, + 0x033, 0x00000008, + 0x03F, 0x00000000, + 0x033, 0x00000036, + 0x03F, 0x00000000, + 0x033, 0x00000037, + 0x03F, 0x00000000, + 0x033, 0x00000034, + 0x03F, 0x00000000, + 0x033, 0x00000026, + 0x03F, 0x00000006, + 0x033, 0x00000027, + 0x03F, 0x00000006, + 0x033, 0x00000024, + 0x03F, 0x00000006, + 0x033, 0x00000022, + 0x03F, 0x00000006, + 0x033, 0x00000020, + 0x03F, 0x00000006, + 0x033, 0x00000006, + 0x03F, 0x00000000, + 0x033, 0x00000007, + 0x03F, 0x00000006, + 0x033, 0x00000004, + 0x03F, 0x00000006, + 0x033, 0x00000002, + 0x03F, 0x00000006, + 0x033, 0x00000000, + 0x03F, 0x00000006, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00000002, + 0x033, 0x0000001E, + 0x03F, 0x00000000, + 0x033, 0x0000001C, + 0x03F, 0x00000000, + 0x033, 0x0000000E, + 0x03F, 0x00000000, + 0x033, 0x0000000C, + 0x03F, 0x00000000, + 0x033, 0x0000000A, + 0x03F, 0x00000002, + 0x033, 0x00000008, + 0x03F, 0x00000000, + 0x033, 0x00000036, + 0x03F, 0x00000000, + 0x033, 0x00000037, + 0x03F, 0x00000000, + 0x033, 0x00000034, + 0x03F, 0x00000000, + 0x033, 0x00000026, + 0x03F, 0x00000006, + 0x033, 0x00000027, + 0x03F, 0x00000006, + 0x033, 0x00000024, + 0x03F, 0x00000006, + 0x033, 0x00000022, + 0x03F, 0x00000006, + 0x033, 0x00000020, + 0x03F, 0x00000006, + 0x033, 0x00000006, + 0x03F, 0x00000000, + 0x033, 0x00000007, + 0x03F, 0x00000006, + 0x033, 0x00000004, + 0x03F, 0x00000006, + 0x033, 0x00000002, + 0x03F, 0x00000006, + 0x033, 0x00000000, + 0x03F, 0x00000006, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0A0, 0x000F0005, + 0x0A1, 0x0006C000, + 0x0A2, 0x0000161B, + 0x0A3, 0x000B9CBD, + 0x0AF, 0x00070000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0A0, 0x000F0005, + 0x0A1, 0x0006C000, + 0x0A2, 0x0000161B, + 0x0A3, 0x000B9CBD, + 0x0AF, 0x00070000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0A0, 0x000F0005, + 0x0A1, 0x0006C000, + 0x0A2, 0x0000161B, + 0x0A3, 0x000B9CBD, + 0x0AF, 0x00070000, + 0xA0000000, 0x00000000, + 0x0A0, 0x000F0005, + 0x0A1, 0x0006C000, + 0x0A2, 0x0000161B, + 0x0A3, 0x000B9CBD, + 0x0AF, 0x00070000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0DE, 0x00000200, + 0x0EE, 0x00000100, + 0x033, 0x00000007, + 0x03F, 0x00000043, + 0x033, 0x00000006, + 0x03F, 0x0000007A, + 0x033, 0x00000005, + 0x03F, 0x00000041, + 0x033, 0x00000004, + 0x03F, 0x00000079, + 0x033, 0x00000003, + 0x03F, 0x00000043, + 0x033, 0x00000002, + 0x03F, 0x0000007A, + 0x033, 0x00000001, + 0x03F, 0x00000041, + 0x033, 0x00000000, + 0x03F, 0x00000079, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0DE, 0x00000200, + 0x0EE, 0x00000100, + 0x033, 0x00000007, + 0x03F, 0x00000043, + 0x033, 0x00000006, + 0x03F, 0x0000007A, + 0x033, 0x00000005, + 0x03F, 0x00000041, + 0x033, 0x00000004, + 0x03F, 0x00000079, + 0x033, 0x00000003, + 0x03F, 0x00000043, + 0x033, 0x00000002, + 0x03F, 0x0000007A, + 0x033, 0x00000001, + 0x03F, 0x00000041, + 0x033, 0x00000000, + 0x03F, 0x00000079, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0DE, 0x00000200, + 0x0EE, 0x00000100, + 0x033, 0x00000007, + 0x03F, 0x00000043, + 0x033, 0x00000006, + 0x03F, 0x0000007A, + 0x033, 0x00000005, + 0x03F, 0x00000041, + 0x033, 0x00000004, + 0x03F, 0x00000079, + 0x033, 0x00000003, + 0x03F, 0x00000043, + 0x033, 0x00000002, + 0x03F, 0x0000007A, + 0x033, 0x00000001, + 0x03F, 0x00000041, + 0x033, 0x00000000, + 0x03F, 0x00000079, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0DE, 0x00000200, + 0x0EE, 0x00000100, + 0x033, 0x00000007, + 0x03F, 0x00000043, + 0x033, 0x00000006, + 0x03F, 0x0000007A, + 0x033, 0x00000005, + 0x03F, 0x00000041, + 0x033, 0x00000004, + 0x03F, 0x00000079, + 0x033, 0x00000003, + 0x03F, 0x00000043, + 0x033, 0x00000002, + 0x03F, 0x0000007A, + 0x033, 0x00000001, + 0x03F, 0x00000041, + 0x033, 0x00000000, + 0x03F, 0x00000079, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0B8, 0x00080A00, + 0x0B0, 0x000FF0FA, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0B8, 0x00080A00, + 0x0B0, 0x000FF0FA, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0B8, 0x00080A00, + 0x0B0, 0x000FF0FA, + 0xA0000000, 0x00000000, + 0x0B8, 0x00080A00, + 0x0B0, 0x000FF0FA, + 0xB0000000, 0x00000000, + 0xFFE, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0CA, 0x00080000, + 0x0C9, 0x0001C141, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0CA, 0x00080000, + 0x0C9, 0x0001C141, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0CA, 0x00080000, + 0x0C9, 0x0001C141, + 0xA0000000, 0x00000000, + 0x0CA, 0x00080000, + 0x0C9, 0x0001C141, + 0xB0000000, 0x00000000, + 0xFFE, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0xA0000000, 0x00000000, + 0x0B0, 0x000FF0F8, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00018D24, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00018D24, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00018D24, + 0xA0000000, 0x00000000, + 0x018, 0x00018D24, + 0xB0000000, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0xFFE, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00010D24, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00010D24, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x018, 0x00010D24, + 0xA0000000, 0x00000000, + 0x018, 0x00010D24, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x01B, 0x00003A40, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x01B, 0x00003A40, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x01B, 0x00003A40, + 0xA0000000, 0x00000000, + 0x01B, 0x00003A40, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0004D3A3, + 0x062, 0x0000D303, + 0x063, 0x00000002, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0004D3A3, + 0x062, 0x0000D303, + 0x063, 0x00000002, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x0004D3A1, + 0x062, 0x0000D3A3, + 0x063, 0x00000002, + 0xA0000000, 0x00000000, + 0x061, 0x0004D3A1, + 0x062, 0x0000D3A3, + 0x063, 0x00000002, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, + 0x030, 0x00000000, + 0x03F, 0x00033303, + 0x030, 0x00001000, + 0x03F, 0x00033303, + 0x030, 0x00002000, + 0x03F, 0x00033303, + 0x030, 0x00003000, + 0x03F, 0x00033303, + 0x030, 0x00004000, + 0x03F, 0x00033303, + 0x030, 0x00005000, + 0x03F, 0x00033303, + 0x030, 0x00006000, + 0x03F, 0x00033303, + 0x030, 0x00007000, + 0x03F, 0x00033303, + 0x030, 0x00008000, + 0x03F, 0x00033303, + 0x030, 0x00009000, + 0x03F, 0x00033303, + 0x030, 0x0000A000, + 0x03F, 0x00033303, + 0x030, 0x0000B000, + 0x03F, 0x00033303, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, + 0x030, 0x00000000, + 0x03F, 0x000333A3, + 0x030, 0x00001000, + 0x03F, 0x000333A3, + 0x030, 0x00002000, + 0x03F, 0x000333A3, + 0x030, 0x00003000, + 0x03F, 0x000333A3, + 0x030, 0x00004000, + 0x03F, 0x000313A3, + 0x030, 0x00005000, + 0x03F, 0x000313A3, + 0x030, 0x00006000, + 0x03F, 0x000313A3, + 0x030, 0x00007000, + 0x03F, 0x000313A3, + 0x030, 0x00008000, + 0x03F, 0x000333A3, + 0x030, 0x00009000, + 0x03F, 0x000333A3, + 0x030, 0x0000A000, + 0x03F, 0x000333A3, + 0x030, 0x0000B000, + 0x03F, 0x000333A3, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000200, + 0x030, 0x00000000, + 0x03F, 0x000335A3, + 0x030, 0x00001000, + 0x03F, 0x000335A3, + 0x030, 0x00002000, + 0x03F, 0x000335A3, + 0x030, 0x00003000, + 0x03F, 0x000335A3, + 0x030, 0x00004000, + 0x03F, 0x000335A3, + 0x030, 0x00005000, + 0x03F, 0x000335A3, + 0x030, 0x00006000, + 0x03F, 0x000335A3, + 0x030, 0x00007000, + 0x03F, 0x000335A3, + 0x030, 0x00008000, + 0x03F, 0x000335A3, + 0x030, 0x00009000, + 0x03F, 0x000335A3, + 0x030, 0x0000A000, + 0x03F, 0x000335A3, + 0x030, 0x0000B000, + 0x03F, 0x000335A3, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000200, + 0x030, 0x00000000, + 0x03F, 0x000335A3, + 0x030, 0x00001000, + 0x03F, 0x000335A3, + 0x030, 0x00002000, + 0x03F, 0x000335A3, + 0x030, 0x00003000, + 0x03F, 0x000335A3, + 0x030, 0x00004000, + 0x03F, 0x000335A3, + 0x030, 0x00005000, + 0x03F, 0x000335A3, + 0x030, 0x00006000, + 0x03F, 0x000335A3, + 0x030, 0x00007000, + 0x03F, 0x000335A3, + 0x030, 0x00008000, + 0x03F, 0x000335A3, + 0x030, 0x00009000, + 0x03F, 0x000335A3, + 0x030, 0x0000A000, + 0x03F, 0x000335A3, + 0x030, 0x0000B000, + 0x03F, 0x000335A3, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, + 0x033, 0x00000000, + 0x03F, 0x00033303, + 0x033, 0x00000001, + 0x03F, 0x00033303, + 0x033, 0x00000002, + 0x03F, 0x00033303, + 0x033, 0x00000003, + 0x03F, 0x00033303, + 0x033, 0x00000004, + 0x03F, 0x00033303, + 0x033, 0x00000005, + 0x03F, 0x00033303, + 0x033, 0x00000006, + 0x03F, 0x00033303, + 0x033, 0x00000007, + 0x03F, 0x00033303, + 0x033, 0x00000008, + 0x03F, 0x00033303, + 0x033, 0x00000009, + 0x03F, 0x00033303, + 0x033, 0x0000000A, + 0x03F, 0x00033303, + 0x033, 0x0000000B, + 0x03F, 0x00033303, + 0x033, 0x0000000C, + 0x03F, 0x00033303, + 0x033, 0x0000000D, + 0x03F, 0x00033303, + 0x033, 0x0000000E, + 0x03F, 0x00033303, + 0x033, 0x0000000F, + 0x03F, 0x00033303, + 0x033, 0x00000010, + 0x03F, 0x00033303, + 0x033, 0x00000011, + 0x03F, 0x00033303, + 0x033, 0x00000012, + 0x03F, 0x00033303, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, + 0x033, 0x00000000, + 0x03F, 0x000333A3, + 0x033, 0x00000001, + 0x03F, 0x000333A3, + 0x033, 0x00000002, + 0x03F, 0x000333A3, + 0x033, 0x00000003, + 0x03F, 0x000333A3, + 0x033, 0x00000004, + 0x03F, 0x000333A3, + 0x033, 0x00000005, + 0x03F, 0x000333A3, + 0x033, 0x00000006, + 0x03F, 0x000333A3, + 0x033, 0x00000007, + 0x03F, 0x000333A3, + 0x033, 0x00000008, + 0x03F, 0x000313A3, + 0x033, 0x00000009, + 0x03F, 0x000313A3, + 0x033, 0x0000000A, + 0x03F, 0x000313A3, + 0x033, 0x0000000B, + 0x03F, 0x000313A3, + 0x033, 0x0000000C, + 0x03F, 0x000313A3, + 0x033, 0x0000000D, + 0x03F, 0x000333A3, + 0x033, 0x0000000E, + 0x03F, 0x000333A3, + 0x033, 0x0000000F, + 0x03F, 0x000333A3, + 0x033, 0x00000010, + 0x03F, 0x000333A3, + 0x033, 0x00000011, + 0x03F, 0x000333A3, + 0x033, 0x00000012, + 0x03F, 0x000333A3, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000080, + 0x033, 0x00000000, + 0x03F, 0x000335A3, + 0x033, 0x00000001, + 0x03F, 0x000335A3, + 0x033, 0x00000002, + 0x03F, 0x000335A3, + 0x033, 0x00000003, + 0x03F, 0x000335A3, + 0x033, 0x00000004, + 0x03F, 0x000335A3, + 0x033, 0x00000005, + 0x03F, 0x000335A3, + 0x033, 0x00000006, + 0x03F, 0x000335A3, + 0x033, 0x00000007, + 0x03F, 0x000335A3, + 0x033, 0x00000008, + 0x03F, 0x000335A3, + 0x033, 0x00000009, + 0x03F, 0x000335A3, + 0x033, 0x0000000A, + 0x03F, 0x000335A3, + 0x033, 0x0000000B, + 0x03F, 0x000335A3, + 0x033, 0x0000000C, + 0x03F, 0x000335A3, + 0x033, 0x0000000D, + 0x03F, 0x000335A3, + 0x033, 0x0000000E, + 0x03F, 0x000335A3, + 0x033, 0x0000000F, + 0x03F, 0x000335A3, + 0x033, 0x00000010, + 0x03F, 0x000335A3, + 0x033, 0x00000011, + 0x03F, 0x000335A3, + 0x033, 0x00000012, + 0x03F, 0x000335A3, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000080, + 0x033, 0x00000000, + 0x03F, 0x000335A3, + 0x033, 0x00000001, + 0x03F, 0x000335A3, + 0x033, 0x00000002, + 0x03F, 0x000335A3, + 0x033, 0x00000003, + 0x03F, 0x000335A3, + 0x033, 0x00000004, + 0x03F, 0x000335A3, + 0x033, 0x00000005, + 0x03F, 0x000335A3, + 0x033, 0x00000006, + 0x03F, 0x000335A3, + 0x033, 0x00000007, + 0x03F, 0x000335A3, + 0x033, 0x00000008, + 0x03F, 0x000335A3, + 0x033, 0x00000009, + 0x03F, 0x000335A3, + 0x033, 0x0000000A, + 0x03F, 0x000335A3, + 0x033, 0x0000000B, + 0x03F, 0x000335A3, + 0x033, 0x0000000C, + 0x03F, 0x000335A3, + 0x033, 0x0000000D, + 0x03F, 0x000335A3, + 0x033, 0x0000000E, + 0x03F, 0x000335A3, + 0x033, 0x0000000F, + 0x03F, 0x000335A3, + 0x033, 0x00000010, + 0x03F, 0x000335A3, + 0x033, 0x00000011, + 0x03F, 0x000335A3, + 0x033, 0x00000012, + 0x03F, 0x000335A3, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000040, + 0x030, 0x00000644, + 0x030, 0x00001135, + 0x030, 0x00002133, + 0x030, 0x00004000, + 0x030, 0x00005000, + 0x030, 0x00006000, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000040, + 0x030, 0x00000644, + 0x030, 0x00001412, + 0x030, 0x00002202, + 0x030, 0x00004000, + 0x030, 0x00005000, + 0x030, 0x00006000, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000040, + 0x030, 0x00000640, + 0x030, 0x00001512, + 0x030, 0x00002202, + 0x030, 0x00004000, + 0x030, 0x00005000, + 0x030, 0x00006000, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000040, + 0x030, 0x00000640, + 0x030, 0x00001512, + 0x030, 0x00002202, + 0x030, 0x00004000, + 0x030, 0x00005000, + 0x030, 0x00006000, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000800, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000800, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000800, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000800, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, + 0x03F, 0x00000001, + 0x033, 0x00000021, + 0x03F, 0x00000004, + 0x033, 0x00000022, + 0x03F, 0x00000007, + 0x033, 0x00000023, + 0x03F, 0x00000024, + 0x033, 0x00000024, + 0x03F, 0x00000027, + 0x033, 0x00000025, + 0x03F, 0x0000002A, + 0x033, 0x00000026, + 0x03F, 0x0000002D, + 0x033, 0x00000027, + 0x03F, 0x00000030, + 0x033, 0x00000028, + 0x03F, 0x00000033, + 0x033, 0x00000029, + 0x03F, 0x00000036, + 0x033, 0x0000002A, + 0x03F, 0x00000039, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, + 0x03F, 0x00000E42, + 0x033, 0x00000021, + 0x03F, 0x00000E45, + 0x033, 0x00000022, + 0x03F, 0x00000E65, + 0x033, 0x00000023, + 0x03F, 0x00000E68, + 0x033, 0x00000024, + 0x03F, 0x00000EE4, + 0x033, 0x00000025, + 0x03F, 0x00000EE7, + 0x033, 0x00000026, + 0x03F, 0x00000EEA, + 0x033, 0x00000027, + 0x03F, 0x00000EED, + 0x033, 0x00000028, + 0x03F, 0x00000EF0, + 0x033, 0x00000029, + 0x03F, 0x00000EF3, + 0x033, 0x0000002A, + 0x03F, 0x00000EF6, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000020, + 0x03F, 0x00000E42, + 0x033, 0x00000021, + 0x03F, 0x00000E45, + 0x033, 0x00000022, + 0x03F, 0x00000E48, + 0x033, 0x00000023, + 0x03F, 0x00000E68, + 0x033, 0x00000024, + 0x03F, 0x00000E6B, + 0x033, 0x00000025, + 0x03F, 0x00000EAA, + 0x033, 0x00000026, + 0x03F, 0x00000EEA, + 0x033, 0x00000027, + 0x03F, 0x00000EED, + 0x033, 0x00000028, + 0x03F, 0x00000EF0, + 0x033, 0x00000029, + 0x03F, 0x00000EF3, + 0x033, 0x0000002A, + 0x03F, 0x00000EF6, + 0xA0000000, 0x00000000, + 0x033, 0x00000020, + 0x03F, 0x00000E42, + 0x033, 0x00000021, + 0x03F, 0x00000E45, + 0x033, 0x00000022, + 0x03F, 0x00000E65, + 0x033, 0x00000023, + 0x03F, 0x00000E68, + 0x033, 0x00000024, + 0x03F, 0x00000EE4, + 0x033, 0x00000025, + 0x03F, 0x00000EE7, + 0x033, 0x00000026, + 0x03F, 0x00000EEA, + 0x033, 0x00000027, + 0x03F, 0x00000EED, + 0x033, 0x00000028, + 0x03F, 0x00000EF0, + 0x033, 0x00000029, + 0x03F, 0x00000EF3, + 0x033, 0x0000002A, + 0x03F, 0x00000EF6, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, + 0x03F, 0x00000001, + 0x033, 0x00000061, + 0x03F, 0x00000004, + 0x033, 0x00000062, + 0x03F, 0x00000007, + 0x033, 0x00000063, + 0x03F, 0x00000024, + 0x033, 0x00000064, + 0x03F, 0x00000027, + 0x033, 0x00000065, + 0x03F, 0x0000002A, + 0x033, 0x00000066, + 0x03F, 0x0000002D, + 0x033, 0x00000067, + 0x03F, 0x00000030, + 0x033, 0x00000068, + 0x03F, 0x00000033, + 0x033, 0x00000069, + 0x03F, 0x00000036, + 0x033, 0x0000006A, + 0x03F, 0x00000039, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, + 0x03F, 0x00000E42, + 0x033, 0x00000061, + 0x03F, 0x00000E45, + 0x033, 0x00000062, + 0x03F, 0x00000E65, + 0x033, 0x00000063, + 0x03F, 0x00000E68, + 0x033, 0x00000064, + 0x03F, 0x00000EE5, + 0x033, 0x00000065, + 0x03F, 0x00000EE8, + 0x033, 0x00000066, + 0x03F, 0x00000EEB, + 0x033, 0x00000067, + 0x03F, 0x00000EEE, + 0x033, 0x00000068, + 0x03F, 0x00000EF1, + 0x033, 0x00000069, + 0x03F, 0x00000EF4, + 0x033, 0x0000006A, + 0x03F, 0x00000EF7, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x00000060, + 0x03F, 0x00000E09, + 0x033, 0x00000061, + 0x03F, 0x00000E43, + 0x033, 0x00000062, + 0x03F, 0x00000E46, + 0x033, 0x00000063, + 0x03F, 0x00000E49, + 0x033, 0x00000064, + 0x03F, 0x00000E88, + 0x033, 0x00000065, + 0x03F, 0x00000E8B, + 0x033, 0x00000066, + 0x03F, 0x00000ECB, + 0x033, 0x00000067, + 0x03F, 0x00000ECE, + 0x033, 0x00000068, + 0x03F, 0x00000EF0, + 0x033, 0x00000069, + 0x03F, 0x00000EF3, + 0x033, 0x0000006A, + 0x03F, 0x00000EF6, + 0xA0000000, 0x00000000, + 0x033, 0x00000060, + 0x03F, 0x00000E42, + 0x033, 0x00000061, + 0x03F, 0x00000E45, + 0x033, 0x00000062, + 0x03F, 0x00000E65, + 0x033, 0x00000063, + 0x03F, 0x00000E68, + 0x033, 0x00000064, + 0x03F, 0x00000EE5, + 0x033, 0x00000065, + 0x03F, 0x00000EE8, + 0x033, 0x00000066, + 0x03F, 0x00000EEB, + 0x033, 0x00000067, + 0x03F, 0x00000EEE, + 0x033, 0x00000068, + 0x03F, 0x00000EF1, + 0x033, 0x00000069, + 0x03F, 0x00000EF4, + 0x033, 0x0000006A, + 0x03F, 0x00000EF7, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, + 0x03F, 0x00000001, + 0x033, 0x000000A1, + 0x03F, 0x00000004, + 0x033, 0x000000A2, + 0x03F, 0x00000007, + 0x033, 0x000000A3, + 0x03F, 0x00000025, + 0x033, 0x000000A4, + 0x03F, 0x00000028, + 0x033, 0x000000A5, + 0x03F, 0x0000002B, + 0x033, 0x000000A6, + 0x03F, 0x0000002E, + 0x033, 0x000000A7, + 0x03F, 0x00000031, + 0x033, 0x000000A8, + 0x03F, 0x00000034, + 0x033, 0x000000A9, + 0x03F, 0x00000037, + 0x033, 0x000000AA, + 0x03F, 0x0000003A, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, + 0x03F, 0x00000E09, + 0x033, 0x000000A1, + 0x03F, 0x00000E43, + 0x033, 0x000000A2, + 0x03F, 0x00000E64, + 0x033, 0x000000A3, + 0x03F, 0x00000E67, + 0x033, 0x000000A4, + 0x03F, 0x00000EE4, + 0x033, 0x000000A5, + 0x03F, 0x00000EE7, + 0x033, 0x000000A6, + 0x03F, 0x00000EEA, + 0x033, 0x000000A7, + 0x03F, 0x00000EED, + 0x033, 0x000000A8, + 0x03F, 0x00000EF0, + 0x033, 0x000000A9, + 0x03F, 0x00000EF3, + 0x033, 0x000000AA, + 0x03F, 0x00000EF6, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x033, 0x000000A0, + 0x03F, 0x00000E08, + 0x033, 0x000000A1, + 0x03F, 0x00000E42, + 0x033, 0x000000A2, + 0x03F, 0x00000E45, + 0x033, 0x000000A3, + 0x03F, 0x00000E48, + 0x033, 0x000000A4, + 0x03F, 0x00000EA5, + 0x033, 0x000000A5, + 0x03F, 0x00000EA8, + 0x033, 0x000000A6, + 0x03F, 0x00000ECA, + 0x033, 0x000000A7, + 0x03F, 0x00000ECD, + 0x033, 0x000000A8, + 0x03F, 0x00000EEF, + 0x033, 0x000000A9, + 0x03F, 0x00000EF2, + 0x033, 0x000000AA, + 0x03F, 0x00000EF5, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x033, 0x000000A0, + 0x03F, 0x00000E09, + 0x033, 0x000000A1, + 0x03F, 0x00000E43, + 0x033, 0x000000A2, + 0x03F, 0x00000E64, + 0x033, 0x000000A3, + 0x03F, 0x00000E67, + 0x033, 0x000000A4, + 0x03F, 0x00000EE4, + 0x033, 0x000000A5, + 0x03F, 0x00000EE7, + 0x033, 0x000000A6, + 0x03F, 0x00000EEA, + 0x033, 0x000000A7, + 0x03F, 0x00000EED, + 0x033, 0x000000A8, + 0x03F, 0x00000EF0, + 0x033, 0x000000A9, + 0x03F, 0x00000EF3, + 0x033, 0x000000AA, + 0x03F, 0x00000EF6, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x0006AC00, + 0x033, 0x00000001, + 0x03F, 0x00060C00, + 0x033, 0x00000002, + 0x03F, 0x0006AC00, + 0x033, 0x00000003, + 0x03F, 0x00086A00, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x0006AC00, + 0x033, 0x00000001, + 0x03F, 0x00060C00, + 0x033, 0x00000002, + 0x03F, 0x0006AC00, + 0x033, 0x00000003, + 0x03F, 0x00086A00, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x0006AC00, + 0x033, 0x00000001, + 0x03F, 0x00060C00, + 0x033, 0x00000002, + 0x03F, 0x0006AC00, + 0x033, 0x00000003, + 0x03F, 0x00086A00, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000400, + 0x033, 0x00000000, + 0x03F, 0x0006AC00, + 0x033, 0x00000001, + 0x03F, 0x00060C00, + 0x033, 0x00000002, + 0x03F, 0x0006AC00, + 0x033, 0x00000003, + 0x03F, 0x00086A00, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000100, + 0x033, 0x00000000, + 0x03F, 0x00000040, + 0x033, 0x00000001, + 0x03F, 0x00000040, + 0x033, 0x00000002, + 0x03F, 0x00000040, + 0x033, 0x00000003, + 0x03F, 0x00000040, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000100, + 0x033, 0x00000000, + 0x03F, 0x00000040, + 0x033, 0x00000001, + 0x03F, 0x00000040, + 0x033, 0x00000002, + 0x03F, 0x00000040, + 0x033, 0x00000003, + 0x03F, 0x00000040, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000100, + 0x033, 0x00000000, + 0x03F, 0x00000040, + 0x033, 0x00000001, + 0x03F, 0x00000040, + 0x033, 0x00000002, + 0x03F, 0x00000040, + 0x033, 0x00000003, + 0x03F, 0x00000040, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000100, + 0x033, 0x00000000, + 0x03F, 0x00000040, + 0x033, 0x00000001, + 0x03F, 0x00000040, + 0x033, 0x00000002, + 0x03F, 0x00000040, + 0x033, 0x00000003, + 0x03F, 0x00000040, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00040000, + 0x033, 0x00000000, + 0x03F, 0x00086A40, + 0x033, 0x00000001, + 0x03F, 0x00086A40, + 0x033, 0x00000002, + 0x03F, 0x00086A40, + 0x033, 0x00000003, + 0x03F, 0x00086A40, + 0x033, 0x00000004, + 0x03F, 0x00086A40, + 0x033, 0x00000005, + 0x03F, 0x00086A40, + 0x033, 0x00000006, + 0x03F, 0x00084A40, + 0x033, 0x00000007, + 0x03F, 0x00084A40, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00040000, + 0x033, 0x00000000, + 0x03F, 0x00086A40, + 0x033, 0x00000001, + 0x03F, 0x00086A40, + 0x033, 0x00000002, + 0x03F, 0x00086A40, + 0x033, 0x00000003, + 0x03F, 0x00086A40, + 0x033, 0x00000004, + 0x03F, 0x00086A40, + 0x033, 0x00000005, + 0x03F, 0x00086A40, + 0x033, 0x00000006, + 0x03F, 0x00084A40, + 0x033, 0x00000007, + 0x03F, 0x00084A40, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00040000, + 0x033, 0x00000000, + 0x03F, 0x00086A40, + 0x033, 0x00000001, + 0x03F, 0x00086A40, + 0x033, 0x00000002, + 0x03F, 0x00086A40, + 0x033, 0x00000003, + 0x03F, 0x00086A40, + 0x033, 0x00000004, + 0x03F, 0x00086A40, + 0x033, 0x00000005, + 0x03F, 0x00086A40, + 0x033, 0x00000006, + 0x03F, 0x00084A40, + 0x033, 0x00000007, + 0x03F, 0x00084A40, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00040000, + 0x033, 0x00000000, + 0x03F, 0x00086A40, + 0x033, 0x00000001, + 0x03F, 0x00086A40, + 0x033, 0x00000002, + 0x03F, 0x00086A40, + 0x033, 0x00000003, + 0x03F, 0x00086A40, + 0x033, 0x00000004, + 0x03F, 0x00086A40, + 0x033, 0x00000005, + 0x03F, 0x00086A40, + 0x033, 0x00000006, + 0x03F, 0x00084A40, + 0x033, 0x00000007, + 0x03F, 0x00084A40, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x051, 0x000801A8, + 0x052, 0x000972E3, + 0x053, 0x00008069, + 0x054, 0x00030032, + 0x055, 0x00082003, + 0x056, 0x00051CCB, + 0x057, 0x0000CFC2, + 0x058, 0x00000010, + 0x059, 0x00030000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x051, 0x000801A8, + 0x052, 0x000972E3, + 0x053, 0x00008069, + 0x054, 0x00030032, + 0x055, 0x00082003, + 0x056, 0x00051CCB, + 0x057, 0x0000CFC2, + 0x058, 0x00000010, + 0x059, 0x00030000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x051, 0x000801A8, + 0x052, 0x000972E3, + 0x053, 0x00008069, + 0x054, 0x00030032, + 0x055, 0x00082003, + 0x056, 0x00051CCB, + 0x057, 0x0000CFC2, + 0x058, 0x00000010, + 0x059, 0x00030000, + 0xA0000000, 0x00000000, + 0x051, 0x000801A8, + 0x052, 0x000972E3, + 0x053, 0x00008069, + 0x054, 0x00030032, + 0x055, 0x00082003, + 0x056, 0x00051CCB, + 0x057, 0x0000CFC2, + 0x058, 0x00000010, + 0x059, 0x00030000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000800, + 0x033, 0x00000000, + 0x03F, 0x00051429, + 0x033, 0x00000001, + 0x03F, 0x00051449, + 0x033, 0x00000002, + 0x03F, 0x0005144C, + 0x033, 0x00000003, + 0x03F, 0x00051C66, + 0x033, 0x00000004, + 0x03F, 0x00051C69, + 0x033, 0x00000005, + 0x03F, 0x00051C6C, + 0x033, 0x00000006, + 0x03F, 0x00051CE8, + 0x033, 0x00000007, + 0x03F, 0x00051CEB, + 0x033, 0x00000008, + 0x03F, 0x00051CEE, + 0x033, 0x00000009, + 0x03F, 0x00051CF1, + 0x033, 0x0000000A, + 0x03F, 0x00051CF4, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000800, + 0x033, 0x00000000, + 0x03F, 0x00051429, + 0x033, 0x00000001, + 0x03F, 0x00051449, + 0x033, 0x00000002, + 0x03F, 0x0005144C, + 0x033, 0x00000003, + 0x03F, 0x00051C66, + 0x033, 0x00000004, + 0x03F, 0x00051C69, + 0x033, 0x00000005, + 0x03F, 0x00051C6C, + 0x033, 0x00000006, + 0x03F, 0x00051CE8, + 0x033, 0x00000007, + 0x03F, 0x00051CEB, + 0x033, 0x00000008, + 0x03F, 0x00051CEE, + 0x033, 0x00000009, + 0x03F, 0x00051CF1, + 0x033, 0x0000000A, + 0x03F, 0x00051CF4, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000800, + 0x033, 0x00000000, + 0x03F, 0x00051427, + 0x033, 0x00000001, + 0x03F, 0x00051446, + 0x033, 0x00000002, + 0x03F, 0x00051449, + 0x033, 0x00000003, + 0x03F, 0x0005144C, + 0x033, 0x00000004, + 0x03F, 0x00051C67, + 0x033, 0x00000005, + 0x03F, 0x00051C6A, + 0x033, 0x00000006, + 0x03F, 0x00051C8B, + 0x033, 0x00000007, + 0x03F, 0x00051CE9, + 0x033, 0x00000008, + 0x03F, 0x00051CEC, + 0x033, 0x00000009, + 0x03F, 0x00051CEF, + 0x033, 0x0000000A, + 0x03F, 0x00051CF2, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000800, + 0x033, 0x00000000, + 0x03F, 0x00051427, + 0x033, 0x00000001, + 0x03F, 0x00051446, + 0x033, 0x00000002, + 0x03F, 0x00051449, + 0x033, 0x00000003, + 0x03F, 0x0005144C, + 0x033, 0x00000004, + 0x03F, 0x00051C67, + 0x033, 0x00000005, + 0x03F, 0x00051C6A, + 0x033, 0x00000006, + 0x03F, 0x00051C8B, + 0x033, 0x00000007, + 0x03F, 0x00051CE9, + 0x033, 0x00000008, + 0x03F, 0x00051CEC, + 0x033, 0x00000009, + 0x03F, 0x00051CEF, + 0x033, 0x0000000A, + 0x03F, 0x00051CF2, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00086E00, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00086E00, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00086E00, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00004000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00086E00, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x00000000, + 0x033, 0x00000001, + 0x03F, 0x00000000, + 0x033, 0x00000002, + 0x03F, 0x00000000, + 0x033, 0x00000003, + 0x03F, 0x00000000, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x00000000, + 0x033, 0x00000001, + 0x03F, 0x00000000, + 0x033, 0x00000002, + 0x03F, 0x00000000, + 0x033, 0x00000003, + 0x03F, 0x00000000, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x00000000, + 0x033, 0x00000001, + 0x03F, 0x00000000, + 0x033, 0x00000002, + 0x03F, 0x00000000, + 0x033, 0x00000003, + 0x03F, 0x00000000, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00002000, + 0x033, 0x00000000, + 0x03F, 0x00000000, + 0x033, 0x00000001, + 0x03F, 0x00000000, + 0x033, 0x00000002, + 0x03F, 0x00000000, + 0x033, 0x00000003, + 0x03F, 0x00000000, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00080000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00048400, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x033, 0x00000004, + 0x03F, 0x00048400, + 0x033, 0x00000005, + 0x03F, 0x00048400, + 0x033, 0x00000006, + 0x03F, 0x00048400, + 0x033, 0x00000007, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00080000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00048400, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x033, 0x00000004, + 0x03F, 0x00048400, + 0x033, 0x00000005, + 0x03F, 0x00048400, + 0x033, 0x00000006, + 0x03F, 0x00048400, + 0x033, 0x00000007, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00080000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00048400, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x033, 0x00000004, + 0x03F, 0x00048400, + 0x033, 0x00000005, + 0x03F, 0x00048400, + 0x033, 0x00000006, + 0x03F, 0x00048400, + 0x033, 0x00000007, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00080000, + 0x033, 0x00000000, + 0x03F, 0x00048400, + 0x033, 0x00000001, + 0x03F, 0x00048400, + 0x033, 0x00000002, + 0x03F, 0x00048400, + 0x033, 0x00000003, + 0x03F, 0x00048400, + 0x033, 0x00000004, + 0x03F, 0x00048400, + 0x033, 0x00000005, + 0x03F, 0x00048400, + 0x033, 0x00000006, + 0x03F, 0x00048400, + 0x033, 0x00000007, + 0x03F, 0x00048400, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x070, 0x00008000, + 0x075, 0x000027DA, + 0x076, 0x00006997, + 0x077, 0x00070418, + 0x078, 0x000BB000, + 0x07D, 0x00007600, + 0x07F, 0x00000000, + 0x06A, 0x000F4C00, + 0x065, 0x00082030, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x070, 0x00008000, + 0x075, 0x000027DA, + 0x076, 0x00006997, + 0x077, 0x00070418, + 0x078, 0x000BB000, + 0x07D, 0x00007600, + 0x07F, 0x00000000, + 0x06A, 0x000F4C00, + 0x065, 0x00082030, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x070, 0x00008000, + 0x075, 0x000027DA, + 0x076, 0x00006997, + 0x077, 0x00070418, + 0x078, 0x000BB000, + 0x07D, 0x00007600, + 0x07F, 0x00000000, + 0x06A, 0x000F4C00, + 0x065, 0x00082030, + 0xA0000000, 0x00000000, + 0x070, 0x00008000, + 0x075, 0x000027DA, + 0x076, 0x00006997, + 0x077, 0x00070418, + 0x078, 0x000BB000, + 0x07D, 0x00007600, + 0x07F, 0x00000000, + 0x06A, 0x000F4C00, + 0x065, 0x00082030, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00008000, + 0x033, 0x00000000, + 0x03F, 0x00051427, + 0x033, 0x00000001, + 0x03F, 0x00051446, + 0x033, 0x00000002, + 0x03F, 0x00051449, + 0x033, 0x00000003, + 0x03F, 0x0005144C, + 0x033, 0x00000004, + 0x03F, 0x00051C69, + 0x033, 0x00000005, + 0x03F, 0x00051C6C, + 0x033, 0x00000006, + 0x03F, 0x00051C8D, + 0x033, 0x00000007, + 0x03F, 0x00051CEB, + 0x033, 0x00000008, + 0x03F, 0x00051CEE, + 0x033, 0x00000009, + 0x03F, 0x00051CF1, + 0x033, 0x0000000A, + 0x03F, 0x00051CF4, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00008000, + 0x033, 0x00000000, + 0x03F, 0x00051427, + 0x033, 0x00000001, + 0x03F, 0x00051446, + 0x033, 0x00000002, + 0x03F, 0x00051449, + 0x033, 0x00000003, + 0x03F, 0x0005144C, + 0x033, 0x00000004, + 0x03F, 0x00051C69, + 0x033, 0x00000005, + 0x03F, 0x00051C6C, + 0x033, 0x00000006, + 0x03F, 0x00051C8D, + 0x033, 0x00000007, + 0x03F, 0x00051CEB, + 0x033, 0x00000008, + 0x03F, 0x00051CEE, + 0x033, 0x00000009, + 0x03F, 0x00051CF1, + 0x033, 0x0000000A, + 0x03F, 0x00051CF4, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00008000, + 0x033, 0x00000000, + 0x03F, 0x00051427, + 0x033, 0x00000001, + 0x03F, 0x00051446, + 0x033, 0x00000002, + 0x03F, 0x00051449, + 0x033, 0x00000003, + 0x03F, 0x0005144C, + 0x033, 0x00000004, + 0x03F, 0x00051C69, + 0x033, 0x00000005, + 0x03F, 0x00051C6C, + 0x033, 0x00000006, + 0x03F, 0x00051C8D, + 0x033, 0x00000007, + 0x03F, 0x00051CEB, + 0x033, 0x00000008, + 0x03F, 0x00051CEE, + 0x033, 0x00000009, + 0x03F, 0x00051CF1, + 0x033, 0x0000000A, + 0x03F, 0x00051CF4, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00008000, + 0x033, 0x00000000, + 0x03F, 0x00051427, + 0x033, 0x00000001, + 0x03F, 0x00051446, + 0x033, 0x00000002, + 0x03F, 0x00051449, + 0x033, 0x00000003, + 0x03F, 0x0005144C, + 0x033, 0x00000004, + 0x03F, 0x00051C69, + 0x033, 0x00000005, + 0x03F, 0x00051C6C, + 0x033, 0x00000006, + 0x03F, 0x00051C8D, + 0x033, 0x00000007, + 0x03F, 0x00051CEB, + 0x033, 0x00000008, + 0x03F, 0x00051CEE, + 0x033, 0x00000009, + 0x03F, 0x00051CF1, + 0x033, 0x0000000A, + 0x03F, 0x00051CF4, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000010, + 0x033, 0x00000000, + 0x008, 0x0009C060, + 0x033, 0x00000001, + 0x008, 0x0009C060, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000010, + 0x033, 0x00000000, + 0x008, 0x0009C060, + 0x033, 0x00000001, + 0x008, 0x0009C060, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00000010, + 0x033, 0x00000000, + 0x008, 0x0009C060, + 0x033, 0x00000001, + 0x008, 0x0009C060, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00000010, + 0x033, 0x00000000, + 0x008, 0x0009C060, + 0x033, 0x00000001, + 0x008, 0x0009C060, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000024, + 0x03E, 0x0000003F, + 0x03F, 0x00060FDE, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000024, + 0x03E, 0x0000003F, + 0x03F, 0x00060FDE, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000024, + 0x03E, 0x0000003F, + 0x03F, 0x00060FDE, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000024, + 0x03E, 0x0000003F, + 0x03F, 0x00060FDE, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000025, + 0x03E, 0x00000037, + 0x03F, 0x0007EFCE, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000025, + 0x03E, 0x00000037, + 0x03F, 0x0007EFCE, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000025, + 0x03E, 0x00000037, + 0x03F, 0x0007EFCE, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000025, + 0x03E, 0x00000037, + 0x03F, 0x0007EFCE, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000026, + 0x03E, 0x00000037, + 0x03F, 0x0005EFCE, + 0x0EF, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000026, + 0x03E, 0x00000037, + 0x03F, 0x0005EFCE, + 0x0EF, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000026, + 0x03E, 0x00000037, + 0x03F, 0x0005EFCE, + 0x0EF, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EF, 0x00080000, + 0x033, 0x00000026, + 0x03E, 0x00000037, + 0x03F, 0x0005EFCE, + 0x0EF, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000004, + 0x03F, 0x00001EC1, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000004, + 0x03F, 0x00001EC1, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000004, + 0x03F, 0x00001EC1, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000004, + 0x03F, 0x00001EC1, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000005, + 0x03F, 0x00001ECF, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000005, + 0x03F, 0x00001ECF, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000005, + 0x03F, 0x00001ECF, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000005, + 0x03F, 0x00001ECF, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + 0x80001005, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000006, + 0x03F, 0x00001F9D, + 0x0EE, 0x00000000, + 0x90001004, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000006, + 0x03F, 0x00001F9D, + 0x0EE, 0x00000000, + 0x90000400, 0x00000000, 0x40000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000006, + 0x03F, 0x00001F9D, + 0x0EE, 0x00000000, + 0xA0000000, 0x00000000, + 0x0EE, 0x00001000, + 0x033, 0x00000006, + 0x03F, 0x00001F9D, + 0x0EE, 0x00000000, + 0xB0000000, 0x00000000, + +}; + +RTW_DECL_TABLE_RF_RADIO(rtw8821c_rf_a, A); + +static const struct rtw_txpwr_lmt_cfg_pair rtw8821c_txpwr_lmt_type0[] = { + { 0, 0, 0, 0, 1, 30, }, + { 2, 0, 0, 0, 1, 30, }, + { 0, 0, 0, 0, 2, 32, }, + { 2, 0, 0, 0, 2, 30, }, + { 0, 0, 0, 0, 3, 32, }, + { 2, 0, 0, 0, 3, 30, }, + { 0, 0, 0, 0, 4, 32, }, + { 2, 0, 0, 0, 4, 30, }, + { 0, 0, 0, 0, 5, 32, }, + { 2, 0, 0, 0, 5, 30, }, + { 0, 0, 0, 0, 6, 32, }, + { 2, 0, 0, 0, 6, 30, }, + { 0, 0, 0, 0, 7, 32, }, + { 2, 0, 0, 0, 7, 30, }, + { 0, 0, 0, 0, 8, 32, }, + { 2, 0, 0, 0, 8, 30, }, + { 0, 0, 0, 0, 9, 32, }, + { 2, 0, 0, 0, 9, 30, }, + { 0, 0, 0, 0, 10, 32, }, + { 2, 0, 0, 0, 10, 30, }, + { 0, 0, 0, 0, 11, 32, }, + { 2, 0, 0, 0, 11, 30, }, + { 0, 0, 0, 0, 12, 24, }, + { 2, 0, 0, 0, 12, 30, }, + { 0, 0, 0, 0, 13, 16, }, + { 2, 0, 0, 0, 13, 30, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 0, 0, 0, 1, 1, 30, }, + { 2, 0, 0, 1, 1, 30, }, + { 0, 0, 0, 1, 2, 32, }, + { 2, 0, 0, 1, 2, 30, }, + { 0, 0, 0, 1, 3, 34, }, + { 2, 0, 0, 1, 3, 30, }, + { 0, 0, 0, 1, 4, 34, }, + { 2, 0, 0, 1, 4, 30, }, + { 0, 0, 0, 1, 5, 34, }, + { 2, 0, 0, 1, 5, 30, }, + { 0, 0, 0, 1, 6, 34, }, + { 2, 0, 0, 1, 6, 30, }, + { 0, 0, 0, 1, 7, 34, }, + { 2, 0, 0, 1, 7, 30, }, + { 0, 0, 0, 1, 8, 34, }, + { 2, 0, 0, 1, 8, 30, }, + { 0, 0, 0, 1, 9, 34, }, + { 2, 0, 0, 1, 9, 30, }, + { 0, 0, 0, 1, 10, 32, }, + { 2, 0, 0, 1, 10, 30, }, + { 0, 0, 0, 1, 11, 30, }, + { 2, 0, 0, 1, 11, 30, }, + { 0, 0, 0, 1, 12, 28, }, + { 2, 0, 0, 1, 12, 30, }, + { 0, 0, 0, 1, 13, 16, }, + { 2, 0, 0, 1, 13, 30, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 26, }, + { 2, 0, 0, 2, 1, 30, }, + { 0, 0, 0, 2, 2, 30, }, + { 2, 0, 0, 2, 2, 30, }, + { 0, 0, 0, 2, 3, 32, }, + { 2, 0, 0, 2, 3, 30, }, + { 0, 0, 0, 2, 4, 34, }, + { 2, 0, 0, 2, 4, 30, }, + { 0, 0, 0, 2, 5, 34, }, + { 2, 0, 0, 2, 5, 30, }, + { 0, 0, 0, 2, 6, 34, }, + { 2, 0, 0, 2, 6, 30, }, + { 0, 0, 0, 2, 7, 34, }, + { 2, 0, 0, 2, 7, 30, }, + { 0, 0, 0, 2, 8, 34, }, + { 2, 0, 0, 2, 8, 30, }, + { 0, 0, 0, 2, 9, 32, }, + { 2, 0, 0, 2, 9, 30, }, + { 0, 0, 0, 2, 10, 30, }, + { 2, 0, 0, 2, 10, 30, }, + { 0, 0, 0, 2, 11, 28, }, + { 2, 0, 0, 2, 11, 30, }, + { 0, 0, 0, 2, 12, 26, }, + { 2, 0, 0, 2, 12, 30, }, + { 0, 0, 0, 2, 13, 12, }, + { 2, 0, 0, 2, 13, 30, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 26, }, + { 2, 0, 1, 2, 3, 30, }, + { 0, 0, 1, 2, 4, 26, }, + { 2, 0, 1, 2, 4, 30, }, + { 0, 0, 1, 2, 5, 30, }, + { 2, 0, 1, 2, 5, 30, }, + { 0, 0, 1, 2, 6, 30, }, + { 2, 0, 1, 2, 6, 30, }, + { 0, 0, 1, 2, 7, 30, }, + { 2, 0, 1, 2, 7, 30, }, + { 0, 0, 1, 2, 8, 26, }, + { 2, 0, 1, 2, 8, 30, }, + { 0, 0, 1, 2, 9, 26, }, + { 2, 0, 1, 2, 9, 30, }, + { 0, 0, 1, 2, 10, 28, }, + { 2, 0, 1, 2, 10, 30, }, + { 0, 0, 1, 2, 11, 20, }, + { 2, 0, 1, 2, 11, 30, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 63, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 63, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 0, 1, 0, 1, 36, 31, }, + { 2, 1, 0, 1, 36, 32, }, + { 0, 1, 0, 1, 40, 33, }, + { 2, 1, 0, 1, 40, 32, }, + { 0, 1, 0, 1, 44, 33, }, + { 2, 1, 0, 1, 44, 32, }, + { 0, 1, 0, 1, 48, 31, }, + { 2, 1, 0, 1, 48, 32, }, + { 0, 1, 0, 1, 52, 33, }, + { 2, 1, 0, 1, 52, 32, }, + { 0, 1, 0, 1, 56, 33, }, + { 2, 1, 0, 1, 56, 32, }, + { 0, 1, 0, 1, 60, 33, }, + { 2, 1, 0, 1, 60, 32, }, + { 0, 1, 0, 1, 64, 30, }, + { 2, 1, 0, 1, 64, 32, }, + { 0, 1, 0, 1, 100, 30, }, + { 2, 1, 0, 1, 100, 32, }, + { 0, 1, 0, 1, 104, 33, }, + { 2, 1, 0, 1, 104, 32, }, + { 0, 1, 0, 1, 108, 33, }, + { 2, 1, 0, 1, 108, 32, }, + { 0, 1, 0, 1, 112, 33, }, + { 2, 1, 0, 1, 112, 32, }, + { 0, 1, 0, 1, 116, 33, }, + { 2, 1, 0, 1, 116, 32, }, + { 0, 1, 0, 1, 120, 33, }, + { 2, 1, 0, 1, 120, 32, }, + { 0, 1, 0, 1, 124, 33, }, + { 2, 1, 0, 1, 124, 32, }, + { 0, 1, 0, 1, 128, 33, }, + { 2, 1, 0, 1, 128, 32, }, + { 0, 1, 0, 1, 132, 33, }, + { 2, 1, 0, 1, 132, 32, }, + { 0, 1, 0, 1, 136, 33, }, + { 2, 1, 0, 1, 136, 32, }, + { 0, 1, 0, 1, 140, 31, }, + { 2, 1, 0, 1, 140, 32, }, + { 0, 1, 0, 1, 144, 30, }, + { 2, 1, 0, 1, 144, 63, }, + { 0, 1, 0, 1, 149, 33, }, + { 2, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 33, }, + { 2, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 33, }, + { 2, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 33, }, + { 2, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 33, }, + { 2, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 30, }, + { 2, 1, 0, 2, 36, 32, }, + { 0, 1, 0, 2, 40, 33, }, + { 2, 1, 0, 2, 40, 32, }, + { 0, 1, 0, 2, 44, 33, }, + { 2, 1, 0, 2, 44, 32, }, + { 0, 1, 0, 2, 48, 33, }, + { 2, 1, 0, 2, 48, 32, }, + { 0, 1, 0, 2, 52, 33, }, + { 2, 1, 0, 2, 52, 32, }, + { 0, 1, 0, 2, 56, 33, }, + { 2, 1, 0, 2, 56, 32, }, + { 0, 1, 0, 2, 60, 33, }, + { 2, 1, 0, 2, 60, 32, }, + { 0, 1, 0, 2, 64, 30, }, + { 2, 1, 0, 2, 64, 32, }, + { 0, 1, 0, 2, 100, 30, }, + { 2, 1, 0, 2, 100, 32, }, + { 0, 1, 0, 2, 104, 33, }, + { 2, 1, 0, 2, 104, 32, }, + { 0, 1, 0, 2, 108, 33, }, + { 2, 1, 0, 2, 108, 32, }, + { 0, 1, 0, 2, 112, 33, }, + { 2, 1, 0, 2, 112, 32, }, + { 0, 1, 0, 2, 116, 33, }, + { 2, 1, 0, 2, 116, 32, }, + { 0, 1, 0, 2, 120, 33, }, + { 2, 1, 0, 2, 120, 32, }, + { 0, 1, 0, 2, 124, 33, }, + { 2, 1, 0, 2, 124, 32, }, + { 0, 1, 0, 2, 128, 33, }, + { 2, 1, 0, 2, 128, 32, }, + { 0, 1, 0, 2, 132, 33, }, + { 2, 1, 0, 2, 132, 32, }, + { 0, 1, 0, 2, 136, 33, }, + { 2, 1, 0, 2, 136, 32, }, + { 0, 1, 0, 2, 140, 29, }, + { 2, 1, 0, 2, 140, 32, }, + { 0, 1, 0, 2, 144, 27, }, + { 2, 1, 0, 2, 144, 63, }, + { 0, 1, 0, 2, 149, 33, }, + { 2, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 33, }, + { 2, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 33, }, + { 2, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 33, }, + { 2, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 33, }, + { 2, 1, 0, 2, 165, 63, }, + { 0, 1, 1, 2, 38, 22, }, + { 2, 1, 1, 2, 38, 32, }, + { 0, 1, 1, 2, 46, 32, }, + { 2, 1, 1, 2, 46, 32, }, + { 0, 1, 1, 2, 54, 32, }, + { 2, 1, 1, 2, 54, 32, }, + { 0, 1, 1, 2, 62, 23, }, + { 2, 1, 1, 2, 62, 32, }, + { 0, 1, 1, 2, 102, 21, }, + { 2, 1, 1, 2, 102, 32, }, + { 0, 1, 1, 2, 110, 32, }, + { 2, 1, 1, 2, 110, 32, }, + { 0, 1, 1, 2, 118, 32, }, + { 2, 1, 1, 2, 118, 32, }, + { 0, 1, 1, 2, 126, 32, }, + { 2, 1, 1, 2, 126, 32, }, + { 0, 1, 1, 2, 134, 32, }, + { 2, 1, 1, 2, 134, 32, }, + { 0, 1, 1, 2, 142, 29, }, + { 2, 1, 1, 2, 142, 63, }, + { 0, 1, 1, 2, 151, 32, }, + { 2, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 32, }, + { 2, 1, 1, 2, 159, 63, }, + { 0, 1, 2, 4, 42, 19, }, + { 2, 1, 2, 4, 42, 32, }, + { 0, 1, 2, 4, 58, 22, }, + { 2, 1, 2, 4, 58, 32, }, + { 0, 1, 2, 4, 106, 18, }, + { 2, 1, 2, 4, 106, 32, }, + { 0, 1, 2, 4, 122, 32, }, + { 2, 1, 2, 4, 122, 32, }, + { 0, 1, 2, 4, 138, 28, }, + { 2, 1, 2, 4, 138, 63, }, + { 0, 1, 2, 4, 155, 32, }, + { 2, 1, 2, 4, 155, 63, }, + { 1, 0, 0, 0, 1, 34, }, + { 3, 0, 0, 0, 1, 30, }, + { 4, 0, 0, 0, 1, 34, }, + { 5, 0, 0, 0, 1, 30, }, + { 6, 0, 0, 0, 1, 30, }, + { 7, 0, 0, 0, 1, 30, }, + { 1, 0, 0, 0, 2, 34, }, + { 3, 0, 0, 0, 2, 32, }, + { 4, 0, 0, 0, 2, 34, }, + { 5, 0, 0, 0, 2, 30, }, + { 6, 0, 0, 0, 2, 32, }, + { 7, 0, 0, 0, 2, 30, }, + { 1, 0, 0, 0, 3, 34, }, + { 3, 0, 0, 0, 3, 32, }, + { 4, 0, 0, 0, 3, 34, }, + { 5, 0, 0, 0, 3, 30, }, + { 6, 0, 0, 0, 3, 32, }, + { 7, 0, 0, 0, 3, 30, }, + { 1, 0, 0, 0, 4, 34, }, + { 3, 0, 0, 0, 4, 32, }, + { 4, 0, 0, 0, 4, 34, }, + { 5, 0, 0, 0, 4, 30, }, + { 6, 0, 0, 0, 4, 32, }, + { 7, 0, 0, 0, 4, 30, }, + { 1, 0, 0, 0, 5, 34, }, + { 3, 0, 0, 0, 5, 32, }, + { 4, 0, 0, 0, 5, 34, }, + { 5, 0, 0, 0, 5, 30, }, + { 6, 0, 0, 0, 5, 32, }, + { 7, 0, 0, 0, 5, 30, }, + { 1, 0, 0, 0, 6, 34, }, + { 3, 0, 0, 0, 6, 32, }, + { 4, 0, 0, 0, 6, 34, }, + { 5, 0, 0, 0, 6, 30, }, + { 6, 0, 0, 0, 6, 32, }, + { 7, 0, 0, 0, 6, 30, }, + { 1, 0, 0, 0, 7, 34, }, + { 3, 0, 0, 0, 7, 32, }, + { 4, 0, 0, 0, 7, 34, }, + { 5, 0, 0, 0, 7, 30, }, + { 6, 0, 0, 0, 7, 32, }, + { 7, 0, 0, 0, 7, 30, }, + { 1, 0, 0, 0, 8, 34, }, + { 3, 0, 0, 0, 8, 32, }, + { 4, 0, 0, 0, 8, 34, }, + { 5, 0, 0, 0, 8, 30, }, + { 6, 0, 0, 0, 8, 32, }, + { 7, 0, 0, 0, 8, 30, }, + { 1, 0, 0, 0, 9, 34, }, + { 3, 0, 0, 0, 9, 32, }, + { 4, 0, 0, 0, 9, 34, }, + { 5, 0, 0, 0, 9, 30, }, + { 6, 0, 0, 0, 9, 32, }, + { 7, 0, 0, 0, 9, 30, }, + { 1, 0, 0, 0, 10, 34, }, + { 3, 0, 0, 0, 10, 32, }, + { 4, 0, 0, 0, 10, 34, }, + { 5, 0, 0, 0, 10, 30, }, + { 6, 0, 0, 0, 10, 32, }, + { 7, 0, 0, 0, 10, 30, }, + { 1, 0, 0, 0, 11, 34, }, + { 3, 0, 0, 0, 11, 32, }, + { 4, 0, 0, 0, 11, 34, }, + { 5, 0, 0, 0, 11, 30, }, + { 6, 0, 0, 0, 11, 32, }, + { 7, 0, 0, 0, 11, 30, }, + { 1, 0, 0, 0, 12, 34, }, + { 3, 0, 0, 0, 12, 24, }, + { 4, 0, 0, 0, 12, 34, }, + { 5, 0, 0, 0, 12, 30, }, + { 6, 0, 0, 0, 12, 24, }, + { 7, 0, 0, 0, 12, 30, }, + { 1, 0, 0, 0, 13, 34, }, + { 3, 0, 0, 0, 13, 16, }, + { 4, 0, 0, 0, 13, 34, }, + { 5, 0, 0, 0, 13, 30, }, + { 6, 0, 0, 0, 13, 16, }, + { 7, 0, 0, 0, 13, 30, }, + { 1, 0, 0, 0, 14, 34, }, + { 3, 0, 0, 0, 14, 63, }, + { 4, 0, 0, 0, 14, 63, }, + { 5, 0, 0, 0, 14, 63, }, + { 6, 0, 0, 0, 14, 63, }, + { 7, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 1, 1, 34, }, + { 3, 0, 0, 1, 1, 30, }, + { 4, 0, 0, 1, 1, 32, }, + { 5, 0, 0, 1, 1, 30, }, + { 6, 0, 0, 1, 1, 30, }, + { 7, 0, 0, 1, 1, 30, }, + { 1, 0, 0, 1, 2, 34, }, + { 3, 0, 0, 1, 2, 32, }, + { 4, 0, 0, 1, 2, 34, }, + { 5, 0, 0, 1, 2, 30, }, + { 6, 0, 0, 1, 2, 32, }, + { 7, 0, 0, 1, 2, 30, }, + { 1, 0, 0, 1, 3, 34, }, + { 3, 0, 0, 1, 3, 34, }, + { 4, 0, 0, 1, 3, 34, }, + { 5, 0, 0, 1, 3, 30, }, + { 6, 0, 0, 1, 3, 34, }, + { 7, 0, 0, 1, 3, 30, }, + { 1, 0, 0, 1, 4, 34, }, + { 3, 0, 0, 1, 4, 34, }, + { 4, 0, 0, 1, 4, 34, }, + { 5, 0, 0, 1, 4, 30, }, + { 6, 0, 0, 1, 4, 34, }, + { 7, 0, 0, 1, 4, 30, }, + { 1, 0, 0, 1, 5, 34, }, + { 3, 0, 0, 1, 5, 34, }, + { 4, 0, 0, 1, 5, 34, }, + { 5, 0, 0, 1, 5, 30, }, + { 6, 0, 0, 1, 5, 34, }, + { 7, 0, 0, 1, 5, 30, }, + { 1, 0, 0, 1, 6, 34, }, + { 3, 0, 0, 1, 6, 34, }, + { 4, 0, 0, 1, 6, 34, }, + { 5, 0, 0, 1, 6, 30, }, + { 6, 0, 0, 1, 6, 34, }, + { 7, 0, 0, 1, 6, 30, }, + { 1, 0, 0, 1, 7, 34, }, + { 3, 0, 0, 1, 7, 34, }, + { 4, 0, 0, 1, 7, 34, }, + { 5, 0, 0, 1, 7, 30, }, + { 6, 0, 0, 1, 7, 34, }, + { 7, 0, 0, 1, 7, 30, }, + { 1, 0, 0, 1, 8, 34, }, + { 3, 0, 0, 1, 8, 34, }, + { 4, 0, 0, 1, 8, 34, }, + { 5, 0, 0, 1, 8, 30, }, + { 6, 0, 0, 1, 8, 34, }, + { 7, 0, 0, 1, 8, 30, }, + { 1, 0, 0, 1, 9, 34, }, + { 3, 0, 0, 1, 9, 34, }, + { 4, 0, 0, 1, 9, 34, }, + { 5, 0, 0, 1, 9, 30, }, + { 6, 0, 0, 1, 9, 34, }, + { 7, 0, 0, 1, 9, 30, }, + { 1, 0, 0, 1, 10, 34, }, + { 3, 0, 0, 1, 10, 32, }, + { 4, 0, 0, 1, 10, 34, }, + { 5, 0, 0, 1, 10, 30, }, + { 6, 0, 0, 1, 10, 32, }, + { 7, 0, 0, 1, 10, 30, }, + { 1, 0, 0, 1, 11, 34, }, + { 3, 0, 0, 1, 11, 30, }, + { 4, 0, 0, 1, 11, 34, }, + { 5, 0, 0, 1, 11, 30, }, + { 6, 0, 0, 1, 11, 30, }, + { 7, 0, 0, 1, 11, 30, }, + { 1, 0, 0, 1, 12, 34, }, + { 3, 0, 0, 1, 12, 28, }, + { 4, 0, 0, 1, 12, 34, }, + { 5, 0, 0, 1, 12, 30, }, + { 6, 0, 0, 1, 12, 28, }, + { 7, 0, 0, 1, 12, 30, }, + { 1, 0, 0, 1, 13, 34, }, + { 3, 0, 0, 1, 13, 16, }, + { 4, 0, 0, 1, 13, 32, }, + { 5, 0, 0, 1, 13, 30, }, + { 6, 0, 0, 1, 13, 16, }, + { 7, 0, 0, 1, 13, 30, }, + { 1, 0, 0, 1, 14, 63, }, + { 3, 0, 0, 1, 14, 63, }, + { 4, 0, 0, 1, 14, 63, }, + { 5, 0, 0, 1, 14, 63, }, + { 6, 0, 0, 1, 14, 63, }, + { 7, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 2, 1, 34, }, + { 3, 0, 0, 2, 1, 26, }, + { 4, 0, 0, 2, 1, 32, }, + { 5, 0, 0, 2, 1, 30, }, + { 6, 0, 0, 2, 1, 26, }, + { 7, 0, 0, 2, 1, 30, }, + { 1, 0, 0, 2, 2, 34, }, + { 3, 0, 0, 2, 2, 30, }, + { 4, 0, 0, 2, 2, 34, }, + { 5, 0, 0, 2, 2, 30, }, + { 6, 0, 0, 2, 2, 30, }, + { 7, 0, 0, 2, 2, 30, }, + { 1, 0, 0, 2, 3, 34, }, + { 3, 0, 0, 2, 3, 32, }, + { 4, 0, 0, 2, 3, 34, }, + { 5, 0, 0, 2, 3, 30, }, + { 6, 0, 0, 2, 3, 32, }, + { 7, 0, 0, 2, 3, 30, }, + { 1, 0, 0, 2, 4, 34, }, + { 3, 0, 0, 2, 4, 34, }, + { 4, 0, 0, 2, 4, 34, }, + { 5, 0, 0, 2, 4, 30, }, + { 6, 0, 0, 2, 4, 34, }, + { 7, 0, 0, 2, 4, 30, }, + { 1, 0, 0, 2, 5, 34, }, + { 3, 0, 0, 2, 5, 34, }, + { 4, 0, 0, 2, 5, 34, }, + { 5, 0, 0, 2, 5, 30, }, + { 6, 0, 0, 2, 5, 34, }, + { 7, 0, 0, 2, 5, 30, }, + { 1, 0, 0, 2, 6, 34, }, + { 3, 0, 0, 2, 6, 34, }, + { 4, 0, 0, 2, 6, 34, }, + { 5, 0, 0, 2, 6, 30, }, + { 6, 0, 0, 2, 6, 34, }, + { 7, 0, 0, 2, 6, 30, }, + { 1, 0, 0, 2, 7, 34, }, + { 3, 0, 0, 2, 7, 34, }, + { 4, 0, 0, 2, 7, 34, }, + { 5, 0, 0, 2, 7, 30, }, + { 6, 0, 0, 2, 7, 34, }, + { 7, 0, 0, 2, 7, 30, }, + { 1, 0, 0, 2, 8, 34, }, + { 3, 0, 0, 2, 8, 34, }, + { 4, 0, 0, 2, 8, 34, }, + { 5, 0, 0, 2, 8, 30, }, + { 6, 0, 0, 2, 8, 34, }, + { 7, 0, 0, 2, 8, 30, }, + { 1, 0, 0, 2, 9, 34, }, + { 3, 0, 0, 2, 9, 32, }, + { 4, 0, 0, 2, 9, 34, }, + { 5, 0, 0, 2, 9, 30, }, + { 6, 0, 0, 2, 9, 32, }, + { 7, 0, 0, 2, 9, 30, }, + { 1, 0, 0, 2, 10, 34, }, + { 3, 0, 0, 2, 10, 30, }, + { 4, 0, 0, 2, 10, 34, }, + { 5, 0, 0, 2, 10, 30, }, + { 6, 0, 0, 2, 10, 30, }, + { 7, 0, 0, 2, 10, 30, }, + { 1, 0, 0, 2, 11, 34, }, + { 3, 0, 0, 2, 11, 28, }, + { 4, 0, 0, 2, 11, 34, }, + { 5, 0, 0, 2, 11, 30, }, + { 6, 0, 0, 2, 11, 28, }, + { 7, 0, 0, 2, 11, 30, }, + { 1, 0, 0, 2, 12, 34, }, + { 3, 0, 0, 2, 12, 26, }, + { 4, 0, 0, 2, 12, 34, }, + { 5, 0, 0, 2, 12, 30, }, + { 6, 0, 0, 2, 12, 26, }, + { 7, 0, 0, 2, 12, 30, }, + { 1, 0, 0, 2, 13, 34, }, + { 3, 0, 0, 2, 13, 12, }, + { 4, 0, 0, 2, 13, 32, }, + { 5, 0, 0, 2, 13, 30, }, + { 6, 0, 0, 2, 13, 12, }, + { 7, 0, 0, 2, 13, 30, }, + { 1, 0, 0, 2, 14, 63, }, + { 3, 0, 0, 2, 14, 63, }, + { 4, 0, 0, 2, 14, 63, }, + { 5, 0, 0, 2, 14, 63, }, + { 6, 0, 0, 2, 14, 63, }, + { 7, 0, 0, 2, 14, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 3, 0, 1, 2, 1, 63, }, + { 4, 0, 1, 2, 1, 63, }, + { 5, 0, 1, 2, 1, 63, }, + { 6, 0, 1, 2, 1, 63, }, + { 7, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 3, 0, 1, 2, 2, 63, }, + { 4, 0, 1, 2, 2, 63, }, + { 5, 0, 1, 2, 2, 63, }, + { 6, 0, 1, 2, 2, 63, }, + { 7, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 3, 30, }, + { 3, 0, 1, 2, 3, 26, }, + { 4, 0, 1, 2, 3, 30, }, + { 5, 0, 1, 2, 3, 30, }, + { 6, 0, 1, 2, 3, 26, }, + { 7, 0, 1, 2, 3, 30, }, + { 1, 0, 1, 2, 4, 30, }, + { 3, 0, 1, 2, 4, 26, }, + { 4, 0, 1, 2, 4, 30, }, + { 5, 0, 1, 2, 4, 30, }, + { 6, 0, 1, 2, 4, 26, }, + { 7, 0, 1, 2, 4, 30, }, + { 1, 0, 1, 2, 5, 30, }, + { 3, 0, 1, 2, 5, 30, }, + { 4, 0, 1, 2, 5, 30, }, + { 5, 0, 1, 2, 5, 30, }, + { 6, 0, 1, 2, 5, 30, }, + { 7, 0, 1, 2, 5, 30, }, + { 1, 0, 1, 2, 6, 30, }, + { 3, 0, 1, 2, 6, 30, }, + { 4, 0, 1, 2, 6, 30, }, + { 5, 0, 1, 2, 6, 30, }, + { 6, 0, 1, 2, 6, 30, }, + { 7, 0, 1, 2, 6, 30, }, + { 1, 0, 1, 2, 7, 30, }, + { 3, 0, 1, 2, 7, 30, }, + { 4, 0, 1, 2, 7, 30, }, + { 5, 0, 1, 2, 7, 30, }, + { 6, 0, 1, 2, 7, 30, }, + { 7, 0, 1, 2, 7, 30, }, + { 1, 0, 1, 2, 8, 30, }, + { 3, 0, 1, 2, 8, 26, }, + { 4, 0, 1, 2, 8, 30, }, + { 5, 0, 1, 2, 8, 30, }, + { 6, 0, 1, 2, 8, 26, }, + { 7, 0, 1, 2, 8, 30, }, + { 1, 0, 1, 2, 9, 30, }, + { 3, 0, 1, 2, 9, 26, }, + { 4, 0, 1, 2, 9, 30, }, + { 5, 0, 1, 2, 9, 30, }, + { 6, 0, 1, 2, 9, 26, }, + { 7, 0, 1, 2, 9, 30, }, + { 1, 0, 1, 2, 10, 30, }, + { 3, 0, 1, 2, 10, 28, }, + { 4, 0, 1, 2, 10, 30, }, + { 5, 0, 1, 2, 10, 30, }, + { 6, 0, 1, 2, 10, 28, }, + { 7, 0, 1, 2, 10, 30, }, + { 1, 0, 1, 2, 11, 30, }, + { 3, 0, 1, 2, 11, 20, }, + { 4, 0, 1, 2, 11, 30, }, + { 5, 0, 1, 2, 11, 30, }, + { 6, 0, 1, 2, 11, 20, }, + { 7, 0, 1, 2, 11, 30, }, + { 1, 0, 1, 2, 12, 63, }, + { 3, 0, 1, 2, 12, 63, }, + { 4, 0, 1, 2, 12, 63, }, + { 5, 0, 1, 2, 12, 63, }, + { 6, 0, 1, 2, 12, 63, }, + { 7, 0, 1, 2, 12, 63, }, + { 1, 0, 1, 2, 13, 63, }, + { 3, 0, 1, 2, 13, 63, }, + { 4, 0, 1, 2, 13, 63, }, + { 5, 0, 1, 2, 13, 63, }, + { 6, 0, 1, 2, 13, 63, }, + { 7, 0, 1, 2, 13, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 3, 0, 1, 2, 14, 63, }, + { 4, 0, 1, 2, 14, 63, }, + { 5, 0, 1, 2, 14, 63, }, + { 6, 0, 1, 2, 14, 63, }, + { 7, 0, 1, 2, 14, 63, }, + { 1, 1, 0, 1, 36, 33, }, + { 3, 1, 0, 1, 36, 31, }, + { 4, 1, 0, 1, 36, 29, }, + { 5, 1, 0, 1, 36, 32, }, + { 6, 1, 0, 1, 36, 29, }, + { 7, 1, 0, 1, 36, 27, }, + { 1, 1, 0, 1, 40, 33, }, + { 3, 1, 0, 1, 40, 31, }, + { 4, 1, 0, 1, 40, 28, }, + { 5, 1, 0, 1, 40, 32, }, + { 6, 1, 0, 1, 40, 29, }, + { 7, 1, 0, 1, 40, 27, }, + { 1, 1, 0, 1, 44, 33, }, + { 3, 1, 0, 1, 44, 31, }, + { 4, 1, 0, 1, 44, 28, }, + { 5, 1, 0, 1, 44, 32, }, + { 6, 1, 0, 1, 44, 30, }, + { 7, 1, 0, 1, 44, 27, }, + { 1, 1, 0, 1, 48, 33, }, + { 3, 1, 0, 1, 48, 31, }, + { 4, 1, 0, 1, 48, 27, }, + { 5, 1, 0, 1, 48, 32, }, + { 6, 1, 0, 1, 48, 30, }, + { 7, 1, 0, 1, 48, 27, }, + { 1, 1, 0, 1, 52, 33, }, + { 3, 1, 0, 1, 52, 32, }, + { 4, 1, 0, 1, 52, 16, }, + { 5, 1, 0, 1, 52, 32, }, + { 6, 1, 0, 1, 52, 30, }, + { 7, 1, 0, 1, 52, 27, }, + { 1, 1, 0, 1, 56, 33, }, + { 3, 1, 0, 1, 56, 32, }, + { 4, 1, 0, 1, 56, 33, }, + { 5, 1, 0, 1, 56, 32, }, + { 6, 1, 0, 1, 56, 30, }, + { 7, 1, 0, 1, 56, 27, }, + { 1, 1, 0, 1, 60, 33, }, + { 3, 1, 0, 1, 60, 32, }, + { 4, 1, 0, 1, 60, 33, }, + { 5, 1, 0, 1, 60, 32, }, + { 6, 1, 0, 1, 60, 30, }, + { 7, 1, 0, 1, 60, 27, }, + { 1, 1, 0, 1, 64, 33, }, + { 3, 1, 0, 1, 64, 30, }, + { 4, 1, 0, 1, 64, 33, }, + { 5, 1, 0, 1, 64, 32, }, + { 6, 1, 0, 1, 64, 29, }, + { 7, 1, 0, 1, 64, 27, }, + { 1, 1, 0, 1, 100, 33, }, + { 3, 1, 0, 1, 100, 30, }, + { 4, 1, 0, 1, 100, 33, }, + { 5, 1, 0, 1, 100, 32, }, + { 6, 1, 0, 1, 100, 30, }, + { 7, 1, 0, 1, 100, 27, }, + { 1, 1, 0, 1, 104, 33, }, + { 3, 1, 0, 1, 104, 33, }, + { 4, 1, 0, 1, 104, 33, }, + { 5, 1, 0, 1, 104, 32, }, + { 6, 1, 0, 1, 104, 30, }, + { 7, 1, 0, 1, 104, 27, }, + { 1, 1, 0, 1, 108, 33, }, + { 3, 1, 0, 1, 108, 33, }, + { 4, 1, 0, 1, 108, 33, }, + { 5, 1, 0, 1, 108, 32, }, + { 6, 1, 0, 1, 108, 30, }, + { 7, 1, 0, 1, 108, 27, }, + { 1, 1, 0, 1, 112, 33, }, + { 3, 1, 0, 1, 112, 33, }, + { 4, 1, 0, 1, 112, 33, }, + { 5, 1, 0, 1, 112, 32, }, + { 6, 1, 0, 1, 112, 30, }, + { 7, 1, 0, 1, 112, 27, }, + { 1, 1, 0, 1, 116, 33, }, + { 3, 1, 0, 1, 116, 33, }, + { 4, 1, 0, 1, 116, 33, }, + { 5, 1, 0, 1, 116, 32, }, + { 6, 1, 0, 1, 116, 30, }, + { 7, 1, 0, 1, 116, 27, }, + { 1, 1, 0, 1, 120, 33, }, + { 3, 1, 0, 1, 120, 63, }, + { 4, 1, 0, 1, 120, 33, }, + { 5, 1, 0, 1, 120, 63, }, + { 6, 1, 0, 1, 120, 30, }, + { 7, 1, 0, 1, 120, 27, }, + { 1, 1, 0, 1, 124, 33, }, + { 3, 1, 0, 1, 124, 63, }, + { 4, 1, 0, 1, 124, 33, }, + { 5, 1, 0, 1, 124, 63, }, + { 6, 1, 0, 1, 124, 30, }, + { 7, 1, 0, 1, 124, 27, }, + { 1, 1, 0, 1, 128, 33, }, + { 3, 1, 0, 1, 128, 63, }, + { 4, 1, 0, 1, 128, 63, }, + { 5, 1, 0, 1, 128, 63, }, + { 6, 1, 0, 1, 128, 30, }, + { 7, 1, 0, 1, 128, 27, }, + { 1, 1, 0, 1, 132, 33, }, + { 3, 1, 0, 1, 132, 33, }, + { 4, 1, 0, 1, 132, 63, }, + { 5, 1, 0, 1, 132, 32, }, + { 6, 1, 0, 1, 132, 30, }, + { 7, 1, 0, 1, 132, 27, }, + { 1, 1, 0, 1, 136, 33, }, + { 3, 1, 0, 1, 136, 33, }, + { 4, 1, 0, 1, 136, 63, }, + { 5, 1, 0, 1, 136, 32, }, + { 6, 1, 0, 1, 136, 30, }, + { 7, 1, 0, 1, 136, 63, }, + { 1, 1, 0, 1, 140, 33, }, + { 3, 1, 0, 1, 140, 31, }, + { 4, 1, 0, 1, 140, 63, }, + { 5, 1, 0, 1, 140, 32, }, + { 6, 1, 0, 1, 140, 30, }, + { 7, 1, 0, 1, 140, 63, }, + { 1, 1, 0, 1, 144, 63, }, + { 3, 1, 0, 1, 144, 30, }, + { 4, 1, 0, 1, 144, 63, }, + { 5, 1, 0, 1, 144, 63, }, + { 6, 1, 0, 1, 144, 30, }, + { 7, 1, 0, 1, 144, 63, }, + { 1, 1, 0, 1, 149, 63, }, + { 3, 1, 0, 1, 149, 30, }, + { 4, 1, 0, 1, 149, 33, }, + { 5, 1, 0, 1, 149, 33, }, + { 6, 1, 0, 1, 149, 30, }, + { 7, 1, 0, 1, 149, 27, }, + { 1, 1, 0, 1, 153, 63, }, + { 3, 1, 0, 1, 153, 33, }, + { 4, 1, 0, 1, 153, 33, }, + { 5, 1, 0, 1, 153, 33, }, + { 6, 1, 0, 1, 153, 30, }, + { 7, 1, 0, 1, 153, 27, }, + { 1, 1, 0, 1, 157, 63, }, + { 3, 1, 0, 1, 157, 33, }, + { 4, 1, 0, 1, 157, 33, }, + { 5, 1, 0, 1, 157, 33, }, + { 6, 1, 0, 1, 157, 30, }, + { 7, 1, 0, 1, 157, 27, }, + { 1, 1, 0, 1, 161, 63, }, + { 3, 1, 0, 1, 161, 33, }, + { 4, 1, 0, 1, 161, 31, }, + { 5, 1, 0, 1, 161, 33, }, + { 6, 1, 0, 1, 161, 30, }, + { 7, 1, 0, 1, 161, 27, }, + { 1, 1, 0, 1, 165, 63, }, + { 3, 1, 0, 1, 165, 33, }, + { 4, 1, 0, 1, 165, 63, }, + { 5, 1, 0, 1, 165, 33, }, + { 6, 1, 0, 1, 165, 30, }, + { 7, 1, 0, 1, 165, 27, }, + { 1, 1, 0, 2, 36, 33, }, + { 3, 1, 0, 2, 36, 30, }, + { 4, 1, 0, 2, 36, 27, }, + { 5, 1, 0, 2, 36, 32, }, + { 6, 1, 0, 2, 36, 30, }, + { 7, 1, 0, 2, 36, 27, }, + { 1, 1, 0, 2, 40, 33, }, + { 3, 1, 0, 2, 40, 31, }, + { 4, 1, 0, 2, 40, 29, }, + { 5, 1, 0, 2, 40, 32, }, + { 6, 1, 0, 2, 40, 30, }, + { 7, 1, 0, 2, 40, 27, }, + { 1, 1, 0, 2, 44, 33, }, + { 3, 1, 0, 2, 44, 31, }, + { 4, 1, 0, 2, 44, 29, }, + { 5, 1, 0, 2, 44, 32, }, + { 6, 1, 0, 2, 44, 30, }, + { 7, 1, 0, 2, 44, 27, }, + { 1, 1, 0, 2, 48, 33, }, + { 3, 1, 0, 2, 48, 31, }, + { 4, 1, 0, 2, 48, 26, }, + { 5, 1, 0, 2, 48, 32, }, + { 6, 1, 0, 2, 48, 30, }, + { 7, 1, 0, 2, 48, 27, }, + { 1, 1, 0, 2, 52, 33, }, + { 3, 1, 0, 2, 52, 32, }, + { 4, 1, 0, 2, 52, 7, }, + { 5, 1, 0, 2, 52, 32, }, + { 6, 1, 0, 2, 52, 30, }, + { 7, 1, 0, 2, 52, 27, }, + { 1, 1, 0, 2, 56, 33, }, + { 3, 1, 0, 2, 56, 32, }, + { 4, 1, 0, 2, 56, 33, }, + { 5, 1, 0, 2, 56, 32, }, + { 6, 1, 0, 2, 56, 30, }, + { 7, 1, 0, 2, 56, 27, }, + { 1, 1, 0, 2, 60, 33, }, + { 3, 1, 0, 2, 60, 32, }, + { 4, 1, 0, 2, 60, 33, }, + { 5, 1, 0, 2, 60, 32, }, + { 6, 1, 0, 2, 60, 30, }, + { 7, 1, 0, 2, 60, 27, }, + { 1, 1, 0, 2, 64, 33, }, + { 3, 1, 0, 2, 64, 30, }, + { 4, 1, 0, 2, 64, 33, }, + { 5, 1, 0, 2, 64, 32, }, + { 6, 1, 0, 2, 64, 30, }, + { 7, 1, 0, 2, 64, 27, }, + { 1, 1, 0, 2, 100, 33, }, + { 3, 1, 0, 2, 100, 30, }, + { 4, 1, 0, 2, 100, 33, }, + { 5, 1, 0, 2, 100, 32, }, + { 6, 1, 0, 2, 100, 30, }, + { 7, 1, 0, 2, 100, 27, }, + { 1, 1, 0, 2, 104, 33, }, + { 3, 1, 0, 2, 104, 33, }, + { 4, 1, 0, 2, 104, 33, }, + { 5, 1, 0, 2, 104, 32, }, + { 6, 1, 0, 2, 104, 30, }, + { 7, 1, 0, 2, 104, 27, }, + { 1, 1, 0, 2, 108, 33, }, + { 3, 1, 0, 2, 108, 33, }, + { 4, 1, 0, 2, 108, 33, }, + { 5, 1, 0, 2, 108, 32, }, + { 6, 1, 0, 2, 108, 30, }, + { 7, 1, 0, 2, 108, 27, }, + { 1, 1, 0, 2, 112, 33, }, + { 3, 1, 0, 2, 112, 33, }, + { 4, 1, 0, 2, 112, 33, }, + { 5, 1, 0, 2, 112, 32, }, + { 6, 1, 0, 2, 112, 30, }, + { 7, 1, 0, 2, 112, 27, }, + { 1, 1, 0, 2, 116, 33, }, + { 3, 1, 0, 2, 116, 33, }, + { 4, 1, 0, 2, 116, 33, }, + { 5, 1, 0, 2, 116, 32, }, + { 6, 1, 0, 2, 116, 30, }, + { 7, 1, 0, 2, 116, 27, }, + { 1, 1, 0, 2, 120, 33, }, + { 3, 1, 0, 2, 120, 63, }, + { 4, 1, 0, 2, 120, 33, }, + { 5, 1, 0, 2, 120, 63, }, + { 6, 1, 0, 2, 120, 30, }, + { 7, 1, 0, 2, 120, 27, }, + { 1, 1, 0, 2, 124, 33, }, + { 3, 1, 0, 2, 124, 63, }, + { 4, 1, 0, 2, 124, 33, }, + { 5, 1, 0, 2, 124, 63, }, + { 6, 1, 0, 2, 124, 30, }, + { 7, 1, 0, 2, 124, 27, }, + { 1, 1, 0, 2, 128, 33, }, + { 3, 1, 0, 2, 128, 63, }, + { 4, 1, 0, 2, 128, 63, }, + { 5, 1, 0, 2, 128, 63, }, + { 6, 1, 0, 2, 128, 30, }, + { 7, 1, 0, 2, 128, 27, }, + { 1, 1, 0, 2, 132, 33, }, + { 3, 1, 0, 2, 132, 33, }, + { 4, 1, 0, 2, 132, 63, }, + { 5, 1, 0, 2, 132, 32, }, + { 6, 1, 0, 2, 132, 30, }, + { 7, 1, 0, 2, 132, 27, }, + { 1, 1, 0, 2, 136, 33, }, + { 3, 1, 0, 2, 136, 33, }, + { 4, 1, 0, 2, 136, 63, }, + { 5, 1, 0, 2, 136, 32, }, + { 6, 1, 0, 2, 136, 30, }, + { 7, 1, 0, 2, 136, 63, }, + { 1, 1, 0, 2, 140, 33, }, + { 3, 1, 0, 2, 140, 29, }, + { 4, 1, 0, 2, 140, 63, }, + { 5, 1, 0, 2, 140, 32, }, + { 6, 1, 0, 2, 140, 30, }, + { 7, 1, 0, 2, 140, 63, }, + { 1, 1, 0, 2, 144, 63, }, + { 3, 1, 0, 2, 144, 27, }, + { 4, 1, 0, 2, 144, 63, }, + { 5, 1, 0, 2, 144, 63, }, + { 6, 1, 0, 2, 144, 30, }, + { 7, 1, 0, 2, 144, 63, }, + { 1, 1, 0, 2, 149, 63, }, + { 3, 1, 0, 2, 149, 33, }, + { 4, 1, 0, 2, 149, 33, }, + { 5, 1, 0, 2, 149, 33, }, + { 6, 1, 0, 2, 149, 30, }, + { 7, 1, 0, 2, 149, 27, }, + { 1, 1, 0, 2, 153, 63, }, + { 3, 1, 0, 2, 153, 33, }, + { 4, 1, 0, 2, 153, 33, }, + { 5, 1, 0, 2, 153, 33, }, + { 6, 1, 0, 2, 153, 30, }, + { 7, 1, 0, 2, 153, 27, }, + { 1, 1, 0, 2, 157, 63, }, + { 3, 1, 0, 2, 157, 33, }, + { 4, 1, 0, 2, 157, 33, }, + { 5, 1, 0, 2, 157, 33, }, + { 6, 1, 0, 2, 157, 30, }, + { 7, 1, 0, 2, 157, 27, }, + { 1, 1, 0, 2, 161, 63, }, + { 3, 1, 0, 2, 161, 33, }, + { 4, 1, 0, 2, 161, 31, }, + { 5, 1, 0, 2, 161, 33, }, + { 6, 1, 0, 2, 161, 30, }, + { 7, 1, 0, 2, 161, 27, }, + { 1, 1, 0, 2, 165, 63, }, + { 3, 1, 0, 2, 165, 33, }, + { 4, 1, 0, 2, 165, 63, }, + { 5, 1, 0, 2, 165, 33, }, + { 6, 1, 0, 2, 165, 30, }, + { 7, 1, 0, 2, 165, 27, }, + { 1, 1, 1, 2, 38, 32, }, + { 3, 1, 1, 2, 38, 22, }, + { 4, 1, 1, 2, 38, 26, }, + { 5, 1, 1, 2, 38, 32, }, + { 6, 1, 1, 2, 38, 22, }, + { 7, 1, 1, 2, 38, 27, }, + { 1, 1, 1, 2, 46, 32, }, + { 3, 1, 1, 2, 46, 32, }, + { 4, 1, 1, 2, 46, 28, }, + { 5, 1, 1, 2, 46, 32, }, + { 6, 1, 1, 2, 46, 30, }, + { 7, 1, 1, 2, 46, 27, }, + { 1, 1, 1, 2, 54, 32, }, + { 3, 1, 1, 2, 54, 32, }, + { 4, 1, 1, 2, 54, 22, }, + { 5, 1, 1, 2, 54, 32, }, + { 6, 1, 1, 2, 54, 30, }, + { 7, 1, 1, 2, 54, 27, }, + { 1, 1, 1, 2, 62, 32, }, + { 3, 1, 1, 2, 62, 23, }, + { 4, 1, 1, 2, 62, 31, }, + { 5, 1, 1, 2, 62, 32, }, + { 6, 1, 1, 2, 62, 23, }, + { 7, 1, 1, 2, 62, 27, }, + { 1, 1, 1, 2, 102, 32, }, + { 3, 1, 1, 2, 102, 21, }, + { 4, 1, 1, 2, 102, 31, }, + { 5, 1, 1, 2, 102, 32, }, + { 6, 1, 1, 2, 102, 30, }, + { 7, 1, 1, 2, 102, 27, }, + { 1, 1, 1, 2, 110, 32, }, + { 3, 1, 1, 2, 110, 32, }, + { 4, 1, 1, 2, 110, 32, }, + { 5, 1, 1, 2, 110, 32, }, + { 6, 1, 1, 2, 110, 30, }, + { 7, 1, 1, 2, 110, 27, }, + { 1, 1, 1, 2, 118, 32, }, + { 3, 1, 1, 2, 118, 63, }, + { 4, 1, 1, 2, 118, 32, }, + { 5, 1, 1, 2, 118, 63, }, + { 6, 1, 1, 2, 118, 30, }, + { 7, 1, 1, 2, 118, 27, }, + { 1, 1, 1, 2, 126, 32, }, + { 3, 1, 1, 2, 126, 63, }, + { 4, 1, 1, 2, 126, 63, }, + { 5, 1, 1, 2, 126, 63, }, + { 6, 1, 1, 2, 126, 30, }, + { 7, 1, 1, 2, 126, 27, }, + { 1, 1, 1, 2, 134, 32, }, + { 3, 1, 1, 2, 134, 32, }, + { 4, 1, 1, 2, 134, 63, }, + { 5, 1, 1, 2, 134, 32, }, + { 6, 1, 1, 2, 134, 30, }, + { 7, 1, 1, 2, 134, 63, }, + { 1, 1, 1, 2, 142, 63, }, + { 3, 1, 1, 2, 142, 29, }, + { 4, 1, 1, 2, 142, 63, }, + { 5, 1, 1, 2, 142, 63, }, + { 6, 1, 1, 2, 142, 30, }, + { 7, 1, 1, 2, 142, 63, }, + { 1, 1, 1, 2, 151, 63, }, + { 3, 1, 1, 2, 151, 32, }, + { 4, 1, 1, 2, 151, 27, }, + { 5, 1, 1, 2, 151, 32, }, + { 6, 1, 1, 2, 151, 30, }, + { 7, 1, 1, 2, 151, 27, }, + { 1, 1, 1, 2, 159, 63, }, + { 3, 1, 1, 2, 159, 32, }, + { 4, 1, 1, 2, 159, 26, }, + { 5, 1, 1, 2, 159, 32, }, + { 6, 1, 1, 2, 159, 30, }, + { 7, 1, 1, 2, 159, 27, }, + { 1, 1, 2, 4, 42, 28, }, + { 3, 1, 2, 4, 42, 19, }, + { 4, 1, 2, 4, 42, 25, }, + { 5, 1, 2, 4, 42, 32, }, + { 6, 1, 2, 4, 42, 19, }, + { 7, 1, 2, 4, 42, 27, }, + { 1, 1, 2, 4, 58, 28, }, + { 3, 1, 2, 4, 58, 22, }, + { 4, 1, 2, 4, 58, 28, }, + { 5, 1, 2, 4, 58, 32, }, + { 6, 1, 2, 4, 58, 22, }, + { 7, 1, 2, 4, 58, 27, }, + { 1, 1, 2, 4, 106, 32, }, + { 3, 1, 2, 4, 106, 18, }, + { 4, 1, 2, 4, 106, 30, }, + { 5, 1, 2, 4, 106, 32, }, + { 6, 1, 2, 4, 106, 30, }, + { 7, 1, 2, 4, 106, 27, }, + { 1, 1, 2, 4, 122, 32, }, + { 3, 1, 2, 4, 122, 63, }, + { 4, 1, 2, 4, 122, 26, }, + { 5, 1, 2, 4, 122, 63, }, + { 6, 1, 2, 4, 122, 30, }, + { 7, 1, 2, 4, 122, 27, }, + { 1, 1, 2, 4, 138, 63, }, + { 3, 1, 2, 4, 138, 28, }, + { 4, 1, 2, 4, 138, 63, }, + { 5, 1, 2, 4, 138, 63, }, + { 6, 1, 2, 4, 138, 30, }, + { 7, 1, 2, 4, 138, 63, }, + { 1, 1, 2, 4, 155, 63, }, + { 3, 1, 2, 4, 155, 32, }, + { 4, 1, 2, 4, 155, 27, }, + { 5, 1, 2, 4, 155, 32, }, + { 6, 1, 2, 4, 155, 30, }, + { 7, 1, 2, 4, 155, 27, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8821c_txpwr_lmt_type0); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c_table.h b/drivers/net/wireless/realtek/rtw88/rtw8821c_table.h new file mode 100644 index 000000000000..5ea8b4fc7fba --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c_table.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW8821C_TABLE_H__ +#define __RTW8821C_TABLE_H__ + +extern const struct rtw_table rtw8821c_mac_tbl; +extern const struct rtw_table rtw8821c_agc_tbl; +extern const struct rtw_table rtw8821c_bb_tbl; +extern const struct rtw_table rtw8821c_bb_pg_type0_tbl; +extern const struct rtw_table rtw8821c_rf_a_tbl; +extern const struct rtw_table rtw8821c_txpwr_lmt_type0_tbl; + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821ce.c b/drivers/net/wireless/realtek/rtw88/rtw8821ce.c new file mode 100644 index 000000000000..616fdcfd62c9 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821ce.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include "rtw8821ce.h" + +static const struct pci_device_id rtw_8821ce_id_table[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC821), + .driver_data = (kernel_ulong_t)&rtw8821c_hw_spec + }, + {} +}; +MODULE_DEVICE_TABLE(pci, rtw_8821ce_id_table); + +static struct pci_driver rtw_8821ce_driver = { + .name = "rtw_8821ce", + .id_table = rtw_8821ce_id_table, + .probe = rtw_pci_probe, + .remove = rtw_pci_remove, + .driver.pm = &rtw_pm_ops, + .shutdown = rtw_pci_shutdown, +}; +module_pci_driver(rtw_8821ce_driver); + +MODULE_AUTHOR("Realtek Corporation"); +MODULE_DESCRIPTION("Realtek 802.11ac wireless 8821ce driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821ce.h b/drivers/net/wireless/realtek/rtw88/rtw8821ce.h new file mode 100644 index 000000000000..8d3eb77a876b --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/rtw8821ce.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation + */ + +#ifndef __RTW_8821CE_H_ +#define __RTW_8821CE_H_ + +extern const struct dev_pm_ops rtw_pm_ops; +extern struct rtw_chip_info rtw8821c_hw_spec; +int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); +void rtw_pci_remove(struct pci_dev *pdev); +void rtw_pci_shutdown(struct pci_dev *pdev); + +#endif diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index e49bdd76ab9a..351cd055a295 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -2147,7 +2147,7 @@ static const struct coex_table_para table_sant_8822b[] = { {0x66555555, 0x5a5a5a5a}, {0x66555555, 0x6a5a5a5a}, /* case-10 */ {0x66555555, 0xfafafafa}, - {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0x5a5a5aaa}, {0x66555555, 0x5aaa5aaa}, {0x66555555, 0xaaaa5aaa}, {0x66555555, 0xaaaaaaaa}, /* case-15 */ @@ -2223,7 +2223,8 @@ static const struct coex_tdma_para tdma_sant_8822b[] = { { {0x55, 0x08, 0x03, 0x10, 0x54} }, { {0x65, 0x10, 0x03, 0x11, 0x11} }, { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ - { {0x51, 0x08, 0x03, 0x10, 0x50} } + { {0x51, 0x08, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } }; /* Non-Shared-Antenna TDMA */ @@ -2475,7 +2476,7 @@ struct rtw_chip_info rtw8822b_hw_spec = { .bfer_mu_max_num = 1, .rx_ldpc = true, - .coex_para_ver = 0x19062706, + .coex_para_ver = 0x20070206, .bt_desired_ver = 0x6, .scbd_support = true, .new_scbd10_def = false, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index c3d72ef611c6..426808413baa 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3899,6 +3899,7 @@ static const struct rtw_rfe_def rtw8822c_rfe_defs[] = { [1] = RTW_DEF_RFE(8822c, 0, 0), [2] = RTW_DEF_RFE(8822c, 0, 0), [5] = RTW_DEF_RFE(8822c, 0, 5), + [6] = RTW_DEF_RFE(8822c, 0, 0), }; static const struct rtw_hw_reg rtw8822c_dig[] = { @@ -3997,7 +3998,7 @@ static const struct coex_table_para table_sant_8822c[] = { {0x66555555, 0x5a5a5a5a}, {0x66555555, 0x6a5a5a5a}, /* case-10 */ {0x66555555, 0xfafafafa}, - {0x66555555, 0x6a5a5aaa}, + {0x66555555, 0x5a5a5aaa}, {0x66555555, 0x5aaa5aaa}, {0x66555555, 0xaaaa5aaa}, {0x66555555, 0xaaaaaaaa}, /* case-15 */ @@ -4073,7 +4074,8 @@ static const struct coex_tdma_para tdma_sant_8822c[] = { { {0x55, 0x08, 0x03, 0x10, 0x54} }, { {0x65, 0x10, 0x03, 0x11, 0x11} }, { {0x51, 0x10, 0x03, 0x10, 0x51} }, /* case-25 */ - { {0x51, 0x08, 0x03, 0x10, 0x50} } + { {0x51, 0x08, 0x03, 0x10, 0x50} }, + { {0x61, 0x08, 0x03, 0x11, 0x11} } }; /* Non-Shared-Antenna TDMA */ @@ -4343,8 +4345,8 @@ struct rtw_chip_info rtw8822c_hw_spec = { .wowlan_stub = &rtw_wowlan_stub_8822c, .max_sched_scan_ssids = 4, #endif - .coex_para_ver = 0x19062706, - .bt_desired_ver = 0x6, + .coex_para_ver = 0x20070217, + .bt_desired_ver = 0x17, .scbd_support = true, .new_scbd10_def = true, .pstdma_type = COEX_PSTDMA_FORCE_LPSOFF, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c index 7b6bd990651e..026ac49ce6e3 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c @@ -11,6 +11,10 @@ static const struct pci_device_id rtw_8822ce_id_table[] = { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC822), .driver_data = (kernel_ulong_t)&rtw8822c_hw_spec }, + { + PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xC82F), + .driver_data = (kernel_ulong_t)&rtw8822c_hw_spec + }, {} }; MODULE_DEVICE_TABLE(pci, rtw_8822ce_id_table); diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 79c42118825f..7fcc992b01a8 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -61,6 +61,8 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) SET_TX_DESC_DISQSELSEQ(txdesc, pkt_info->dis_qselseq); SET_TX_DESC_EN_HWSEQ(txdesc, pkt_info->en_hwseq); SET_TX_DESC_HW_SSN_SEL(txdesc, pkt_info->hw_ssn_sel); + SET_TX_DESC_NAVUSEHDR(txdesc, pkt_info->nav_use_hdr); + SET_TX_DESC_BT_NULL(txdesc, pkt_info->bt_null); } EXPORT_SYMBOL(rtw_tx_fill_tx_desc); @@ -227,17 +229,58 @@ void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src) spin_unlock_irqrestore(&tx_report->q_lock, flags); } -static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, +static void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, - struct ieee80211_sta *sta, struct sk_buff *skb) { + if (rtwdev->hal.current_band_type == RTW_BAND_2G) { + pkt_info->rate_id = RTW_RATEID_B_20M; + pkt_info->rate = DESC_RATE1M; + } else { + pkt_info->rate_id = RTW_RATEID_G; + pkt_info->rate = DESC_RATE6M; + } pkt_info->use_rate = true; - pkt_info->rate_id = 6; pkt_info->dis_rate_fallback = true; +} + +static void rtw_tx_pkt_info_update_sec(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct sk_buff *skb) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 sec_type = 0; + + if (info && info->control.hw_key) { + struct ieee80211_key_conf *key = info->control.hw_key; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + sec_type = 0x01; + break; + case WLAN_CIPHER_SUITE_CCMP: + sec_type = 0x03; + break; + default: + break; + } + } + + pkt_info->sec_type = sec_type; +} + +static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb); pkt_info->dis_qselseq = true; pkt_info->en_hwseq = true; pkt_info->hw_ssn_sel = 0; + /* TODO: need to change hw port and hw ssn sel for multiple vifs */ } static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, @@ -312,7 +355,6 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_sta_info *si; struct ieee80211_vif *vif = NULL; __le16 fc = hdr->frame_control; - u8 sec_type = 0; bool bmc; if (sta) { @@ -325,23 +367,6 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, else if (ieee80211_is_data(fc)) rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); - if (info->control.hw_key) { - struct ieee80211_key_conf *key = info->control.hw_key; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - case WLAN_CIPHER_SUITE_TKIP: - sec_type = 0x01; - break; - case WLAN_CIPHER_SUITE_CCMP: - sec_type = 0x03; - break; - default: - break; - } - } - bmc = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); @@ -349,7 +374,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, rtw_tx_report_enable(rtwdev, pkt_info); pkt_info->bmc = bmc; - pkt_info->sec_type = sec_type; + rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); pkt_info->tx_pkt_size = skb->len; pkt_info->offset = chip->tx_pkt_desc_sz; pkt_info->qsel = skb->priority; @@ -359,24 +384,42 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, rtw_tx_stats(rtwdev, vif, skb); } -void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, - struct rtw_tx_pkt_info *pkt_info, - struct sk_buff *skb) +void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct sk_buff *skb, + enum rtw_rsvd_packet_type type) { struct rtw_chip_info *chip = rtwdev->chip; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; bool bmc; + /* A beacon or dummy reserved page packet indicates that it is the first + * reserved page, and the qsel of it will be set in each hci. + */ + if (type != RSVD_BEACON && type != RSVD_DUMMY) + pkt_info->qsel = TX_DESC_QSEL_MGMT; + + rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb); + bmc = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); - pkt_info->use_rate = true; - pkt_info->rate_id = 6; - pkt_info->dis_rate_fallback = true; pkt_info->bmc = bmc; pkt_info->tx_pkt_size = skb->len; pkt_info->offset = chip->tx_pkt_desc_sz; - pkt_info->qsel = TX_DESC_QSEL_MGMT; pkt_info->ls = true; + if (type == RSVD_PS_POLL) { + pkt_info->nav_use_hdr = true; + } else { + pkt_info->dis_qselseq = true; + pkt_info->en_hwseq = true; + pkt_info->hw_ssn_sel = 0; + } + if (type == RSVD_QOS_NULL) + pkt_info->bt_null = true; + + rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); + + /* TODO: need to change hw port and hw ssn sel for multiple vifs */ } struct sk_buff * @@ -399,8 +442,7 @@ rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev, skb_reserve(skb, tx_pkt_desc_sz); skb_put_data(skb, buf, size); - pkt_info->tx_pkt_size = size; - pkt_info->offset = tx_pkt_desc_sz; + rtw_tx_rsvd_page_pkt_info_update(rtwdev, pkt_info, skb, RSVD_BEACON); return skb; } diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 72dfd4059f03..cfe84eef5923 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -59,6 +59,10 @@ le32p_replace_bits((__le32 *)(txdesc) + 0x08, value, BIT(15)) #define SET_TX_DESC_HW_SSN_SEL(txdesc, value) \ le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, GENMASK(7, 6)) +#define SET_TX_DESC_NAVUSEHDR(txdesc, value) \ + le32p_replace_bits((__le32 *)(txdesc) + 0x03, value, BIT(15)) +#define SET_TX_DESC_BT_NULL(txdesc, value) \ + le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, BIT(23)) enum rtw_tx_desc_queue_select { TX_DESC_QSEL_TID0 = 0, @@ -83,6 +87,8 @@ enum rtw_tx_desc_queue_select { TX_DESC_QSEL_H2C = 19, }; +enum rtw_rsvd_packet_type; + void rtw_tx(struct rtw_dev *rtwdev, struct ieee80211_tx_control *control, struct sk_buff *skb); @@ -96,9 +102,10 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb); void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn); void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src); -void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, - struct rtw_tx_pkt_info *pkt_info, - struct sk_buff *skb); +void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, + struct rtw_tx_pkt_info *pkt_info, + struct sk_buff *skb, + enum rtw_rsvd_packet_type type); struct sk_buff * rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 5d6143a55187..a04ff75c409f 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -1038,10 +1038,10 @@ static int rsi_probe(struct sdio_func *pfunction, goto fail_free_adapter; } - if (pfunction->device == RSI_SDIO_PID_9113) { + if (pfunction->device == SDIO_DEVICE_ID_RSI_9113) { rsi_dbg(ERR_ZONE, "%s: 9113 module detected\n", __func__); adapter->device_model = RSI_DEV_9113; - } else if (pfunction->device == RSI_SDIO_PID_9116) { + } else if (pfunction->device == SDIO_DEVICE_ID_RSI_9116) { rsi_dbg(ERR_ZONE, "%s: 9116 module detected\n", __func__); adapter->device_model = RSI_DEV_9116; } else { @@ -1526,8 +1526,8 @@ static const struct dev_pm_ops rsi_pm_ops = { #endif static const struct sdio_device_id rsi_dev_table[] = { - { SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9113) }, - { SDIO_DEVICE(RSI_SDIO_VENDOR_ID, RSI_SDIO_PID_9116) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_RSI, SDIO_DEVICE_ID_RSI_9113) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_RSI, SDIO_DEVICE_ID_RSI_9116) }, { /* Blank */}, }; diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index c5cfb6238f73..9afc1d0d2684 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -28,10 +28,6 @@ #include <linux/mmc/sdio_ids.h> #include "rsi_main.h" -#define RSI_SDIO_VENDOR_ID 0x041B -#define RSI_SDIO_PID_9113 0x9330 -#define RSI_SDIO_PID_9116 0x9116 - enum sdio_interrupt_type { BUFFER_FULL = 0x0, BUFFER_AVAILABLE = 0x2, diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c index 850864dbafa1..e6d426edab56 100644 --- a/drivers/net/wireless/ti/wl1251/event.c +++ b/drivers/net/wireless/ti/wl1251/event.c @@ -70,7 +70,7 @@ static int wl1251_event_ps_report(struct wl1251 *wl, break; } - return 0; + return ret; } static void wl1251_event_mbox_dump(struct event_mailbox *mbox) diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index de6c8a7589ca..821ad1acd505 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -521,6 +521,7 @@ static int wlcore_irq_locked(struct wl1271 *wl) int ret = 0; u32 intr; int loopcount = WL1271_IRQ_MAX_LOOPS; + bool run_tx_queue = true; bool done = false; unsigned int defer_count; unsigned long flags; @@ -586,19 +587,22 @@ static int wlcore_irq_locked(struct wl1271 *wl) goto err_ret; /* Check if any tx blocks were freed */ - spin_lock_irqsave(&wl->wl_lock, flags); - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - wl1271_tx_total_queue_count(wl) > 0) { - spin_unlock_irqrestore(&wl->wl_lock, flags); + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) { + if (spin_trylock_irqsave(&wl->wl_lock, flags)) { + if (!wl1271_tx_total_queue_count(wl)) + run_tx_queue = false; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + /* * In order to avoid starvation of the TX path, * call the work function directly. */ - ret = wlcore_tx_work_locked(wl); - if (ret < 0) - goto err_ret; - } else { - spin_unlock_irqrestore(&wl->wl_lock, flags); + if (run_tx_queue) { + ret = wlcore_tx_work_locked(wl); + if (ret < 0) + goto err_ret; + } } /* check for tx results */ @@ -648,25 +652,28 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) int ret; unsigned long flags; struct wl1271 *wl = cookie; + bool queue_tx_work = true; - /* complete the ELP completion */ - spin_lock_irqsave(&wl->wl_lock, flags); set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - if (wl->elp_compl) { - complete(wl->elp_compl); - wl->elp_compl = NULL; + + /* complete the ELP completion */ + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) { + spin_lock_irqsave(&wl->wl_lock, flags); + if (wl->elp_compl) + complete(wl->elp_compl); + spin_unlock_irqrestore(&wl->wl_lock, flags); } if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { /* don't enqueue a work right now. mark it as pending */ set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); wl1271_debug(DEBUG_IRQ, "should not enqueue work"); + spin_lock_irqsave(&wl->wl_lock, flags); disable_irq_nosync(wl->irq); pm_wakeup_event(wl->dev, 0); spin_unlock_irqrestore(&wl->wl_lock, flags); goto out_handled; } - spin_unlock_irqrestore(&wl->wl_lock, flags); /* TX might be handled here, avoid redundant work */ set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); @@ -678,20 +685,22 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) if (ret) wl12xx_queue_recovery_work(wl); - spin_lock_irqsave(&wl->wl_lock, flags); - /* In case TX was not handled here, queue TX work */ + /* In case TX was not handled in wlcore_irq_locked(), queue TX work */ clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && - wl1271_tx_total_queue_count(wl) > 0) - ieee80211_queue_work(wl->hw, &wl->tx_work); - spin_unlock_irqrestore(&wl->wl_lock, flags); + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) { + if (spin_trylock_irqsave(&wl->wl_lock, flags)) { + if (!wl1271_tx_total_queue_count(wl)) + queue_tx_work = false; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } + if (queue_tx_work) + ieee80211_queue_work(wl->hw, &wl->tx_work); + } mutex_unlock(&wl->mutex); out_handled: - spin_lock_irqsave(&wl->wl_lock, flags); clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); return IRQ_HANDLED; } @@ -6732,7 +6741,6 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev) unsigned long flags; int ret; unsigned long start_time = jiffies; - bool pending = false; bool recovery = false; /* Nothing to do if no ELP mode requested */ @@ -6742,49 +6750,35 @@ static int __maybe_unused wlcore_runtime_resume(struct device *dev) wl1271_debug(DEBUG_PSM, "waking up chip from elp"); spin_lock_irqsave(&wl->wl_lock, flags); - if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) - pending = true; - else - wl->elp_compl = &compl; + wl->elp_compl = &compl; spin_unlock_irqrestore(&wl->wl_lock, flags); ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); if (ret < 0) { recovery = true; - goto err; - } - - if (!pending) { + } else if (!test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) { ret = wait_for_completion_timeout(&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); if (ret == 0) { wl1271_warning("ELP wakeup timeout!"); - - /* Return no error for runtime PM for recovery */ - ret = 0; recovery = true; - goto err; } } - clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); - - wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", - jiffies_to_msecs(jiffies - start_time)); - - return 0; - -err: spin_lock_irqsave(&wl->wl_lock, flags); wl->elp_compl = NULL; spin_unlock_irqrestore(&wl->wl_lock, flags); + clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); if (recovery) { set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); wl12xx_queue_recovery_work(wl); + } else { + wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", + jiffies_to_msecs(jiffies - start_time)); } - return ret; + return 0; } static const struct dev_pm_ops wlcore_pm_ops = { diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index 8ff0374126e4..65b5985ad402 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -600,9 +600,7 @@ void zd_usb_disable_int(struct zd_usb *usb) dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb); usb_free_urb(urb); - if (buffer) - usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, - buffer, buffer_dma); + usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER, buffer, buffer_dma); } static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, |