diff options
Diffstat (limited to 'drivers/net/wireless')
263 files changed, 14232 insertions, 7905 deletions
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 106d6f8d471a..68f0463ed8df 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1749,7 +1749,7 @@ static void ar5523_disconnect(struct usb_interface *intf) { USB_DEVICE((vendor), (device) + 1), \ .driver_info = AR5523_FLAG_ABG|AR5523_FLAG_PRE_FIRMWARE } -static struct usb_device_id ar5523_id_table[] = { +static const struct usb_device_id ar5523_id_table[] = { AR5523_DEVICE_UG(0x168c, 0x0001), /* Atheros / AR5523 */ AR5523_DEVICE_UG(0x0cf3, 0x0001), /* Atheros2 / AR5523_1 */ AR5523_DEVICE_UG(0x0cf3, 0x0003), /* Atheros2 / AR5523_2 */ diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index 412eb1380dcc..87f56d0e17a6 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -29,6 +29,13 @@ config ATH10K_SDIO This module adds experimental support for SDIO/MMC bus. Currently work in progress and will not fully work. +config ATH10K_USB + tristate "Atheros ath10k USB support (EXPERIMENTAL)" + depends on ATH10K && USB + ---help--- + This module adds experimental support for USB bus. Currently + work in progress and will not fully work. + config ATH10K_DEBUG bool "Atheros ath10k debugging" depends on ATH10K diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index b0b19a7eb98b..899b9b79f4ce 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -30,5 +30,8 @@ ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o obj-$(CONFIG_ATH10K_SDIO) += ath10k_sdio.o ath10k_sdio-y += sdio.o +obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o +ath10k_usb-y += usb.o + # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index da770af83036..ff6815e95684 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -197,35 +197,40 @@ static int ath10k_ahb_rst_ctrl_init(struct ath10k *ar) dev = &ar_ahb->pdev->dev; - ar_ahb->core_cold_rst = devm_reset_control_get(dev, "wifi_core_cold"); + ar_ahb->core_cold_rst = devm_reset_control_get_exclusive(dev, + "wifi_core_cold"); if (IS_ERR(ar_ahb->core_cold_rst)) { ath10k_err(ar, "failed to get core cold rst ctrl: %ld\n", PTR_ERR(ar_ahb->core_cold_rst)); return PTR_ERR(ar_ahb->core_cold_rst); } - ar_ahb->radio_cold_rst = devm_reset_control_get(dev, "wifi_radio_cold"); + ar_ahb->radio_cold_rst = devm_reset_control_get_exclusive(dev, + "wifi_radio_cold"); if (IS_ERR(ar_ahb->radio_cold_rst)) { ath10k_err(ar, "failed to get radio cold rst ctrl: %ld\n", PTR_ERR(ar_ahb->radio_cold_rst)); return PTR_ERR(ar_ahb->radio_cold_rst); } - ar_ahb->radio_warm_rst = devm_reset_control_get(dev, "wifi_radio_warm"); + ar_ahb->radio_warm_rst = devm_reset_control_get_exclusive(dev, + "wifi_radio_warm"); if (IS_ERR(ar_ahb->radio_warm_rst)) { ath10k_err(ar, "failed to get radio warm rst ctrl: %ld\n", PTR_ERR(ar_ahb->radio_warm_rst)); return PTR_ERR(ar_ahb->radio_warm_rst); } - ar_ahb->radio_srif_rst = devm_reset_control_get(dev, "wifi_radio_srif"); + ar_ahb->radio_srif_rst = devm_reset_control_get_exclusive(dev, + "wifi_radio_srif"); if (IS_ERR(ar_ahb->radio_srif_rst)) { ath10k_err(ar, "failed to get radio srif rst ctrl: %ld\n", PTR_ERR(ar_ahb->radio_srif_rst)); return PTR_ERR(ar_ahb->radio_srif_rst); } - ar_ahb->cpu_init_rst = devm_reset_control_get(dev, "wifi_cpu_init"); + ar_ahb->cpu_init_rst = devm_reset_control_get_exclusive(dev, + "wifi_cpu_init"); if (IS_ERR(ar_ahb->cpu_init_rst)) { ath10k_err(ar, "failed to get cpu init rst ctrl: %ld\n", PTR_ERR(ar_ahb->cpu_init_rst)); @@ -787,8 +792,9 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ar_pci->mem = ar_ahb->mem; ar_pci->mem_len = ar_ahb->mem_len; ar_pci->ar = ar; - ar_pci->bus_ops = &ath10k_ahb_bus_ops; + ar_pci->ce.bus_ops = &ath10k_ahb_bus_ops; ar_pci->targ_cpu_to_ce_addr = ath10k_ahb_qca4019_targ_cpu_to_ce_addr; + ar->ce_priv = &ar_pci->ce; ret = ath10k_pci_setup_resource(ar); if (ret) { diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 08b84c8c3614..a8afd690290f 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -16,7 +16,6 @@ */ #include "hif.h" -#include "pci.h" #include "ce.h" #include "debug.h" @@ -33,7 +32,7 @@ * Each ring consists of a number of descriptors which specify * an address, length, and meta-data. * - * Typically, one side of the PCIe interconnect (Host or Target) + * Typically, one side of the PCIe/AHB/SNOC interconnect (Host or Target) * controls one ring and the other side controls the other ring. * The source side chooses when to initiate a transfer and it * chooses what to send (buffer address, length). The destination @@ -73,57 +72,71 @@ ath10k_get_ring_byte(unsigned int offset, return ((offset & addr_map->mask) >> (addr_map->lsb)); } +static inline u32 ath10k_ce_read32(struct ath10k *ar, u32 offset) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + return ce->bus_ops->read32(ar, offset); +} + +static inline void ath10k_ce_write32(struct ath10k *ar, u32 offset, u32 value) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + ce->bus_ops->write32(ar, offset, value); +} + static inline void ath10k_ce_dest_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->dst_wr_index_addr, n); + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dst_wr_index_addr, n); } static inline u32 ath10k_ce_dest_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->dst_wr_index_addr); + return ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dst_wr_index_addr); } static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->sr_wr_index_addr, n); + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_wr_index_addr, n); } static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->sr_wr_index_addr); + return ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_wr_index_addr); } static inline u32 ath10k_ce_src_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->current_srri_addr); + return ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_srri_addr); } static inline void ath10k_ce_src_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->sr_base_addr, addr); + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_base_addr, addr); } static inline void ath10k_ce_src_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->sr_size_addr, n); + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->sr_size_addr, n); } static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, @@ -131,12 +144,13 @@ static inline void ath10k_ce_src_ring_dmax_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; - u32 ctrl1_addr = ath10k_pci_read32(ar, - ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, - (ctrl1_addr & ~(ctrl_regs->dmax->mask)) | - ath10k_set_ring_byte(n, ctrl_regs->dmax)); + u32 ctrl1_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ctrl_regs->addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dmax->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->dmax)); } static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, @@ -144,11 +158,13 @@ static inline void ath10k_ce_src_ring_byte_swap_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, - (ctrl1_addr & ~(ctrl_regs->src_ring->mask)) | - ath10k_set_ring_byte(n, ctrl_regs->src_ring)); + u32 ctrl1_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ctrl_regs->addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->src_ring->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->src_ring)); } static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, @@ -156,34 +172,36 @@ static inline void ath10k_ce_dest_ring_byte_swap_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_ctrl1 *ctrl_regs = ar->hw_ce_regs->ctrl1_regs; - u32 ctrl1_addr = ath10k_pci_read32(ar, ce_ctrl_addr + ctrl_regs->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ctrl_regs->addr, - (ctrl1_addr & ~(ctrl_regs->dst_ring->mask)) | - ath10k_set_ring_byte(n, ctrl_regs->dst_ring)); + u32 ctrl1_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ctrl_regs->addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + ctrl_regs->addr, + (ctrl1_addr & ~(ctrl_regs->dst_ring->mask)) | + ath10k_set_ring_byte(n, ctrl_regs->dst_ring)); } static inline u32 ath10k_ce_dest_ring_read_index_get(struct ath10k *ar, u32 ce_ctrl_addr) { - return ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->current_drri_addr); + return ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->current_drri_addr); } static inline void ath10k_ce_dest_ring_base_addr_set(struct ath10k *ar, u32 ce_ctrl_addr, u32 addr) { - ath10k_pci_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->dr_base_addr, addr); + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_base_addr, addr); } static inline void ath10k_ce_dest_ring_size_set(struct ath10k *ar, u32 ce_ctrl_addr, unsigned int n) { - ath10k_pci_write32(ar, ce_ctrl_addr + - ar->hw_ce_regs->dr_size_addr, n); + ath10k_ce_write32(ar, ce_ctrl_addr + + ar->hw_ce_regs->dr_size_addr, n); } static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, @@ -191,11 +209,11 @@ static inline void ath10k_ce_src_ring_highmark_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + srcr_wm->addr); + u32 addr = ath10k_ce_read32(ar, ce_ctrl_addr + srcr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + srcr_wm->addr, - (addr & ~(srcr_wm->wm_high->mask)) | - (ath10k_set_ring_byte(n, srcr_wm->wm_high))); + ath10k_ce_write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_high->mask)) | + (ath10k_set_ring_byte(n, srcr_wm->wm_high))); } static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, @@ -203,11 +221,11 @@ static inline void ath10k_ce_src_ring_lowmark_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_dst_src_wm_regs *srcr_wm = ar->hw_ce_regs->wm_srcr; - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + srcr_wm->addr); + u32 addr = ath10k_ce_read32(ar, ce_ctrl_addr + srcr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + srcr_wm->addr, - (addr & ~(srcr_wm->wm_low->mask)) | - (ath10k_set_ring_byte(n, srcr_wm->wm_low))); + ath10k_ce_write32(ar, ce_ctrl_addr + srcr_wm->addr, + (addr & ~(srcr_wm->wm_low->mask)) | + (ath10k_set_ring_byte(n, srcr_wm->wm_low))); } static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, @@ -215,11 +233,11 @@ static inline void ath10k_ce_dest_ring_highmark_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + dstr_wm->addr); + u32 addr = ath10k_ce_read32(ar, ce_ctrl_addr + dstr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + dstr_wm->addr, - (addr & ~(dstr_wm->wm_high->mask)) | - (ath10k_set_ring_byte(n, dstr_wm->wm_high))); + ath10k_ce_write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_high->mask)) | + (ath10k_set_ring_byte(n, dstr_wm->wm_high))); } static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, @@ -227,66 +245,73 @@ static inline void ath10k_ce_dest_ring_lowmark_set(struct ath10k *ar, unsigned int n) { struct ath10k_hw_ce_dst_src_wm_regs *dstr_wm = ar->hw_ce_regs->wm_dstr; - u32 addr = ath10k_pci_read32(ar, ce_ctrl_addr + dstr_wm->addr); + u32 addr = ath10k_ce_read32(ar, ce_ctrl_addr + dstr_wm->addr); - ath10k_pci_write32(ar, ce_ctrl_addr + dstr_wm->addr, - (addr & ~(dstr_wm->wm_low->mask)) | - (ath10k_set_ring_byte(n, dstr_wm->wm_low))); + ath10k_ce_write32(ar, ce_ctrl_addr + dstr_wm->addr, + (addr & ~(dstr_wm->wm_low->mask)) | + (ath10k_set_ring_byte(n, dstr_wm->wm_low))); } static inline void ath10k_ce_copy_complete_inter_enable(struct ath10k *ar, u32 ce_ctrl_addr) { struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; - u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, - host_ie_addr | host_ie->copy_complete->mask); + u32 host_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr | host_ie->copy_complete->mask); } static inline void ath10k_ce_copy_complete_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { struct ath10k_hw_ce_host_ie *host_ie = ar->hw_ce_regs->host_ie; - u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, - host_ie_addr & ~(host_ie->copy_complete->mask)); + u32 host_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(host_ie->copy_complete->mask)); } static inline void ath10k_ce_watermark_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; - u32 host_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->host_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, - host_ie_addr & ~(wm_regs->wm_mask)); + u32 host_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->host_ie_addr); + + ath10k_ce_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->host_ie_addr, + host_ie_addr & ~(wm_regs->wm_mask)); } static inline void ath10k_ce_error_intr_enable(struct ath10k *ar, u32 ce_ctrl_addr) { struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; - u32 misc_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->misc_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, - misc_ie_addr | misc_regs->err_mask); + u32 misc_ie_addr = ath10k_ce_read32(ar, ce_ctrl_addr + + ar->hw_ce_regs->misc_ie_addr); + + ath10k_ce_write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr | misc_regs->err_mask); } static inline void ath10k_ce_error_intr_disable(struct ath10k *ar, u32 ce_ctrl_addr) { struct ath10k_hw_ce_misc_regs *misc_regs = ar->hw_ce_regs->misc_regs; - u32 misc_ie_addr = ath10k_pci_read32(ar, ce_ctrl_addr + - ar->hw_ce_regs->misc_ie_addr); - ath10k_pci_write32(ar, ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, - misc_ie_addr & ~(misc_regs->err_mask)); + u32 misc_ie_addr = ath10k_ce_read32(ar, + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr); + + ath10k_ce_write32(ar, + ce_ctrl_addr + ar->hw_ce_regs->misc_ie_addr, + misc_ie_addr & ~(misc_regs->err_mask)); } static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, @@ -295,7 +320,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar, { struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; - ath10k_pci_write32(ar, ce_ctrl_addr + wm_regs->addr, mask); + ath10k_ce_write32(ar, ce_ctrl_addr + wm_regs->addr, mask); } /* @@ -362,11 +387,11 @@ exit: void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_ring *src_ring = pipe->src_ring; u32 ctrl_addr = pipe->ctrl_addr; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ce->ce_lock); /* * This function must be called only if there is an incomplete @@ -394,13 +419,13 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, unsigned int flags) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, buffer, nbytes, transfer_id, flags); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -408,14 +433,14 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int delta; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, pipe->src_ring->write_index, pipe->src_ring->sw_index - 1); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return delta; } @@ -423,13 +448,13 @@ int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; unsigned int sw_index = dest_ring->sw_index; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ce->ce_lock); return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); } @@ -437,7 +462,7 @@ int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe) int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_ring *dest_ring = pipe->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; unsigned int write_index = dest_ring->write_index; @@ -446,7 +471,7 @@ int __ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) struct ce_desc *desc = CE_DEST_RING_TO_DESC(base, write_index); u32 ctrl_addr = pipe->ctrl_addr; - lockdep_assert_held(&ar_pci->ce_lock); + lockdep_assert_held(&ce->ce_lock); if ((pipe->id != 5) && CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) == 0) @@ -486,12 +511,12 @@ void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries) int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) { struct ath10k *ar = pipe->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ret = __ath10k_ce_rx_post_buf(pipe, ctx, paddr); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -554,14 +579,14 @@ int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state, unsigned int *nbytesp) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ret = ath10k_ce_completed_recv_next_nolock(ce_state, per_transfer_contextp, nbytesp); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -576,7 +601,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, unsigned int write_index; int ret; struct ath10k *ar; - struct ath10k_pci *ar_pci; + struct ath10k_ce *ce; dest_ring = ce_state->dest_ring; @@ -584,9 +609,9 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, return -EIO; ar = ce_state->ar; - ar_pci = ath10k_pci_priv(ar); + ce = ath10k_ce_priv(ar); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); nentries_mask = dest_ring->nentries_mask; sw_index = dest_ring->sw_index; @@ -614,7 +639,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, ret = -EIO; } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -686,7 +711,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, unsigned int write_index; int ret; struct ath10k *ar; - struct ath10k_pci *ar_pci; + struct ath10k_ce *ce; src_ring = ce_state->src_ring; @@ -694,9 +719,9 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, return -EIO; ar = ce_state->ar; - ar_pci = ath10k_pci_priv(ar); + ce = ath10k_ce_priv(ar); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); nentries_mask = src_ring->nentries_mask; sw_index = src_ring->sw_index; @@ -727,7 +752,7 @@ int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state, ret = -EIO; } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -736,13 +761,13 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp) { struct ath10k *ar = ce_state->ar; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ret = ath10k_ce_completed_send_next_nolock(ce_state, per_transfer_contextp); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -755,17 +780,18 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, */ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; struct ath10k_hw_ce_host_wm_regs *wm_regs = ar->hw_ce_regs->wm_regs; u32 ctrl_addr = ce_state->ctrl_addr; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); /* Clear the copy-complete interrupts that will be handled here. */ - ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->cc_mask); + ath10k_ce_engine_int_status_clear(ar, ctrl_addr, + wm_regs->cc_mask); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); if (ce_state->recv_cb) ce_state->recv_cb(ce_state); @@ -773,7 +799,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) if (ce_state->send_cb) ce_state->send_cb(ce_state); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); /* * Misc CE interrupts are not being handled, but still need @@ -781,7 +807,7 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id) */ ath10k_ce_engine_int_status_clear(ar, ctrl_addr, wm_regs->wm_mask); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); } /* @@ -795,7 +821,7 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar) int ce_id; u32 intr_summary; - intr_summary = CE_INTERRUPT_SUMMARY(ar); + intr_summary = ath10k_ce_interrupt_summary(ar); for (ce_id = 0; intr_summary && (ce_id < CE_COUNT); ce_id++) { if (intr_summary & (1 << ce_id)) @@ -847,22 +873,25 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar) void ath10k_ce_enable_interrupts(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ce_id; + struct ath10k_ce_pipe *ce_state; /* Skip the last copy engine, CE7 the diagnostic window, as that * uses polling and isn't initialized for interrupts. */ - for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) - ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]); + for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) { + ce_state = &ce->ce_states[ce_id]; + ath10k_ce_per_engine_handler_adjust(ce_state); + } } static int ath10k_ce_init_src_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; struct ath10k_ce_ring *src_ring = ce_state->src_ring; u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); @@ -898,8 +927,8 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id); @@ -1081,8 +1110,8 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; int ret; /* @@ -1138,8 +1167,8 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_pipe *ce_state = &ce->ce_states[ce_id]; if (ce_state->src_ring) { dma_free_coherent(ar->dev, @@ -1168,38 +1197,38 @@ void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_crash_data ce; + struct ath10k_ce *ce = ath10k_ce_priv(ar); + struct ath10k_ce_crash_data ce_data; u32 addr, id; lockdep_assert_held(&ar->data_lock); ath10k_err(ar, "Copy Engine register dump:\n"); - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); for (id = 0; id < CE_COUNT; id++) { addr = ath10k_ce_base_address(ar, id); - ce.base_addr = cpu_to_le32(addr); + ce_data.base_addr = cpu_to_le32(addr); - ce.src_wr_idx = + ce_data.src_wr_idx = cpu_to_le32(ath10k_ce_src_ring_write_index_get(ar, addr)); - ce.src_r_idx = + ce_data.src_r_idx = cpu_to_le32(ath10k_ce_src_ring_read_index_get(ar, addr)); - ce.dst_wr_idx = + ce_data.dst_wr_idx = cpu_to_le32(ath10k_ce_dest_ring_write_index_get(ar, addr)); - ce.dst_r_idx = + ce_data.dst_r_idx = cpu_to_le32(ath10k_ce_dest_ring_read_index_get(ar, addr)); if (crash_data) - crash_data->ce_crash_data[id] = ce; + crash_data->ce_crash_data[id] = ce_data; ath10k_err(ar, "[%02d]: 0x%08x %3u %3u %3u %3u", id, - le32_to_cpu(ce.base_addr), - le32_to_cpu(ce.src_wr_idx), - le32_to_cpu(ce.src_r_idx), - le32_to_cpu(ce.dst_wr_idx), - le32_to_cpu(ce.dst_r_idx)); + le32_to_cpu(ce_data.base_addr), + le32_to_cpu(ce_data.src_wr_idx), + le32_to_cpu(ce_data.src_r_idx), + le32_to_cpu(ce_data.dst_wr_idx), + le32_to_cpu(ce_data.dst_r_idx)); } - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); } diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 95743a57525d..bdec794704d9 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -122,6 +122,24 @@ struct ath10k_ce_pipe { /* Copy Engine settable attributes */ struct ce_attr; +struct ath10k_bus_ops { + u32 (*read32)(struct ath10k *ar, u32 offset); + void (*write32)(struct ath10k *ar, u32 offset, u32 value); + int (*get_num_banks)(struct ath10k *ar); +}; + +static inline struct ath10k_ce *ath10k_ce_priv(struct ath10k *ar) +{ + return (struct ath10k_ce *)ar->ce_priv; +} + +struct ath10k_ce { + /* protects CE info */ + spinlock_t ce_lock; + const struct ath10k_bus_ops *bus_ops; + struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; +}; + /*==================Send====================*/ /* ath10k_ce_send flags */ @@ -291,9 +309,13 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) #define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 -#define CE_INTERRUPT_SUMMARY(ar) \ - CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \ - ath10k_pci_read32((ar), CE_WRAPPER_BASE_ADDRESS + \ - CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)) +static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar) +{ + struct ath10k_ce *ce = ath10k_ce_priv(ar); + + return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( + ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); +} #endif /* _CE_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 75c5c903c8a6..a4f635820f35 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -519,7 +519,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, dir = "."; snprintf(filename, sizeof(filename), "%s/%s", dir, file); - ret = request_firmware_direct(&fw, filename, ar->dev); + ret = request_firmware(&fw, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", filename, ret); @@ -1454,6 +1454,7 @@ static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name, { switch (ar->hif.bus) { case ATH10K_BUS_SDIO: + case ATH10K_BUS_USB: scnprintf(fw_name, fw_name_len, "%s-%s-%d.bin", ATH10K_FW_FILE_BASE, ath10k_bus_str(ar->hif.bus), fw_api); @@ -1885,6 +1886,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->fw_stats_req_mask = WMI_10_4_STAT_PEER | WMI_10_4_STAT_PEER_EXTD; ar->max_spatial_stream = ar->hw_params.max_spatial_stream; + ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS; if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, fw_file->fw_features)) @@ -2055,6 +2057,12 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_wmi_detach; } + /* If firmware indicates Full Rx Reorder support it must be used in a + * slightly different manner. Let HTT code know. + */ + ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, + ar->wmi.svc_map)); + status = ath10k_htt_rx_alloc(&ar->htt); if (status) { ath10k_err(ar, "failed to alloc htt rx: %d\n", status); @@ -2123,6 +2131,14 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ar->running_fw->fw_file.fw_features)) val |= WMI_10_4_COEX_GPIO_SUPPORT; + if (test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, + ar->wmi.svc_map)) + val |= WMI_10_4_TDLS_EXPLICIT_MODE_ONLY; + + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, + ar->wmi.svc_map)) + val |= WMI_10_4_TDLS_UAPSD_BUFFER_STA; + status = ath10k_mac_ext_resource_config(ar, val); if (status) { ath10k_err(ar, @@ -2167,12 +2183,6 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, } } - /* If firmware indicates Full Rx Reorder support it must be used in a - * slightly different manner. Let HTT code know. - */ - ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER, - ar->wmi.svc_map)); - status = ath10k_htt_rx_ring_refill(ar); if (status) { ath10k_err(ar, "failed to refill htt rx ring: %d\n", status); @@ -2516,6 +2526,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->hw_ce_regs = &qcax_ce_regs; ar->hw_values = &qca4019_values; break; + case ATH10K_HW_WCN3990: + ar->regs = &wcn3990_regs; + ar->hw_ce_regs = &wcn3990_ce_regs; + ar->hw_values = &wcn3990_values; + break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 1aa5cf12fce0..949ebb3e967b 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -92,6 +92,7 @@ enum ath10k_bus { ATH10K_BUS_PCI, ATH10K_BUS_AHB, ATH10K_BUS_SDIO, + ATH10K_BUS_USB, }; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -103,6 +104,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus) return "ahb"; case ATH10K_BUS_SDIO: return "sdio"; + case ATH10K_BUS_USB: + return "usb"; } return "unknown"; @@ -459,7 +462,7 @@ struct ath10k_ce_crash_hdr { struct ath10k_fw_crash_data { bool crashed_since_read; - uuid_le uuid; + guid_t guid; struct timespec timestamp; __le32 registers[REG_DUMP_COUNT_QCA988X]; struct ath10k_ce_crash_data ce_crash_data[CE_COUNT_MAX]; @@ -993,6 +996,10 @@ struct ath10k { u32 reg_ack_cts_timeout_orig; } fw_coverage; + u32 ampdu_reference; + + void *ce_priv; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 389fcb7a9fd0..df514507d3f1 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -70,7 +70,7 @@ struct ath10k_dump_file_data { /* some info we can get from ath10k struct that might help */ - u8 uuid[16]; + guid_t guid; __le32 chip_id; @@ -237,7 +237,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file, { struct ath10k *ar = file->private_data; char *buf; - size_t len = 0, buf_len = 4096; + size_t len = 0, buf_len = 8192; const char *name; ssize_t ret_cnt; bool enabled; @@ -719,7 +719,7 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) lockdep_assert_held(&ar->data_lock); crash_data->crashed_since_read = true; - uuid_le_gen(&crash_data->uuid); + guid_gen(&crash_data->guid); getnstimeofday(&crash_data->timestamp); return crash_data; @@ -766,7 +766,7 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar, dump_data->version = cpu_to_le32(ATH10K_FW_CRASH_DUMP_VERSION); - memcpy(dump_data->uuid, &crash_data->uuid, sizeof(dump_data->uuid)); + guid_copy(&dump_data->guid, &crash_data->guid); dump_data->chip_id = cpu_to_le32(ar->chip_id); dump_data->bus_type = cpu_to_le32(0); dump_data->target_version = cpu_to_le32(ar->target_version); diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 257d10985c6e..548ad5483a4a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -40,6 +40,8 @@ enum ath10k_debug_mask { ATH10K_DBG_AHB = 0x00008000, ATH10K_DBG_SDIO = 0x00010000, ATH10K_DBG_SDIO_DUMP = 0x00020000, + ATH10K_DBG_USB = 0x00040000, + ATH10K_DBG_USB_BULK = 0x00080000, ATH10K_DBG_ANY = 0xffffffff, }; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 398dda978d6e..a3f5dc78353f 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -890,16 +890,26 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar, status->nss = 0; status->encoding = RX_ENC_LEGACY; status->bw = RATE_INFO_BW_20; + status->flag &= ~RX_FLAG_MACTIME_END; status->flag |= RX_FLAG_NO_SIGNAL_VAL; + status->flag &= ~(RX_FLAG_AMPDU_IS_LAST); + status->flag |= RX_FLAG_AMPDU_DETAILS | RX_FLAG_AMPDU_LAST_KNOWN; + status->ampdu_reference = ar->ampdu_reference; + ath10k_htt_rx_h_signal(ar, status, rxd); ath10k_htt_rx_h_channel(ar, status, rxd, vdev_id); ath10k_htt_rx_h_rates(ar, status, rxd); } - if (is_last_ppdu) + if (is_last_ppdu) { ath10k_htt_rx_h_mactime(ar, status, rxd); + + /* set ampdu last segment flag */ + status->flag |= RX_FLAG_AMPDU_IS_LAST; + ar->ampdu_reference++; + } } static const char * const tid_to_ac[] = { @@ -1514,7 +1524,7 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, */ if (!rx_status->freq) { - ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n"); + ath10k_dbg(ar, ATH10K_DBG_HTT, "no channel configured; ignoring frame(s)!\n"); return false; } @@ -1735,7 +1745,8 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp) } static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, - struct sk_buff_head *amsdu) + struct sk_buff_head *amsdu, + int budget_left) { struct sk_buff *msdu; struct htt_rx_desc *rxd; @@ -1746,8 +1757,9 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, if (WARN_ON(!skb_queue_empty(amsdu))) return -EINVAL; - while ((msdu = __skb_dequeue(list))) { + while ((msdu = __skb_dequeue(list)) && budget_left) { __skb_queue_tail(amsdu, msdu); + budget_left--; rxd = (void *)msdu->data - sizeof(*rxd); if (rxd->msdu_end.common.info0 & @@ -1838,7 +1850,8 @@ static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar, return num_msdu; } -static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb, + int budget_left) { struct ath10k_htt *htt = &ar->htt; struct htt_resp *resp = (void *)skb->data; @@ -1895,9 +1908,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) if (offload) num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list); - while (!skb_queue_empty(&list)) { + while (!skb_queue_empty(&list) && budget_left) { __skb_queue_head_init(&amsdu); - ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu); + ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu, budget_left); switch (ret) { case 0: /* Note: The in-order indication may report interleaved @@ -1907,6 +1920,7 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) * should still give an idea about rx rate to the user. */ num_msdus += skb_queue_len(&amsdu); + budget_left -= skb_queue_len(&amsdu); ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); ath10k_htt_rx_h_filter(ar, &amsdu, status); ath10k_htt_rx_h_mpdu(ar, &amsdu, status); @@ -2549,7 +2563,8 @@ int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget) } spin_lock_bh(&htt->rx_ring.lock); - num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb); + num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb, + (budget - quota)); spin_unlock_bh(&htt->rx_ring.lock); if (num_rx_msdus < 0) { resched_napi = true; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index afb0c01cbb55..a860691d635d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -192,6 +192,156 @@ const struct ath10k_hw_values qca4019_values = { .ce_desc_meta_data_lsb = 4, }; +const struct ath10k_hw_regs wcn3990_regs = { + .rtc_soc_base_address = 0x00000000, + .rtc_wmac_base_address = 0x00000000, + .soc_core_base_address = 0x00000000, + .ce_wrapper_base_address = 0x0024C000, + .ce0_base_address = 0x00240000, + .ce1_base_address = 0x00241000, + .ce2_base_address = 0x00242000, + .ce3_base_address = 0x00243000, + .ce4_base_address = 0x00244000, + .ce5_base_address = 0x00245000, + .ce6_base_address = 0x00246000, + .ce7_base_address = 0x00247000, + .ce8_base_address = 0x00248000, + .ce9_base_address = 0x00249000, + .ce10_base_address = 0x0024A000, + .ce11_base_address = 0x0024B000, + .soc_chip_id_address = 0x000000f0, + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00000100, + .ce_wrap_intr_sum_host_msi_lsb = 0x0000000c, + .ce_wrap_intr_sum_host_msi_mask = 0x00fff000, + .pcie_intr_fw_mask = 0x00100000, +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_src_ring = { + .msb = 0x00000010, + .lsb = 0x00000010, + .mask = GENMASK(17, 17), +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_dst_ring = { + .msb = 0x00000012, + .lsb = 0x00000012, + .mask = GENMASK(18, 18), +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_dmax = { + .msb = 0x00000000, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_ctrl1 wcn3990_ctrl1 = { + .addr = 0x00000018, + .src_ring = &wcn3990_src_ring, + .dst_ring = &wcn3990_dst_ring, + .dmax = &wcn3990_dmax, +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_host_ie_cc = { + .mask = GENMASK(0, 0), +}; + +static struct ath10k_hw_ce_host_ie wcn3990_host_ie = { + .copy_complete = &wcn3990_host_ie_cc, +}; + +static struct ath10k_hw_ce_host_wm_regs wcn3990_wm_reg = { + .dstr_lmask = 0x00000010, + .dstr_hmask = 0x00000008, + .srcr_lmask = 0x00000004, + .srcr_hmask = 0x00000002, + .cc_mask = 0x00000001, + .wm_mask = 0x0000001E, + .addr = 0x00000030, +}; + +static struct ath10k_hw_ce_misc_regs wcn3990_misc_reg = { + .axi_err = 0x00000100, + .dstr_add_err = 0x00000200, + .srcr_len_err = 0x00000100, + .dstr_mlen_vio = 0x00000080, + .dstr_overflow = 0x00000040, + .srcr_overflow = 0x00000020, + .err_mask = 0x000003E0, + .addr = 0x00000038, +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_src_wm_low = { + .msb = 0x00000000, + .lsb = 0x00000010, + .mask = GENMASK(31, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_src_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_src_ring = { + .addr = 0x0000004c, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &wcn3990_src_wm_low, + .wm_high = &wcn3990_src_wm_high, +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_dst_wm_low = { + .lsb = 0x00000010, + .mask = GENMASK(31, 16), +}; + +static struct ath10k_hw_ce_regs_addr_map wcn3990_dst_wm_high = { + .msb = 0x0000000f, + .lsb = 0x00000000, + .mask = GENMASK(15, 0), +}; + +static struct ath10k_hw_ce_dst_src_wm_regs wcn3990_wm_dst_ring = { + .addr = 0x00000050, + .low_rst = 0x00000000, + .high_rst = 0x00000000, + .wm_low = &wcn3990_dst_wm_low, + .wm_high = &wcn3990_dst_wm_high, +}; + +struct ath10k_hw_ce_regs wcn3990_ce_regs = { + .sr_base_addr = 0x00000000, + .sr_size_addr = 0x00000008, + .dr_base_addr = 0x0000000c, + .dr_size_addr = 0x00000014, + .misc_ie_addr = 0x00000034, + .sr_wr_index_addr = 0x0000003c, + .dst_wr_index_addr = 0x00000040, + .current_srri_addr = 0x00000044, + .current_drri_addr = 0x00000048, + .ddr_addr_for_rri_low = 0x00000004, + .ddr_addr_for_rri_high = 0x00000008, + .ce_rri_low = 0x0024C004, + .ce_rri_high = 0x0024C008, + .host_ie_addr = 0x0000002c, + .ctrl1_regs = &wcn3990_ctrl1, + .host_ie = &wcn3990_host_ie, + .wm_regs = &wcn3990_wm_reg, + .misc_regs = &wcn3990_misc_reg, + .wm_srcr = &wcn3990_wm_src_ring, + .wm_dstr = &wcn3990_wm_dst_ring, +}; + +const struct ath10k_hw_values wcn3990_values = { + .rtc_state_val_on = 5, + .ce_count = 12, + .msi_assign_ce_max = 12, + .num_target_ce_config_wlan = 12, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, +}; + static struct ath10k_hw_ce_regs_addr_map qcax_src_ring = { .msb = 0x00000010, .lsb = 0x00000010, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 97dc1479f44e..0c089f6dd3d9 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -231,6 +231,7 @@ enum ath10k_hw_rev { ATH10K_HW_QCA9377, ATH10K_HW_QCA4019, ATH10K_HW_QCA9887, + ATH10K_HW_WCN3990, }; struct ath10k_hw_regs { @@ -247,6 +248,10 @@ struct ath10k_hw_regs { u32 ce5_base_address; u32 ce6_base_address; u32 ce7_base_address; + u32 ce8_base_address; + u32 ce9_base_address; + u32 ce10_base_address; + u32 ce11_base_address; u32 soc_reset_control_si0_rst_mask; u32 soc_reset_control_ce_rst_mask; u32 soc_chip_id_address; @@ -267,6 +272,7 @@ extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; extern const struct ath10k_hw_regs qca99x0_regs; extern const struct ath10k_hw_regs qca4019_regs; +extern const struct ath10k_hw_regs wcn3990_regs; struct ath10k_hw_ce_regs_addr_map { u32 msb; @@ -362,6 +368,8 @@ extern const struct ath10k_hw_values qca6174_values; extern const struct ath10k_hw_values qca99x0_values; extern const struct ath10k_hw_values qca9888_values; extern const struct ath10k_hw_values qca4019_values; +extern const struct ath10k_hw_values wcn3990_values; +extern struct ath10k_hw_ce_regs wcn3990_ce_regs; extern struct ath10k_hw_ce_regs qcax_ce_regs; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, @@ -375,6 +383,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, #define QCA_REV_9984(ar) ((ar)->hw_rev == ATH10K_HW_QCA9984) #define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377) #define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019) +#define QCA_REV_WCN3990(ar) ((ar)->hw_rev == ATH10K_HW_WCN3990) /* Known peculiarities: * - raw appears in nwifi decap, raw and nwifi appear in ethernet decap @@ -711,6 +720,11 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw, #define TARGET_10_4_IPHDR_PAD_CONFIG 1 #define TARGET_10_4_QWRAP_CONFIG 0 +/* TDLS config */ +#define TARGET_10_4_NUM_TDLS_VDEVS 1 +#define TARGET_10_4_NUM_TDLS_BUFFER_STA 1 +#define TARGET_10_4_NUM_TDLS_SLEEP_STA 1 + /* Maximum number of Copy Engine's supported */ #define CE_COUNT_MAX 12 diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 55c808f03a84..5683f1a5330e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7644,6 +7644,7 @@ static const struct ieee80211_ops ath10k_ops = { #ifdef CONFIG_PM .suspend = ath10k_wow_op_suspend, .resume = ath10k_wow_op_resume, + .set_wakeup = ath10k_wow_op_set_wakeup, #endif #ifdef CONFIG_MAC80211_DEBUGFS .sta_add_debugfs = ath10k_sta_add_debugfs, @@ -8197,8 +8198,11 @@ int ath10k_mac_register(struct ath10k *ar) NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; } - if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map)) + if (test_bit(WMI_SERVICE_TDLS, ar->wmi.svc_map) || + test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, ar->wmi.svc_map)) { ar->hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; + ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); + } ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 7ebfc409018d..bc1633945a56 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -672,16 +672,16 @@ static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset) inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); - ar_pci->bus_ops->write32(ar, offset, value); + ce->bus_ops->write32(ar, offset, value); } inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); - return ar_pci->bus_ops->read32(ar, offset); + return ce->bus_ops->read32(ar, offset); } u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr) @@ -761,7 +761,7 @@ static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) { struct ath10k *ar = pipe->hif_ce_state; - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; struct sk_buff *skb; dma_addr_t paddr; @@ -784,9 +784,9 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) ATH10K_SKB_RXCB(skb)->paddr = paddr; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); if (ret) { dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -801,6 +801,7 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) { struct ath10k *ar = pipe->hif_ce_state; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; int ret, num; @@ -810,9 +811,9 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) if (!ce_pipe->dest_ring) return; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); num = __ath10k_ce_rx_num_free_bufs(ce_pipe); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); while (num >= 0) { ret = __ath10k_pci_rx_post_buf(pipe); @@ -882,6 +883,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, int nbytes) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret = 0; u32 *buf; unsigned int completed_nbytes, alloc_nbytes, remaining_bytes; @@ -892,7 +894,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, void *data_buf = NULL; int i; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ce_diag = ar_pci->ce_diag; @@ -986,7 +988,7 @@ done: dma_free_coherent(ar->dev, alloc_nbytes, data_buf, ce_data_base); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -1034,6 +1036,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, const void *data, int nbytes) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret = 0; u32 *buf; unsigned int completed_nbytes, orig_nbytes, remaining_bytes; @@ -1043,7 +1046,7 @@ int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, dma_addr_t ce_data_base = 0; int i; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); ce_diag = ar_pci->ce_diag; @@ -1147,7 +1150,7 @@ done: ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n", address, ret); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return ret; } @@ -1342,6 +1345,7 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, struct ath10k_hif_sg_item *items, int n_items) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id]; struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl; struct ath10k_ce_ring *src_ring = ce_pipe->src_ring; @@ -1350,7 +1354,7 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, unsigned int write_index; int err, i = 0; - spin_lock_bh(&ar_pci->ce_lock); + spin_lock_bh(&ce->ce_lock); nentries_mask = src_ring->nentries_mask; sw_index = src_ring->sw_index; @@ -1396,14 +1400,14 @@ int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, if (err) goto err; - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return 0; err: for (; i > 0; i--) __ath10k_ce_send_revert(ce_pipe); - spin_unlock_bh(&ar_pci->ce_lock); + spin_unlock_bh(&ce->ce_lock); return err; } @@ -1459,7 +1463,7 @@ static void ath10k_pci_dump_registers(struct ath10k *ar, static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) { struct ath10k_fw_crash_data *crash_data; - char uuid[50]; + char guid[UUID_STRING_LEN + 1]; spin_lock_bh(&ar->data_lock); @@ -1468,11 +1472,11 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) crash_data = ath10k_debug_get_new_fw_crash_data(ar); if (crash_data) - scnprintf(uuid, sizeof(uuid), "%pUl", &crash_data->uuid); + scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid); else - scnprintf(uuid, sizeof(uuid), "n/a"); + scnprintf(guid, sizeof(guid), "n/a"); - ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid); + ath10k_err(ar, "firmware crashed! (guid %s)\n", guid); ath10k_print_driver_info(ar); ath10k_pci_dump_registers(ar, crash_data); ath10k_ce_dump_registers(ar, crash_data); @@ -1593,6 +1597,8 @@ void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) * to mask irq/MSI. */ break; + case ATH10K_HW_WCN3990: + break; } } @@ -1619,6 +1625,8 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) * to unmask irq/MSI. */ break; + case ATH10K_HW_WCN3990: + break; } } @@ -2000,9 +2008,9 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) static int ath10k_bus_get_num_banks(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); - return ar_pci->bus_ops->get_num_banks(ar); + return ce->bus_ops->get_num_banks(ar); } int ath10k_pci_init_config(struct ath10k *ar) @@ -2173,11 +2181,12 @@ int ath10k_pci_alloc_pipes(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_pci_pipe *pipe; + struct ath10k_ce *ce = ath10k_ce_priv(ar); int i, ret; for (i = 0; i < CE_COUNT; i++) { pipe = &ar_pci->pipe_info[i]; - pipe->ce_hdl = &ar_pci->ce_states[i]; + pipe->ce_hdl = &ce->ce_states[i]; pipe->pipe_num = i; pipe->hif_ce_state = ar; @@ -2825,7 +2834,7 @@ static int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget) * interrupts safer to check for pending interrupts for * immediate servicing. */ - if (CE_INTERRUPT_SUMMARY(ar)) { + if (ath10k_ce_interrupt_summary(ar)) { napi_reschedule(ctx); goto out; } @@ -3142,9 +3151,10 @@ static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) int ath10k_pci_setup_resource(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_ce *ce = ath10k_ce_priv(ar); int ret; - spin_lock_init(&ar_pci->ce_lock); + spin_lock_init(&ce->ce_lock); spin_lock_init(&ar_pci->ps_lock); setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, @@ -3263,10 +3273,11 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->ar = ar; ar->dev_id = pci_dev->device; ar_pci->pci_ps = pci_ps; - ar_pci->bus_ops = &ath10k_pci_bus_ops; + ar_pci->ce.bus_ops = &ath10k_pci_bus_ops; ar_pci->pci_soft_reset = pci_soft_reset; ar_pci->pci_hard_reset = pci_hard_reset; ar_pci->targ_cpu_to_ce_addr = targ_cpu_to_ce_addr; + ar->ce_priv = &ar_pci->ce; ar->id.vendor = pdev->vendor; ar->id.device = pdev->device; @@ -3385,11 +3396,53 @@ static void ath10k_pci_remove(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, ath10k_pci_id_table); +#ifdef CONFIG_PM + +static int ath10k_pci_pm_suspend(struct device *dev) +{ + struct ath10k *ar = dev_get_drvdata(dev); + int ret; + + if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + ar->running_fw->fw_file.fw_features)) + return 0; + + ret = ath10k_hif_suspend(ar); + if (ret) + ath10k_warn(ar, "failed to suspend hif: %d\n", ret); + + return ret; +} + +static int ath10k_pci_pm_resume(struct device *dev) +{ + struct ath10k *ar = dev_get_drvdata(dev); + int ret; + + if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + ar->running_fw->fw_file.fw_features)) + return 0; + + ret = ath10k_hif_resume(ar); + if (ret) + ath10k_warn(ar, "failed to resume hif: %d\n", ret); + + return ret; +} + +static SIMPLE_DEV_PM_OPS(ath10k_pci_pm_ops, + ath10k_pci_pm_suspend, + ath10k_pci_pm_resume); +#endif + static struct pci_driver ath10k_pci_driver = { .name = "ath10k_pci", .id_table = ath10k_pci_id_table, .probe = ath10k_pci_probe, .remove = ath10k_pci_remove, +#ifdef CONFIG_PM + .driver.pm = &ath10k_pci_pm_ops, +#endif }; static int __init ath10k_pci_init(void) diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index c1e08ad63940..424ff323b2dc 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -150,12 +150,6 @@ struct ath10k_pci_supp_chip { u32 rev_id; }; -struct ath10k_bus_ops { - u32 (*read32)(struct ath10k *ar, u32 offset); - void (*write32)(struct ath10k *ar, u32 offset, u32 value); - int (*get_num_banks)(struct ath10k *ar); -}; - enum ath10k_pci_irq_mode { ATH10K_PCI_IRQ_AUTO = 0, ATH10K_PCI_IRQ_LEGACY = 1, @@ -177,11 +171,7 @@ struct ath10k_pci { /* Copy Engine used for Diagnostic Accesses */ struct ath10k_ce_pipe *ce_diag; - /* FIXME: document what this really protects */ - spinlock_t ce_lock; - - /* Map CE id to ce_state */ - struct ath10k_ce_pipe ce_states[CE_COUNT_MAX]; + struct ath10k_ce ce; struct timer_list rx_post_retry; /* Due to HW quirks it is recommended to disable ASPM during device @@ -225,8 +215,6 @@ struct ath10k_pci { */ bool pci_ps; - const struct ath10k_bus_ops *bus_ops; - /* Chip specific pci reset routine used to do a safe reset */ int (*pci_soft_reset)(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 859ed870bd97..03a69e5b1116 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -683,7 +683,7 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar, lookaheads[0] = msg_lookahead; timeout = jiffies + SDIO_MBOX_PROCESSING_TIMEOUT_HZ; - while (time_before(jiffies, timeout)) { + do { /* Try to allocate as many HTC RX packets indicated by * n_lookaheads. */ @@ -719,7 +719,7 @@ static int ath10k_sdio_mbox_rxmsg_pending_handler(struct ath10k *ar, * performance in high throughput situations. */ *done = false; - } + } while (time_before(jiffies, timeout)); if (ret && (ret != -ECANCELED)) ath10k_warn(ar, "failed to get pending recv messages: %d\n", @@ -1336,16 +1336,14 @@ static void ath10k_sdio_irq_handler(struct sdio_func *func) sdio_release_host(ar_sdio->func); timeout = jiffies + ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ; - while (time_before(jiffies, timeout) && !done) { + do { ret = ath10k_sdio_mbox_proc_pending_irqs(ar, &done); if (ret) break; - } + } while (time_before(jiffies, timeout) && !done); sdio_claim_host(ar_sdio->func); - wake_up(&ar_sdio->irq_wq); - if (ret && ret != -ECANCELED) ath10k_warn(ar, "failed to process pending SDIO interrupts: %d\n", ret); @@ -2000,8 +1998,6 @@ static int ath10k_sdio_probe(struct sdio_func *func, goto err_free_bmi_buf; } - init_waitqueue_head(&ar_sdio->irq_wq); - for (i = 0; i < ATH10K_SDIO_BUS_REQUEST_MAX_NUM; i++) ath10k_sdio_free_bus_req(ar, &ar_sdio->bus_req[i]); diff --git a/drivers/net/wireless/ath/ath10k/sdio.h b/drivers/net/wireless/ath/ath10k/sdio.h index 3f61c67c601d..4ff7b545293b 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.h +++ b/drivers/net/wireless/ath/ath10k/sdio.h @@ -210,8 +210,6 @@ struct ath10k_sdio { /* temporary buffer for BMI requests */ u8 *bmi_buf; - wait_queue_head_t irq_wq; - bool is_disabled; struct workqueue_struct *workqueue; diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c new file mode 100644 index 000000000000..d4803ff5a78a --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2007-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc. + * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/module.h> +#include <linux/usb.h> + +#include "debug.h" +#include "core.h" +#include "bmi.h" +#include "hif.h" +#include "htc.h" +#include "usb.h" + +static void ath10k_usb_post_recv_transfers(struct ath10k *ar, + struct ath10k_usb_pipe *recv_pipe); + +/* inlined helper functions */ + +static inline enum ath10k_htc_ep_id +eid_from_htc_hdr(struct ath10k_htc_hdr *htc_hdr) +{ + return (enum ath10k_htc_ep_id)htc_hdr->eid; +} + +static inline bool is_trailer_only_msg(struct ath10k_htc_hdr *htc_hdr) +{ + return __le16_to_cpu(htc_hdr->len) == htc_hdr->trailer_len; +} + +/* pipe/urb operations */ +static struct ath10k_urb_context * +ath10k_usb_alloc_urb_from_pipe(struct ath10k_usb_pipe *pipe) +{ + struct ath10k_urb_context *urb_context = NULL; + unsigned long flags; + + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); + if (!list_empty(&pipe->urb_list_head)) { + urb_context = list_first_entry(&pipe->urb_list_head, + struct ath10k_urb_context, link); + list_del(&urb_context->link); + pipe->urb_cnt--; + } + spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags); + + return urb_context; +} + +static void ath10k_usb_free_urb_to_pipe(struct ath10k_usb_pipe *pipe, + struct ath10k_urb_context *urb_context) +{ + unsigned long flags; + + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); + + pipe->urb_cnt++; + list_add(&urb_context->link, &pipe->urb_list_head); + + spin_unlock_irqrestore(&pipe->ar_usb->cs_lock, flags); +} + +static void ath10k_usb_cleanup_recv_urb(struct ath10k_urb_context *urb_context) +{ + dev_kfree_skb(urb_context->skb); + urb_context->skb = NULL; + + ath10k_usb_free_urb_to_pipe(urb_context->pipe, urb_context); +} + +static void ath10k_usb_free_pipe_resources(struct ath10k *ar, + struct ath10k_usb_pipe *pipe) +{ + struct ath10k_urb_context *urb_context; + + if (!pipe->ar_usb) { + /* nothing allocated for this pipe */ + return; + } + + ath10k_dbg(ar, ATH10K_DBG_USB, + "usb free resources lpipe %d hpipe 0x%x urbs %d avail %d\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->urb_alloc, pipe->urb_cnt); + + if (pipe->urb_alloc != pipe->urb_cnt) { + ath10k_dbg(ar, ATH10K_DBG_USB, + "usb urb leak lpipe %d hpipe 0x%x urbs %d avail %d\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->urb_alloc, pipe->urb_cnt); + } + + for (;;) { + urb_context = ath10k_usb_alloc_urb_from_pipe(pipe); + + if (!urb_context) + break; + + kfree(urb_context); + } +} + +static void ath10k_usb_cleanup_pipe_resources(struct ath10k *ar) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + int i; + + for (i = 0; i < ATH10K_USB_PIPE_MAX; i++) + ath10k_usb_free_pipe_resources(ar, &ar_usb->pipes[i]); +} + +/* hif usb rx/tx completion functions */ + +static void ath10k_usb_recv_complete(struct urb *urb) +{ + struct ath10k_urb_context *urb_context = urb->context; + struct ath10k_usb_pipe *pipe = urb_context->pipe; + struct ath10k *ar = pipe->ar_usb->ar; + struct sk_buff *skb; + int status = 0; + + ath10k_dbg(ar, ATH10K_DBG_USB_BULK, + "usb recv pipe %d stat %d len %d urb 0x%pK\n", + pipe->logical_pipe_num, urb->status, urb->actual_length, + urb); + + if (urb->status != 0) { + status = -EIO; + switch (urb->status) { + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* no need to spew these errors when device + * removed or urb killed due to driver shutdown + */ + status = -ECANCELED; + break; + default: + ath10k_dbg(ar, ATH10K_DBG_USB_BULK, + "usb recv pipe %d ep 0x%2.2x failed: %d\n", + pipe->logical_pipe_num, + pipe->ep_address, urb->status); + break; + } + goto cleanup_recv_urb; + } + + if (urb->actual_length == 0) + goto cleanup_recv_urb; + + skb = urb_context->skb; + + /* we are going to pass it up */ + urb_context->skb = NULL; + skb_put(skb, urb->actual_length); + + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, skb); + schedule_work(&pipe->io_complete_work); + +cleanup_recv_urb: + ath10k_usb_cleanup_recv_urb(urb_context); + + if (status == 0 && + pipe->urb_cnt >= pipe->urb_cnt_thresh) { + /* our free urbs are piling up, post more transfers */ + ath10k_usb_post_recv_transfers(ar, pipe); + } +} + +static void ath10k_usb_transmit_complete(struct urb *urb) +{ + struct ath10k_urb_context *urb_context = urb->context; + struct ath10k_usb_pipe *pipe = urb_context->pipe; + struct ath10k *ar = pipe->ar_usb->ar; + struct sk_buff *skb; + + if (urb->status != 0) { + ath10k_dbg(ar, ATH10K_DBG_USB_BULK, + "pipe: %d, failed:%d\n", + pipe->logical_pipe_num, urb->status); + } + + skb = urb_context->skb; + urb_context->skb = NULL; + ath10k_usb_free_urb_to_pipe(urb_context->pipe, urb_context); + + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, skb); + schedule_work(&pipe->io_complete_work); +} + +/* pipe operations */ +static void ath10k_usb_post_recv_transfers(struct ath10k *ar, + struct ath10k_usb_pipe *recv_pipe) +{ + struct ath10k_urb_context *urb_context; + struct urb *urb; + int usb_status; + + for (;;) { + urb_context = ath10k_usb_alloc_urb_from_pipe(recv_pipe); + if (!urb_context) + break; + + urb_context->skb = dev_alloc_skb(ATH10K_USB_RX_BUFFER_SIZE); + if (!urb_context->skb) + goto err; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + goto err; + + usb_fill_bulk_urb(urb, + recv_pipe->ar_usb->udev, + recv_pipe->usb_pipe_handle, + urb_context->skb->data, + ATH10K_USB_RX_BUFFER_SIZE, + ath10k_usb_recv_complete, urb_context); + + ath10k_dbg(ar, ATH10K_DBG_USB_BULK, + "usb bulk recv submit %d 0x%x ep 0x%2.2x len %d buf 0x%pK\n", + recv_pipe->logical_pipe_num, + recv_pipe->usb_pipe_handle, recv_pipe->ep_address, + ATH10K_USB_RX_BUFFER_SIZE, urb_context->skb); + + usb_anchor_urb(urb, &recv_pipe->urb_submitted); + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + + if (usb_status) { + ath10k_dbg(ar, ATH10K_DBG_USB_BULK, + "usb bulk recv failed: %d\n", + usb_status); + usb_unanchor_urb(urb); + usb_free_urb(urb); + goto err; + } + usb_free_urb(urb); + } + + return; + +err: + ath10k_usb_cleanup_recv_urb(urb_context); +} + +static void ath10k_usb_flush_all(struct ath10k *ar) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + int i; + + for (i = 0; i < ATH10K_USB_PIPE_MAX; i++) { + if (ar_usb->pipes[i].ar_usb) { + usb_kill_anchored_urbs(&ar_usb->pipes[i].urb_submitted); + cancel_work_sync(&ar_usb->pipes[i].io_complete_work); + } + } +} + +static void ath10k_usb_start_recv_pipes(struct ath10k *ar) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + + ar_usb->pipes[ATH10K_USB_PIPE_RX_DATA].urb_cnt_thresh = 1; + + ath10k_usb_post_recv_transfers(ar, + &ar_usb->pipes[ATH10K_USB_PIPE_RX_DATA]); +} + +static void ath10k_usb_tx_complete(struct ath10k *ar, struct sk_buff *skb) +{ + struct ath10k_htc_hdr *htc_hdr; + struct ath10k_htc_ep *ep; + + htc_hdr = (struct ath10k_htc_hdr *)skb->data; + ep = &ar->htc.endpoint[htc_hdr->eid]; + ath10k_htc_notify_tx_completion(ep, skb); + /* The TX complete handler now owns the skb... */ +} + +static void ath10k_usb_rx_complete(struct ath10k *ar, struct sk_buff *skb) +{ + struct ath10k_htc *htc = &ar->htc; + struct ath10k_htc_hdr *htc_hdr; + enum ath10k_htc_ep_id eid; + struct ath10k_htc_ep *ep; + u16 payload_len; + u8 *trailer; + int ret; + + htc_hdr = (struct ath10k_htc_hdr *)skb->data; + eid = eid_from_htc_hdr(htc_hdr); + ep = &ar->htc.endpoint[eid]; + + if (ep->service_id == 0) { + ath10k_warn(ar, "ep %d is not connected\n", eid); + goto out_free_skb; + } + + payload_len = le16_to_cpu(htc_hdr->len); + if (!payload_len) { + ath10k_warn(ar, "zero length frame received, firmware crashed?\n"); + goto out_free_skb; + } + + if (payload_len < htc_hdr->trailer_len) { + ath10k_warn(ar, "malformed frame received, firmware crashed?\n"); + goto out_free_skb; + } + + if (htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT) { + trailer = skb->data + sizeof(*htc_hdr) + payload_len - + htc_hdr->trailer_len; + + ret = ath10k_htc_process_trailer(htc, + trailer, + htc_hdr->trailer_len, + eid, + NULL, + NULL); + if (ret) + goto out_free_skb; + + if (is_trailer_only_msg(htc_hdr)) + goto out_free_skb; + + /* strip off the trailer from the skb since it should not + * be passed on to upper layers + */ + skb_trim(skb, skb->len - htc_hdr->trailer_len); + } + + skb_pull(skb, sizeof(*htc_hdr)); + ep->ep_ops.ep_rx_complete(ar, skb); + /* The RX complete handler now owns the skb... */ + + return; + +out_free_skb: + dev_kfree_skb(skb); +} + +static void ath10k_usb_io_comp_work(struct work_struct *work) +{ + struct ath10k_usb_pipe *pipe = container_of(work, + struct ath10k_usb_pipe, + io_complete_work); + struct ath10k *ar = pipe->ar_usb->ar; + struct sk_buff *skb; + + while ((skb = skb_dequeue(&pipe->io_comp_queue))) { + if (pipe->flags & ATH10K_USB_PIPE_FLAG_TX) + ath10k_usb_tx_complete(ar, skb); + else + ath10k_usb_rx_complete(ar, skb); + } +} + +#define ATH10K_USB_MAX_DIAG_CMD (sizeof(struct ath10k_usb_ctrl_diag_cmd_write)) +#define ATH10K_USB_MAX_DIAG_RESP (sizeof(struct ath10k_usb_ctrl_diag_resp_read)) + +static void ath10k_usb_destroy(struct ath10k *ar) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + + ath10k_usb_flush_all(ar); + ath10k_usb_cleanup_pipe_resources(ar); + usb_set_intfdata(ar_usb->interface, NULL); + + kfree(ar_usb->diag_cmd_buffer); + kfree(ar_usb->diag_resp_buffer); +} + +static int ath10k_usb_hif_start(struct ath10k *ar) +{ + int i; + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + + ath10k_usb_start_recv_pipes(ar); + + /* set the TX resource avail threshold for each TX pipe */ + for (i = ATH10K_USB_PIPE_TX_CTRL; + i <= ATH10K_USB_PIPE_TX_DATA_HP; i++) { + ar_usb->pipes[i].urb_cnt_thresh = + ar_usb->pipes[i].urb_alloc / 2; + } + + return 0; +} + +static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id, + struct ath10k_hif_sg_item *items, int n_items) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + struct ath10k_usb_pipe *pipe = &ar_usb->pipes[pipe_id]; + struct ath10k_urb_context *urb_context; + struct sk_buff *skb; + struct urb *urb; + int ret, i; + + for (i = 0; i < n_items; i++) { + urb_context = ath10k_usb_alloc_urb_from_pipe(pipe); + if (!urb_context) { + ret = -ENOMEM; + goto err; + } + + skb = items[i].transfer_context; + urb_context->skb = skb; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + ret = -ENOMEM; + goto err_free_urb_to_pipe; + } + + usb_fill_bulk_urb(urb, + ar_usb->udev, + pipe->usb_pipe_handle, + skb->data, + skb->len, + ath10k_usb_transmit_complete, urb_context); + + if (!(skb->len % pipe->max_packet_size)) { + /* hit a max packet boundary on this pipe */ + urb->transfer_flags |= URB_ZERO_PACKET; + } + + usb_anchor_urb(urb, &pipe->urb_submitted); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + ath10k_dbg(ar, ATH10K_DBG_USB_BULK, + "usb bulk transmit failed: %d\n", ret); + usb_unanchor_urb(urb); + ret = -EINVAL; + goto err_free_urb_to_pipe; + } + + usb_free_urb(urb); + } + + return 0; + +err_free_urb_to_pipe: + ath10k_usb_free_urb_to_pipe(urb_context->pipe, urb_context); +err: + return ret; +} + +static void ath10k_usb_hif_stop(struct ath10k *ar) +{ + ath10k_usb_flush_all(ar); +} + +static u16 ath10k_usb_hif_get_free_queue_number(struct ath10k *ar, u8 pipe_id) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + + return ar_usb->pipes[pipe_id].urb_cnt; +} + +static int ath10k_usb_submit_ctrl_out(struct ath10k *ar, + u8 req, u16 value, u16 index, void *data, + u32 size) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + u8 *buf = NULL; + int ret; + + if (size > 0) { + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + /* note: if successful returns number of bytes transferred */ + ret = usb_control_msg(ar_usb->udev, + usb_sndctrlpipe(ar_usb->udev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, buf, + size, 1000); + + if (ret < 0) { + ath10k_warn(ar, "Failed to submit usb control message: %d\n", + ret); + kfree(buf); + return ret; + } + + kfree(buf); + + return 0; +} + +static int ath10k_usb_submit_ctrl_in(struct ath10k *ar, + u8 req, u16 value, u16 index, void *data, + u32 size) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + u8 *buf = NULL; + int ret; + + if (size > 0) { + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + + /* note: if successful returns number of bytes transferred */ + ret = usb_control_msg(ar_usb->udev, + usb_rcvctrlpipe(ar_usb->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, buf, + size, 2 * HZ); + + if (ret < 0) { + ath10k_warn(ar, "Failed to read usb control message: %d\n", + ret); + kfree(buf); + return ret; + } + + memcpy((u8 *)data, buf, size); + + kfree(buf); + + return 0; +} + +static int ath10k_usb_ctrl_msg_exchange(struct ath10k *ar, + u8 req_val, u8 *req_buf, u32 req_len, + u8 resp_val, u8 *resp_buf, + u32 *resp_len) +{ + int ret; + + /* send command */ + ret = ath10k_usb_submit_ctrl_out(ar, req_val, 0, 0, + req_buf, req_len); + if (ret) + goto err; + + /* get response */ + if (resp_buf) { + ret = ath10k_usb_submit_ctrl_in(ar, resp_val, 0, 0, + resp_buf, *resp_len); + if (ret) + goto err; + } + + return 0; +err: + return ret; +} + +static int ath10k_usb_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + struct ath10k_usb_ctrl_diag_cmd_read *cmd; + u32 resp_len; + int ret; + + if (buf_len < sizeof(struct ath10k_usb_ctrl_diag_resp_read)) + return -EINVAL; + + cmd = (struct ath10k_usb_ctrl_diag_cmd_read *)ar_usb->diag_cmd_buffer; + memset(cmd, 0, sizeof(*cmd)); + cmd->cmd = ATH10K_USB_CTRL_DIAG_CC_READ; + cmd->address = cpu_to_le32(address); + resp_len = sizeof(struct ath10k_usb_ctrl_diag_resp_read); + + ret = ath10k_usb_ctrl_msg_exchange(ar, + ATH10K_USB_CONTROL_REQ_DIAG_CMD, + (u8 *)cmd, + sizeof(*cmd), + ATH10K_USB_CONTROL_REQ_DIAG_RESP, + ar_usb->diag_resp_buffer, &resp_len); + if (ret) + return ret; + + if (resp_len != sizeof(struct ath10k_usb_ctrl_diag_resp_read)) + return -EMSGSIZE; + + memcpy(buf, ar_usb->diag_resp_buffer, + sizeof(struct ath10k_usb_ctrl_diag_resp_read)); + + return 0; +} + +static int ath10k_usb_hif_diag_write(struct ath10k *ar, u32 address, + const void *data, int nbytes) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + struct ath10k_usb_ctrl_diag_cmd_write *cmd; + int ret; + + if (nbytes != sizeof(cmd->value)) + return -EINVAL; + + cmd = (struct ath10k_usb_ctrl_diag_cmd_write *)ar_usb->diag_cmd_buffer; + memset(cmd, 0, sizeof(*cmd)); + cmd->cmd = cpu_to_le32(ATH10K_USB_CTRL_DIAG_CC_WRITE); + cmd->address = cpu_to_le32(address); + memcpy(&cmd->value, data, nbytes); + + ret = ath10k_usb_ctrl_msg_exchange(ar, + ATH10K_USB_CONTROL_REQ_DIAG_CMD, + (u8 *)cmd, + sizeof(*cmd), + 0, NULL, NULL); + if (ret) + return ret; + + return 0; +} + +static int ath10k_usb_bmi_exchange_msg(struct ath10k *ar, + void *req, u32 req_len, + void *resp, u32 *resp_len) +{ + int ret; + + if (req) { + ret = ath10k_usb_submit_ctrl_out(ar, + ATH10K_USB_CONTROL_REQ_SEND_BMI_CMD, + 0, 0, req, req_len); + if (ret) { + ath10k_warn(ar, + "unable to send the bmi data to the device: %d\n", + ret); + return ret; + } + } + + if (resp) { + ret = ath10k_usb_submit_ctrl_in(ar, + ATH10K_USB_CONTROL_REQ_RECV_BMI_RESP, + 0, 0, resp, *resp_len); + if (ret) { + ath10k_warn(ar, + "Unable to read the bmi data from the device: %d\n", + ret); + return ret; + } + } + + return 0; +} + +static void ath10k_usb_hif_get_default_pipe(struct ath10k *ar, + u8 *ul_pipe, u8 *dl_pipe) +{ + *ul_pipe = ATH10K_USB_PIPE_TX_CTRL; + *dl_pipe = ATH10K_USB_PIPE_RX_CTRL; +} + +static int ath10k_usb_hif_map_service_to_pipe(struct ath10k *ar, u16 svc_id, + u8 *ul_pipe, u8 *dl_pipe) +{ + switch (svc_id) { + case ATH10K_HTC_SVC_ID_RSVD_CTRL: + case ATH10K_HTC_SVC_ID_WMI_CONTROL: + *ul_pipe = ATH10K_USB_PIPE_TX_CTRL; + /* due to large control packets, shift to data pipe */ + *dl_pipe = ATH10K_USB_PIPE_RX_DATA; + break; + case ATH10K_HTC_SVC_ID_HTT_DATA_MSG: + *ul_pipe = ATH10K_USB_PIPE_TX_DATA_LP; + /* Disable rxdata2 directly, it will be enabled + * if FW enable rxdata2 + */ + *dl_pipe = ATH10K_USB_PIPE_RX_DATA; + break; + default: + return -EPERM; + } + + return 0; +} + +/* This op is currently only used by htc_wait_target if the HTC ready + * message times out. It is not applicable for USB since there is nothing + * we can do if the HTC ready message does not arrive in time. + * TODO: Make this op non mandatory by introducing a NULL check in the + * hif op wrapper. + */ +static void ath10k_usb_hif_send_complete_check(struct ath10k *ar, + u8 pipe, int force) +{ +} + +static int ath10k_usb_hif_power_up(struct ath10k *ar) +{ + return 0; +} + +static void ath10k_usb_hif_power_down(struct ath10k *ar) +{ + ath10k_usb_flush_all(ar); +} + +#ifdef CONFIG_PM + +static int ath10k_usb_hif_suspend(struct ath10k *ar) +{ + return -EOPNOTSUPP; +} + +static int ath10k_usb_hif_resume(struct ath10k *ar) +{ + return -EOPNOTSUPP; +} +#endif + +static const struct ath10k_hif_ops ath10k_usb_hif_ops = { + .tx_sg = ath10k_usb_hif_tx_sg, + .diag_read = ath10k_usb_hif_diag_read, + .diag_write = ath10k_usb_hif_diag_write, + .exchange_bmi_msg = ath10k_usb_bmi_exchange_msg, + .start = ath10k_usb_hif_start, + .stop = ath10k_usb_hif_stop, + .map_service_to_pipe = ath10k_usb_hif_map_service_to_pipe, + .get_default_pipe = ath10k_usb_hif_get_default_pipe, + .send_complete_check = ath10k_usb_hif_send_complete_check, + .get_free_queue_number = ath10k_usb_hif_get_free_queue_number, + .power_up = ath10k_usb_hif_power_up, + .power_down = ath10k_usb_hif_power_down, +#ifdef CONFIG_PM + .suspend = ath10k_usb_hif_suspend, + .resume = ath10k_usb_hif_resume, +#endif +}; + +static u8 ath10k_usb_get_logical_pipe_num(u8 ep_address, int *urb_count) +{ + u8 pipe_num = ATH10K_USB_PIPE_INVALID; + + switch (ep_address) { + case ATH10K_USB_EP_ADDR_APP_CTRL_IN: + pipe_num = ATH10K_USB_PIPE_RX_CTRL; + *urb_count = RX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_DATA_IN: + pipe_num = ATH10K_USB_PIPE_RX_DATA; + *urb_count = RX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_INT_IN: + pipe_num = ATH10K_USB_PIPE_RX_INT; + *urb_count = RX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_DATA2_IN: + pipe_num = ATH10K_USB_PIPE_RX_DATA2; + *urb_count = RX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_CTRL_OUT: + pipe_num = ATH10K_USB_PIPE_TX_CTRL; + *urb_count = TX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_DATA_LP_OUT: + pipe_num = ATH10K_USB_PIPE_TX_DATA_LP; + *urb_count = TX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_DATA_MP_OUT: + pipe_num = ATH10K_USB_PIPE_TX_DATA_MP; + *urb_count = TX_URB_COUNT; + break; + case ATH10K_USB_EP_ADDR_APP_DATA_HP_OUT: + pipe_num = ATH10K_USB_PIPE_TX_DATA_HP; + *urb_count = TX_URB_COUNT; + break; + default: + /* note: there may be endpoints not currently used */ + break; + } + + return pipe_num; +} + +static int ath10k_usb_alloc_pipe_resources(struct ath10k *ar, + struct ath10k_usb_pipe *pipe, + int urb_cnt) +{ + struct ath10k_urb_context *urb_context; + int i; + + INIT_LIST_HEAD(&pipe->urb_list_head); + init_usb_anchor(&pipe->urb_submitted); + + for (i = 0; i < urb_cnt; i++) { + urb_context = kzalloc(sizeof(*urb_context), GFP_KERNEL); + if (!urb_context) + return -ENOMEM; + + urb_context->pipe = pipe; + + /* we are only allocate the urb contexts here, the actual URB + * is allocated from the kernel as needed to do a transaction + */ + pipe->urb_alloc++; + ath10k_usb_free_urb_to_pipe(pipe, urb_context); + } + + ath10k_dbg(ar, ATH10K_DBG_USB, + "usb alloc resources lpipe %d hpipe 0x%x urbs %d\n", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->urb_alloc); + + return 0; +} + +static int ath10k_usb_setup_pipe_resources(struct ath10k *ar, + struct usb_interface *interface) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + struct usb_host_interface *iface_desc = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint; + struct ath10k_usb_pipe *pipe; + int ret, i, urbcount; + u8 pipe_num; + + ath10k_dbg(ar, ATH10K_DBG_USB, "usb setting up pipes using interface\n"); + + /* walk decriptors and setup pipes */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (ATH10K_USB_IS_BULK_EP(endpoint->bmAttributes)) { + ath10k_dbg(ar, ATH10K_DBG_USB, + "usb %s bulk ep 0x%2.2x maxpktsz %d\n", + ATH10K_USB_IS_DIR_IN + (endpoint->bEndpointAddress) ? + "rx" : "tx", endpoint->bEndpointAddress, + le16_to_cpu(endpoint->wMaxPacketSize)); + } else if (ATH10K_USB_IS_INT_EP(endpoint->bmAttributes)) { + ath10k_dbg(ar, ATH10K_DBG_USB, + "usb %s int ep 0x%2.2x maxpktsz %d interval %d\n", + ATH10K_USB_IS_DIR_IN + (endpoint->bEndpointAddress) ? + "rx" : "tx", endpoint->bEndpointAddress, + le16_to_cpu(endpoint->wMaxPacketSize), + endpoint->bInterval); + } else if (ATH10K_USB_IS_ISOC_EP(endpoint->bmAttributes)) { + /* TODO for ISO */ + ath10k_dbg(ar, ATH10K_DBG_USB, + "usb %s isoc ep 0x%2.2x maxpktsz %d interval %d\n", + ATH10K_USB_IS_DIR_IN + (endpoint->bEndpointAddress) ? + "rx" : "tx", endpoint->bEndpointAddress, + le16_to_cpu(endpoint->wMaxPacketSize), + endpoint->bInterval); + } + urbcount = 0; + + pipe_num = + ath10k_usb_get_logical_pipe_num(endpoint->bEndpointAddress, + &urbcount); + if (pipe_num == ATH10K_USB_PIPE_INVALID) + continue; + + pipe = &ar_usb->pipes[pipe_num]; + if (pipe->ar_usb) + /* hmmm..pipe was already setup */ + continue; + + pipe->ar_usb = ar_usb; + pipe->logical_pipe_num = pipe_num; + pipe->ep_address = endpoint->bEndpointAddress; + pipe->max_packet_size = le16_to_cpu(endpoint->wMaxPacketSize); + + if (ATH10K_USB_IS_BULK_EP(endpoint->bmAttributes)) { + if (ATH10K_USB_IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvbulkpipe(ar_usb->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndbulkpipe(ar_usb->udev, + pipe->ep_address); + } + } else if (ATH10K_USB_IS_INT_EP(endpoint->bmAttributes)) { + if (ATH10K_USB_IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvintpipe(ar_usb->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndintpipe(ar_usb->udev, + pipe->ep_address); + } + } else if (ATH10K_USB_IS_ISOC_EP(endpoint->bmAttributes)) { + /* TODO for ISO */ + if (ATH10K_USB_IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvisocpipe(ar_usb->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndisocpipe(ar_usb->udev, + pipe->ep_address); + } + } + + pipe->ep_desc = endpoint; + + if (!ATH10K_USB_IS_DIR_IN(pipe->ep_address)) + pipe->flags |= ATH10K_USB_PIPE_FLAG_TX; + + ret = ath10k_usb_alloc_pipe_resources(ar, pipe, urbcount); + if (ret) + return ret; + } + + return 0; +} + +static int ath10k_usb_create(struct ath10k *ar, + struct usb_interface *interface) +{ + struct ath10k_usb *ar_usb = ath10k_usb_priv(ar); + struct usb_device *dev = interface_to_usbdev(interface); + struct ath10k_usb_pipe *pipe; + int ret, i; + + usb_set_intfdata(interface, ar_usb); + spin_lock_init(&ar_usb->cs_lock); + ar_usb->udev = dev; + ar_usb->interface = interface; + + for (i = 0; i < ATH10K_USB_PIPE_MAX; i++) { + pipe = &ar_usb->pipes[i]; + INIT_WORK(&pipe->io_complete_work, + ath10k_usb_io_comp_work); + skb_queue_head_init(&pipe->io_comp_queue); + } + + ar_usb->diag_cmd_buffer = kzalloc(ATH10K_USB_MAX_DIAG_CMD, GFP_KERNEL); + if (!ar_usb->diag_cmd_buffer) { + ret = -ENOMEM; + goto err; + } + + ar_usb->diag_resp_buffer = kzalloc(ATH10K_USB_MAX_DIAG_RESP, + GFP_KERNEL); + if (!ar_usb->diag_resp_buffer) { + ret = -ENOMEM; + goto err; + } + + ret = ath10k_usb_setup_pipe_resources(ar, interface); + if (ret) + goto err; + + return 0; + +err: + ath10k_usb_destroy(ar); + return ret; +} + +/* ath10k usb driver registered functions */ +static int ath10k_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct ath10k *ar; + struct ath10k_usb *ar_usb; + struct usb_device *dev = interface_to_usbdev(interface); + int ret, vendor_id, product_id; + enum ath10k_hw_rev hw_rev; + u32 chip_id; + + /* Assumption: All USB based chipsets (so far) are QCA9377 based. + * If there will be newer chipsets that does not use the hw reg + * setup as defined in qca6174_regs and qca6174_values, this + * assumption is no longer valid and hw_rev must be setup differently + * depending on chipset. + */ + hw_rev = ATH10K_HW_QCA9377; + + ar = ath10k_core_create(sizeof(*ar_usb), &dev->dev, ATH10K_BUS_USB, + hw_rev, &ath10k_usb_hif_ops); + if (!ar) { + dev_err(&dev->dev, "failed to allocate core\n"); + return -ENOMEM; + } + + usb_get_dev(dev); + vendor_id = le16_to_cpu(dev->descriptor.idVendor); + product_id = le16_to_cpu(dev->descriptor.idProduct); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "usb new func vendor 0x%04x product 0x%04x\n", + vendor_id, product_id); + + ar_usb = ath10k_usb_priv(ar); + ret = ath10k_usb_create(ar, interface); + ar_usb->ar = ar; + + ar->dev_id = product_id; + ar->id.vendor = vendor_id; + ar->id.device = product_id; + + /* TODO: don't know yet how to get chip_id with USB */ + chip_id = 0; + ret = ath10k_core_register(ar, chip_id); + if (ret) { + ath10k_warn(ar, "failed to register driver core: %d\n", ret); + goto err; + } + + /* TODO: remove this once USB support is fully implemented */ + ath10k_warn(ar, "WARNING: ath10k USB support is incomplete, don't expect anything to work!\n"); + + return 0; + +err: + ath10k_core_destroy(ar); + + usb_put_dev(dev); + + return ret; +} + +static void ath10k_usb_remove(struct usb_interface *interface) +{ + struct ath10k_usb *ar_usb; + + ar_usb = usb_get_intfdata(interface); + if (!ar_usb) + return; + + ath10k_core_unregister(ar_usb->ar); + ath10k_usb_destroy(ar_usb->ar); + usb_put_dev(interface_to_usbdev(interface)); + ath10k_core_destroy(ar_usb->ar); +} + +#ifdef CONFIG_PM + +static int ath10k_usb_pm_suspend(struct usb_interface *interface, + pm_message_t message) +{ + struct ath10k_usb *ar_usb = usb_get_intfdata(interface); + + ath10k_usb_flush_all(ar_usb->ar); + return 0; +} + +static int ath10k_usb_pm_resume(struct usb_interface *interface) +{ + struct ath10k_usb *ar_usb = usb_get_intfdata(interface); + struct ath10k *ar = ar_usb->ar; + + ath10k_usb_post_recv_transfers(ar, + &ar_usb->pipes[ATH10K_USB_PIPE_RX_DATA]); + + return 0; +} + +#else + +#define ath10k_usb_pm_suspend NULL +#define ath10k_usb_pm_resume NULL + +#endif + +/* table of devices that work with this driver */ +static struct usb_device_id ath10k_usb_ids[] = { + {USB_DEVICE(0x13b1, 0x0042)}, /* Linksys WUSB6100M */ + { /* Terminating entry */ }, +}; + +MODULE_DEVICE_TABLE(usb, ath10k_usb_ids); + +static struct usb_driver ath10k_usb_driver = { + .name = "ath10k_usb", + .probe = ath10k_usb_probe, + .suspend = ath10k_usb_pm_suspend, + .resume = ath10k_usb_pm_resume, + .disconnect = ath10k_usb_remove, + .id_table = ath10k_usb_ids, + .supports_autosuspend = true, + .disable_hub_initiated_lpm = 1, +}; + +module_usb_driver(ath10k_usb_driver); + +MODULE_AUTHOR("Atheros Communications, Inc."); +MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN USB devices"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/ath/ath10k/usb.h b/drivers/net/wireless/ath/ath10k/usb.h new file mode 100644 index 000000000000..f60a3cc7d712 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/usb.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2004-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros, Inc. + * Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _USB_H_ +#define _USB_H_ + +/* constants */ +#define TX_URB_COUNT 32 +#define RX_URB_COUNT 32 +#define ATH10K_USB_RX_BUFFER_SIZE 4096 + +#define ATH10K_USB_PIPE_INVALID ATH10K_USB_PIPE_MAX + +/* USB endpoint definitions */ +#define ATH10K_USB_EP_ADDR_APP_CTRL_IN 0x81 +#define ATH10K_USB_EP_ADDR_APP_DATA_IN 0x82 +#define ATH10K_USB_EP_ADDR_APP_DATA2_IN 0x83 +#define ATH10K_USB_EP_ADDR_APP_INT_IN 0x84 + +#define ATH10K_USB_EP_ADDR_APP_CTRL_OUT 0x01 +#define ATH10K_USB_EP_ADDR_APP_DATA_LP_OUT 0x02 +#define ATH10K_USB_EP_ADDR_APP_DATA_MP_OUT 0x03 +#define ATH10K_USB_EP_ADDR_APP_DATA_HP_OUT 0x04 + +/* diagnostic command defnitions */ +#define ATH10K_USB_CONTROL_REQ_SEND_BMI_CMD 1 +#define ATH10K_USB_CONTROL_REQ_RECV_BMI_RESP 2 +#define ATH10K_USB_CONTROL_REQ_DIAG_CMD 3 +#define ATH10K_USB_CONTROL_REQ_DIAG_RESP 4 + +#define ATH10K_USB_CTRL_DIAG_CC_READ 0 +#define ATH10K_USB_CTRL_DIAG_CC_WRITE 1 + +#define ATH10K_USB_IS_BULK_EP(attr) (((attr) & 3) == 0x02) +#define ATH10K_USB_IS_INT_EP(attr) (((attr) & 3) == 0x03) +#define ATH10K_USB_IS_ISOC_EP(attr) (((attr) & 3) == 0x01) +#define ATH10K_USB_IS_DIR_IN(addr) ((addr) & 0x80) + +struct ath10k_usb_ctrl_diag_cmd_write { + __le32 cmd; + __le32 address; + __le32 value; + __le32 padding; +} __packed; + +struct ath10k_usb_ctrl_diag_cmd_read { + __le32 cmd; + __le32 address; +} __packed; + +struct ath10k_usb_ctrl_diag_resp_read { + u8 value[4]; +} __packed; + +/* tx/rx pipes for usb */ +enum ath10k_usb_pipe_id { + ATH10K_USB_PIPE_TX_CTRL = 0, + ATH10K_USB_PIPE_TX_DATA_LP, + ATH10K_USB_PIPE_TX_DATA_MP, + ATH10K_USB_PIPE_TX_DATA_HP, + ATH10K_USB_PIPE_RX_CTRL, + ATH10K_USB_PIPE_RX_DATA, + ATH10K_USB_PIPE_RX_DATA2, + ATH10K_USB_PIPE_RX_INT, + ATH10K_USB_PIPE_MAX +}; + +struct ath10k_usb_pipe { + struct list_head urb_list_head; + struct usb_anchor urb_submitted; + u32 urb_alloc; + u32 urb_cnt; + u32 urb_cnt_thresh; + unsigned int usb_pipe_handle; + u32 flags; + u8 ep_address; + u8 logical_pipe_num; + struct ath10k_usb *ar_usb; + u16 max_packet_size; + struct work_struct io_complete_work; + struct sk_buff_head io_comp_queue; + struct usb_endpoint_descriptor *ep_desc; +}; + +#define ATH10K_USB_PIPE_FLAG_TX BIT(0) + +/* usb device object */ +struct ath10k_usb { + /* protects pipe->urb_list_head and pipe->urb_cnt */ + spinlock_t cs_lock; + + struct usb_device *udev; + struct usb_interface *interface; + struct ath10k_usb_pipe pipes[ATH10K_USB_PIPE_MAX]; + u8 *diag_cmd_buffer; + u8 *diag_resp_buffer; + struct ath10k *ar; +}; + +/* usb urb object */ +struct ath10k_urb_context { + struct list_head link; + struct ath10k_usb_pipe *pipe; + struct sk_buff *skb; + struct ath10k *ar; +}; + +static inline struct ath10k_usb *ath10k_usb_priv(struct ath10k *ar) +{ + return (struct ath10k_usb *)ar->drv_priv; +} + +#endif diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3efb404b83c0..38a97086708b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -651,8 +651,6 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .gpio_output_cmdid = WMI_10_4_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, .vdev_set_wmm_params_cmdid = WMI_CMD_UNSUPPORTED, - .tdls_set_state_cmdid = WMI_CMD_UNSUPPORTED, - .tdls_peer_update_cmdid = WMI_CMD_UNSUPPORTED, .adaptive_qcs_cmdid = WMI_CMD_UNSUPPORTED, .scan_update_request_cmdid = WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, .vdev_standby_response_cmdid = WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, @@ -711,6 +709,33 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .pdev_bss_chan_info_request_cmdid = WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, .ext_resource_cfg_cmdid = WMI_10_4_EXT_RESOURCE_CFG_CMDID, + .vdev_set_ie_cmdid = WMI_10_4_VDEV_SET_IE_CMDID, + .set_lteu_config_cmdid = WMI_10_4_SET_LTEU_CONFIG_CMDID, + .atf_ssid_grouping_request_cmdid = + WMI_10_4_ATF_SSID_GROUPING_REQUEST_CMDID, + .peer_atf_ext_request_cmdid = WMI_10_4_PEER_ATF_EXT_REQUEST_CMDID, + .set_periodic_channel_stats_cfg_cmdid = + WMI_10_4_SET_PERIODIC_CHANNEL_STATS_CONFIG, + .peer_bwf_request_cmdid = WMI_10_4_PEER_BWF_REQUEST_CMDID, + .btcoex_cfg_cmdid = WMI_10_4_BTCOEX_CFG_CMDID, + .peer_tx_mu_txmit_count_cmdid = WMI_10_4_PEER_TX_MU_TXMIT_COUNT_CMDID, + .peer_tx_mu_txmit_rstcnt_cmdid = WMI_10_4_PEER_TX_MU_TXMIT_RSTCNT_CMDID, + .peer_gid_userpos_list_cmdid = WMI_10_4_PEER_GID_USERPOS_LIST_CMDID, + .pdev_check_cal_version_cmdid = WMI_10_4_PDEV_CHECK_CAL_VERSION_CMDID, + .coex_version_cfg_cmid = WMI_10_4_COEX_VERSION_CFG_CMID, + .pdev_get_rx_filter_cmdid = WMI_10_4_PDEV_GET_RX_FILTER_CMDID, + .pdev_extended_nss_cfg_cmdid = WMI_10_4_PDEV_EXTENDED_NSS_CFG_CMDID, + .vdev_set_scan_nac_rssi_cmdid = WMI_10_4_VDEV_SET_SCAN_NAC_RSSI_CMDID, + .prog_gpio_band_select_cmdid = WMI_10_4_PROG_GPIO_BAND_SELECT_CMDID, + .config_smart_logging_cmdid = WMI_10_4_CONFIG_SMART_LOGGING_CMDID, + .debug_fatal_condition_cmdid = WMI_10_4_DEBUG_FATAL_CONDITION_CMDID, + .get_tsf_timer_cmdid = WMI_10_4_GET_TSF_TIMER_CMDID, + .pdev_get_tpc_table_cmdid = WMI_10_4_PDEV_GET_TPC_TABLE_CMDID, + .vdev_sifs_trigger_time_cmdid = WMI_10_4_VDEV_SIFS_TRIGGER_TIME_CMDID, + .pdev_wds_entry_list_cmdid = WMI_10_4_PDEV_WDS_ENTRY_LIST_CMDID, + .tdls_set_state_cmdid = WMI_10_4_TDLS_SET_STATE_CMDID, + .tdls_peer_update_cmdid = WMI_10_4_TDLS_PEER_UPDATE_CMDID, + .tdls_set_offchan_mode_cmdid = WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID, }; /* MAIN WMI VDEV param map */ @@ -3305,7 +3330,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif, if (arvif->u.ap.noa_data) if (!pskb_expand_head(bcn, 0, arvif->u.ap.noa_len, GFP_ATOMIC)) skb_put_data(bcn, arvif->u.ap.noa_data, - arvif->u.ap.noa_len); + arvif->u.ap.noa_len); } static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, @@ -6473,6 +6498,7 @@ ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id, cmd = (struct wmi_peer_create_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(vdev_id); ether_addr_copy(cmd->peer_macaddr.addr, peer_addr); + cmd->peer_type = __cpu_to_le32(peer_type); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi peer create vdev_id %d peer_addr %pM\n", @@ -7803,14 +7829,28 @@ ath10k_wmi_10_4_ext_resource_config(struct ath10k *ar, { struct wmi_ext_resource_config_10_4_cmd *cmd; struct sk_buff *skb; + u32 num_tdls_sleep_sta = 0; skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); if (!skb) return ERR_PTR(-ENOMEM); + if (test_bit(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, ar->wmi.svc_map)) + num_tdls_sleep_sta = TARGET_10_4_NUM_TDLS_SLEEP_STA; + cmd = (struct wmi_ext_resource_config_10_4_cmd *)skb->data; cmd->host_platform_config = __cpu_to_le32(type); cmd->fw_feature_bitmap = __cpu_to_le32(fw_feature_bitmap); + cmd->wlan_gpio_priority = __cpu_to_le32(-1); + cmd->coex_version = __cpu_to_le32(WMI_NO_COEX_VERSION_SUPPORT); + cmd->coex_gpio_pin1 = __cpu_to_le32(-1); + cmd->coex_gpio_pin2 = __cpu_to_le32(-1); + cmd->coex_gpio_pin3 = __cpu_to_le32(-1); + cmd->num_tdls_vdevs = __cpu_to_le32(TARGET_10_4_NUM_TDLS_VDEVS); + cmd->num_tdls_conn_table_entries = __cpu_to_le32(20); + cmd->max_tdls_concurrent_sleep_sta = __cpu_to_le32(num_tdls_sleep_sta); + cmd->max_tdls_concurrent_buffer_sta = + __cpu_to_le32(TARGET_10_4_NUM_TDLS_BUFFER_STA); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi ext resource config host type %d firmware feature bitmap %08x\n", @@ -7819,6 +7859,124 @@ ath10k_wmi_10_4_ext_resource_config(struct ath10k *ar, } static struct sk_buff * +ath10k_wmi_10_4_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id, + enum wmi_tdls_state state) +{ + struct wmi_10_4_tdls_set_state_cmd *cmd; + struct sk_buff *skb; + u32 options = 0; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + if (test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, ar->wmi.svc_map)) + state = WMI_TDLS_ENABLE_PASSIVE; + + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) + options |= WMI_TDLS_BUFFER_STA_EN; + + cmd = (struct wmi_10_4_tdls_set_state_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(vdev_id); + cmd->state = __cpu_to_le32(state); + cmd->notification_interval_ms = __cpu_to_le32(5000); + cmd->tx_discovery_threshold = __cpu_to_le32(100); + cmd->tx_teardown_threshold = __cpu_to_le32(5); + cmd->rssi_teardown_threshold = __cpu_to_le32(-75); + cmd->rssi_delta = __cpu_to_le32(-20); + cmd->tdls_options = __cpu_to_le32(options); + cmd->tdls_peer_traffic_ind_window = __cpu_to_le32(2); + cmd->tdls_peer_traffic_response_timeout_ms = __cpu_to_le32(5000); + cmd->tdls_puapsd_mask = __cpu_to_le32(0xf); + cmd->tdls_puapsd_inactivity_time_ms = __cpu_to_le32(0); + cmd->tdls_puapsd_rx_frame_threshold = __cpu_to_le32(10); + cmd->teardown_notification_ms = __cpu_to_le32(10); + cmd->tdls_peer_kickout_threshold = __cpu_to_le32(96); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi update fw tdls state %d for vdev %i\n", + state, vdev_id); + return skb; +} + +static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp) +{ + u32 peer_qos = 0; + + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + peer_qos |= WMI_TDLS_PEER_QOS_AC_VO; + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) + peer_qos |= WMI_TDLS_PEER_QOS_AC_VI; + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) + peer_qos |= WMI_TDLS_PEER_QOS_AC_BK; + if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) + peer_qos |= WMI_TDLS_PEER_QOS_AC_BE; + + peer_qos |= SM(sp, WMI_TDLS_PEER_SP); + + return peer_qos; +} + +static struct sk_buff * +ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, + const struct wmi_tdls_peer_update_cmd_arg *arg, + const struct wmi_tdls_peer_capab_arg *cap, + const struct wmi_channel_arg *chan_arg) +{ + struct wmi_10_4_tdls_peer_update_cmd *cmd; + struct wmi_tdls_peer_capabilities *peer_cap; + struct wmi_channel *chan; + struct sk_buff *skb; + u32 peer_qos; + int len, chan_len; + int i; + + /* tdls peer update cmd has place holder for one channel*/ + chan_len = cap->peer_chan_len ? (cap->peer_chan_len - 1) : 0; + + len = sizeof(*cmd) + chan_len * sizeof(*chan); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return ERR_PTR(-ENOMEM); + + memset(skb->data, 0, sizeof(*cmd)); + + cmd = (struct wmi_10_4_tdls_peer_update_cmd *)skb->data; + cmd->vdev_id = __cpu_to_le32(arg->vdev_id); + ether_addr_copy(cmd->peer_macaddr.addr, arg->addr); + cmd->peer_state = __cpu_to_le32(arg->peer_state); + + peer_qos = ath10k_wmi_prepare_peer_qos(cap->peer_uapsd_queues, + cap->peer_max_sp); + + peer_cap = &cmd->peer_capab; + peer_cap->peer_qos = __cpu_to_le32(peer_qos); + peer_cap->buff_sta_support = __cpu_to_le32(cap->buff_sta_support); + peer_cap->off_chan_support = __cpu_to_le32(cap->off_chan_support); + peer_cap->peer_curr_operclass = __cpu_to_le32(cap->peer_curr_operclass); + peer_cap->self_curr_operclass = __cpu_to_le32(cap->self_curr_operclass); + peer_cap->peer_chan_len = __cpu_to_le32(cap->peer_chan_len); + peer_cap->peer_operclass_len = __cpu_to_le32(cap->peer_operclass_len); + + for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++) + peer_cap->peer_operclass[i] = cap->peer_operclass[i]; + + peer_cap->is_peer_responder = __cpu_to_le32(cap->is_peer_responder); + peer_cap->pref_offchan_num = __cpu_to_le32(cap->pref_offchan_num); + peer_cap->pref_offchan_bw = __cpu_to_le32(cap->pref_offchan_bw); + + for (i = 0; i < cap->peer_chan_len; i++) { + chan = (struct wmi_channel *)&peer_cap->peer_chan_list[i]; + ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]); + } + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi tdls peer update vdev %i state %d n_chans %u\n", + arg->vdev_id, arg->peer_state, cap->peer_chan_len); + return skb; +} + +static struct sk_buff * ath10k_wmi_op_gen_echo(struct ath10k *ar, u32 value) { struct wmi_echo_cmd *cmd; @@ -8197,6 +8355,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_delba_send = ath10k_wmi_op_gen_delba_send, .fw_stats_fill = ath10k_wmi_10_4_op_fw_stats_fill, .ext_resource_config = ath10k_wmi_10_4_ext_resource_config, + .gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state, + .gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update, /* shared with 10.2 */ .pull_echo_ev = ath10k_wmi_op_pull_echo_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index baa38c8f847c..7a3606dde227 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -184,6 +184,17 @@ enum wmi_service { WMI_SERVICE_TX_MODE_PUSH_ONLY, WMI_SERVICE_TX_MODE_PUSH_PULL, WMI_SERVICE_TX_MODE_DYNAMIC, + WMI_SERVICE_VDEV_RX_FILTER, + WMI_SERVICE_BTCOEX, + WMI_SERVICE_CHECK_CAL_VERSION, + WMI_SERVICE_DBGLOG_WARN2, + WMI_SERVICE_BTCOEX_DUTY_CYCLE, + WMI_SERVICE_4_WIRE_COEX_SUPPORT, + WMI_SERVICE_EXTENDED_NSS_SUPPORT, + WMI_SERVICE_PROG_GPIO_BAND_SELECT, + WMI_SERVICE_SMART_LOGGING_SUPPORT, + WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, + WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, /* keep last */ WMI_SERVICE_MAX, @@ -310,6 +321,21 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_TX_MODE_PUSH_ONLY, WMI_10_4_SERVICE_TX_MODE_PUSH_PULL, WMI_10_4_SERVICE_TX_MODE_DYNAMIC, + WMI_10_4_SERVICE_VDEV_RX_FILTER, + WMI_10_4_SERVICE_BTCOEX, + WMI_10_4_SERVICE_CHECK_CAL_VERSION, + WMI_10_4_SERVICE_DBGLOG_WARN2, + WMI_10_4_SERVICE_BTCOEX_DUTY_CYCLE, + WMI_10_4_SERVICE_4_WIRE_COEX_SUPPORT, + WMI_10_4_SERVICE_EXTENDED_NSS_SUPPORT, + WMI_10_4_SERVICE_PROG_GPIO_BAND_SELECT, + WMI_10_4_SERVICE_SMART_LOGGING_SUPPORT, + WMI_10_4_SERVICE_TDLS, + WMI_10_4_SERVICE_TDLS_OFFCHAN, + WMI_10_4_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_10_4_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, + WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, }; static inline char *wmi_service_name(int service_id) @@ -408,6 +434,16 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_TX_MODE_PUSH_ONLY); SVCSTR(WMI_SERVICE_TX_MODE_PUSH_PULL); SVCSTR(WMI_SERVICE_TX_MODE_DYNAMIC); + SVCSTR(WMI_SERVICE_VDEV_RX_FILTER); + SVCSTR(WMI_SERVICE_CHECK_CAL_VERSION); + SVCSTR(WMI_SERVICE_DBGLOG_WARN2); + SVCSTR(WMI_SERVICE_BTCOEX_DUTY_CYCLE); + SVCSTR(WMI_SERVICE_4_WIRE_COEX_SUPPORT); + SVCSTR(WMI_SERVICE_EXTENDED_NSS_SUPPORT); + SVCSTR(WMI_SERVICE_PROG_GPIO_BAND_SELECT); + SVCSTR(WMI_SERVICE_SMART_LOGGING_SUPPORT); + SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE); + SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); default: return NULL; } @@ -420,9 +456,20 @@ static inline char *wmi_service_name(int service_id) __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \ BIT((svc_id) % (sizeof(u32)))) +/* This extension is required to accommodate new services, current limit + * for wmi_services is 64 as target is using only 4-bits of each 32-bit + * wmi_service word. Extending this to make use of remaining unused bits + * for new services. + */ +#define WMI_EXT_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \ + ((svc_id) >= (len) && \ + __le32_to_cpu((wmi_svc_bmap)[((svc_id) - (len)) / 28]) & \ + BIT(((((svc_id) - (len)) % 28) & 0x1f) + 4)) + #define SVCMAP(x, y, len) \ do { \ - if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \ + if ((WMI_SERVICE_IS_ENABLED((in), (x), (len))) || \ + (WMI_EXT_SERVICE_IS_ENABLED((in), (x), (len)))) \ __set_bit(y, out); \ } while (0) @@ -663,6 +710,36 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TX_MODE_PUSH_PULL, len); SVCMAP(WMI_10_4_SERVICE_TX_MODE_DYNAMIC, WMI_SERVICE_TX_MODE_DYNAMIC, len); + SVCMAP(WMI_10_4_SERVICE_VDEV_RX_FILTER, + WMI_SERVICE_VDEV_RX_FILTER, len); + SVCMAP(WMI_10_4_SERVICE_BTCOEX, + WMI_SERVICE_BTCOEX, len); + SVCMAP(WMI_10_4_SERVICE_CHECK_CAL_VERSION, + WMI_SERVICE_CHECK_CAL_VERSION, len); + SVCMAP(WMI_10_4_SERVICE_DBGLOG_WARN2, + WMI_SERVICE_DBGLOG_WARN2, len); + SVCMAP(WMI_10_4_SERVICE_BTCOEX_DUTY_CYCLE, + WMI_SERVICE_BTCOEX_DUTY_CYCLE, len); + SVCMAP(WMI_10_4_SERVICE_4_WIRE_COEX_SUPPORT, + WMI_SERVICE_4_WIRE_COEX_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_EXTENDED_NSS_SUPPORT, + WMI_SERVICE_EXTENDED_NSS_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_PROG_GPIO_BAND_SELECT, + WMI_SERVICE_PROG_GPIO_BAND_SELECT, len); + SVCMAP(WMI_10_4_SERVICE_SMART_LOGGING_SUPPORT, + WMI_SERVICE_SMART_LOGGING_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_TDLS, + WMI_SERVICE_TDLS, len); + SVCMAP(WMI_10_4_SERVICE_TDLS_OFFCHAN, + WMI_SERVICE_TDLS_OFFCHAN, len); + SVCMAP(WMI_10_4_SERVICE_TDLS_UAPSD_BUFFER_STA, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len); + SVCMAP(WMI_10_4_SERVICE_TDLS_UAPSD_SLEEP_STA, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len); + SVCMAP(WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, + WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, len); + SVCMAP(WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, + WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len); } #undef SVCMAP @@ -837,6 +914,29 @@ struct wmi_cmd_map { u32 pdev_bss_chan_info_request_cmdid; u32 pdev_enable_adaptive_cca_cmdid; u32 ext_resource_cfg_cmdid; + u32 vdev_set_ie_cmdid; + u32 set_lteu_config_cmdid; + u32 atf_ssid_grouping_request_cmdid; + u32 peer_atf_ext_request_cmdid; + u32 set_periodic_channel_stats_cfg_cmdid; + u32 peer_bwf_request_cmdid; + u32 btcoex_cfg_cmdid; + u32 peer_tx_mu_txmit_count_cmdid; + u32 peer_tx_mu_txmit_rstcnt_cmdid; + u32 peer_gid_userpos_list_cmdid; + u32 pdev_check_cal_version_cmdid; + u32 coex_version_cfg_cmid; + u32 pdev_get_rx_filter_cmdid; + u32 pdev_extended_nss_cfg_cmdid; + u32 vdev_set_scan_nac_rssi_cmdid; + u32 prog_gpio_band_select_cmdid; + u32 config_smart_logging_cmdid; + u32 debug_fatal_condition_cmdid; + u32 get_tsf_timer_cmdid; + u32 pdev_get_tpc_table_cmdid; + u32 vdev_sifs_trigger_time_cmdid; + u32 pdev_wds_entry_list_cmdid; + u32 tdls_set_offchan_mode_cmdid; }; /* @@ -1647,6 +1747,29 @@ enum wmi_10_4_cmd_id { WMI_10_4_EXT_RESOURCE_CFG_CMDID, WMI_10_4_VDEV_SET_IE_CMDID, WMI_10_4_SET_LTEU_CONFIG_CMDID, + WMI_10_4_ATF_SSID_GROUPING_REQUEST_CMDID, + WMI_10_4_PEER_ATF_EXT_REQUEST_CMDID, + WMI_10_4_SET_PERIODIC_CHANNEL_STATS_CONFIG, + WMI_10_4_PEER_BWF_REQUEST_CMDID, + WMI_10_4_BTCOEX_CFG_CMDID, + WMI_10_4_PEER_TX_MU_TXMIT_COUNT_CMDID, + WMI_10_4_PEER_TX_MU_TXMIT_RSTCNT_CMDID, + WMI_10_4_PEER_GID_USERPOS_LIST_CMDID, + WMI_10_4_PDEV_CHECK_CAL_VERSION_CMDID, + WMI_10_4_COEX_VERSION_CFG_CMID, + WMI_10_4_PDEV_GET_RX_FILTER_CMDID, + WMI_10_4_PDEV_EXTENDED_NSS_CFG_CMDID, + WMI_10_4_VDEV_SET_SCAN_NAC_RSSI_CMDID, + WMI_10_4_PROG_GPIO_BAND_SELECT_CMDID, + WMI_10_4_CONFIG_SMART_LOGGING_CMDID, + WMI_10_4_DEBUG_FATAL_CONDITION_CMDID, + WMI_10_4_GET_TSF_TIMER_CMDID, + WMI_10_4_PDEV_GET_TPC_TABLE_CMDID, + WMI_10_4_VDEV_SIFS_TRIGGER_TIME_CMDID, + WMI_10_4_PDEV_WDS_ENTRY_LIST_CMDID, + WMI_10_4_TDLS_SET_STATE_CMDID, + WMI_10_4_TDLS_PEER_UPDATE_CMDID, + WMI_10_4_TDLS_SET_OFFCHAN_MODE_CMDID, WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, }; @@ -1710,6 +1833,18 @@ enum wmi_10_4_event_id { WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID, WMI_10_4_MU_REPORT_EVENTID, + WMI_10_4_TX_DATA_TRAFFIC_CTRL_EVENTID, + WMI_10_4_PEER_TX_MU_TXMIT_COUNT_EVENTID, + WMI_10_4_PEER_GID_USERPOS_LIST_EVENTID, + WMI_10_4_PDEV_CHECK_CAL_VERSION_EVENTID, + WMI_10_4_ATF_PEER_STATS_EVENTID, + WMI_10_4_PDEV_GET_RX_FILTER_EVENTID, + WMI_10_4_NAC_RSSI_EVENTID, + WMI_10_4_DEBUG_FATAL_CONDITION_EVENTID, + WMI_10_4_GET_TSF_TIMER_RESP_EVENTID, + WMI_10_4_PDEV_TPC_TABLE_EVENTID, + WMI_10_4_PDEV_WDS_ENTRY_LIST_EVENTID, + WMI_10_4_TDLS_PEER_EVENTID, WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1, }; @@ -2718,6 +2853,18 @@ struct wmi_resource_config_10_4 { __le32 qwrap_config; } __packed; +enum wmi_coex_version { + WMI_NO_COEX_VERSION_SUPPORT = 0, + /* 3 wire coex support*/ + WMI_COEX_VERSION_1 = 1, + /* 2.5 wire coex support*/ + WMI_COEX_VERSION_2 = 2, + /* 2.5 wire coex with duty cycle support */ + WMI_COEX_VERSION_3 = 3, + /* 4 wire coex support*/ + WMI_COEX_VERSION_4 = 4, +}; + /** * enum wmi_10_4_feature_mask - WMI 10.4 feature enable/disable flags * @WMI_10_4_LTEU_SUPPORT: LTEU config @@ -2726,6 +2873,14 @@ struct wmi_resource_config_10_4 { * @WMI_10_4_AUX_RADIO_CHAN_LOAD_INTF: AUX Radio Enhancement for chan load scan * @WMI_10_4_BSS_CHANNEL_INFO_64: BSS channel info stats * @WMI_10_4_PEER_STATS: Per station stats + * @WMI_10_4_VDEV_STATS: Per vdev stats + * @WMI_10_4_TDLS: Implicit TDLS support in firmware enable/disable + * @WMI_10_4_TDLS_OFFCHAN: TDLS offchannel support enable/disable + * @WMI_10_4_TDLS_UAPSD_BUFFER_STA: TDLS buffer sta support enable/disable + * @WMI_10_4_TDLS_UAPSD_SLEEP_STA: TDLS sleep sta support enable/disable + * @WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE: TDLS connection tracker in host + * enable/disable + * @WMI_10_4_TDLS_EXPLICIT_MODE_ONLY:Explicit TDLS mode enable/disable */ enum wmi_10_4_feature_mask { WMI_10_4_LTEU_SUPPORT = BIT(0), @@ -2734,6 +2889,14 @@ enum wmi_10_4_feature_mask { WMI_10_4_AUX_RADIO_CHAN_LOAD_INTF = BIT(3), WMI_10_4_BSS_CHANNEL_INFO_64 = BIT(4), WMI_10_4_PEER_STATS = BIT(5), + WMI_10_4_VDEV_STATS = BIT(6), + WMI_10_4_TDLS = BIT(7), + WMI_10_4_TDLS_OFFCHAN = BIT(8), + WMI_10_4_TDLS_UAPSD_BUFFER_STA = BIT(9), + WMI_10_4_TDLS_UAPSD_SLEEP_STA = BIT(10), + WMI_10_4_TDLS_CONN_TRACKER_IN_HOST_MODE = BIT(11), + WMI_10_4_TDLS_EXPLICIT_MODE_ONLY = BIT(12), + }; struct wmi_ext_resource_config_10_4_cmd { @@ -2741,6 +2904,22 @@ struct wmi_ext_resource_config_10_4_cmd { __le32 host_platform_config; /* see enum wmi_10_4_feature_mask */ __le32 fw_feature_bitmap; + /* WLAN priority GPIO number */ + __le32 wlan_gpio_priority; + /* see enum wmi_coex_version */ + __le32 coex_version; + /* COEX GPIO config */ + __le32 coex_gpio_pin1; + __le32 coex_gpio_pin2; + __le32 coex_gpio_pin3; + /* number of vdevs allowed to perform tdls */ + __le32 num_tdls_vdevs; + /* number of peers to track per TDLS vdev */ + __le32 num_tdls_conn_table_entries; + /* number of tdls sleep sta supported */ + __le32 max_tdls_concurrent_sleep_sta; + /* number of tdls buffer sta supported */ + __le32 max_tdls_concurrent_buffer_sta; }; /* strucutre describing host memory chunk. */ @@ -5698,6 +5877,7 @@ struct wmi_tbtt_offset_event { struct wmi_peer_create_cmd { __le32 vdev_id; struct wmi_mac_addr peer_macaddr; + __le32 peer_type; } __packed; enum wmi_peer_type { @@ -6556,6 +6736,22 @@ struct wmi_tdls_peer_update_cmd_arg { #define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32 +#define WMI_TDLS_PEER_SP_MASK 0x60 +#define WMI_TDLS_PEER_SP_LSB 5 + +enum wmi_tdls_options { + WMI_TDLS_OFFCHAN_EN = BIT(0), + WMI_TDLS_BUFFER_STA_EN = BIT(1), + WMI_TDLS_SLEEP_STA_EN = BIT(2), +}; + +enum { + WMI_TDLS_PEER_QOS_AC_VO = BIT(0), + WMI_TDLS_PEER_QOS_AC_VI = BIT(1), + WMI_TDLS_PEER_QOS_AC_BK = BIT(2), + WMI_TDLS_PEER_QOS_AC_BE = BIT(3), +}; + struct wmi_tdls_peer_capab_arg { u8 peer_uapsd_queues; u8 peer_max_sp; @@ -6571,6 +6767,79 @@ struct wmi_tdls_peer_capab_arg { u32 pref_offchan_bw; }; +struct wmi_10_4_tdls_set_state_cmd { + __le32 vdev_id; + __le32 state; + __le32 notification_interval_ms; + __le32 tx_discovery_threshold; + __le32 tx_teardown_threshold; + __le32 rssi_teardown_threshold; + __le32 rssi_delta; + __le32 tdls_options; + __le32 tdls_peer_traffic_ind_window; + __le32 tdls_peer_traffic_response_timeout_ms; + __le32 tdls_puapsd_mask; + __le32 tdls_puapsd_inactivity_time_ms; + __le32 tdls_puapsd_rx_frame_threshold; + __le32 teardown_notification_ms; + __le32 tdls_peer_kickout_threshold; +} __packed; + +struct wmi_tdls_peer_capabilities { + __le32 peer_qos; + __le32 buff_sta_support; + __le32 off_chan_support; + __le32 peer_curr_operclass; + __le32 self_curr_operclass; + __le32 peer_chan_len; + __le32 peer_operclass_len; + u8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES]; + __le32 is_peer_responder; + __le32 pref_offchan_num; + __le32 pref_offchan_bw; + struct wmi_channel peer_chan_list[1]; +} __packed; + +struct wmi_10_4_tdls_peer_update_cmd { + __le32 vdev_id; + struct wmi_mac_addr peer_macaddr; + __le32 peer_state; + __le32 reserved[4]; + struct wmi_tdls_peer_capabilities peer_capab; +} __packed; + +enum wmi_tdls_peer_reason { + WMI_TDLS_TEARDOWN_REASON_TX, + WMI_TDLS_TEARDOWN_REASON_RSSI, + WMI_TDLS_TEARDOWN_REASON_SCAN, + WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE, + WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT, + WMI_TDLS_TEARDOWN_REASON_BAD_PTR, + WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE, + WMI_TDLS_ENTER_BUF_STA, + WMI_TDLS_EXIT_BUF_STA, + WMI_TDLS_ENTER_BT_BUSY_MODE, + WMI_TDLS_EXIT_BT_BUSY_MODE, + WMI_TDLS_SCAN_STARTED_EVENT, + WMI_TDLS_SCAN_COMPLETED_EVENT, +}; + +enum wmi_tdls_peer_notification { + WMI_TDLS_SHOULD_DISCOVER, + WMI_TDLS_SHOULD_TEARDOWN, + WMI_TDLS_PEER_DISCONNECTED, + WMI_TDLS_CONNECTION_TRACKER_NOTIFICATION, +}; + +struct wmi_tdls_peer_event { + struct wmi_mac_addr peer_macaddr; + /* see enum wmi_tdls_peer_notification*/ + __le32 peer_status; + /* see enum wmi_tdls_peer_reason */ + __le32 peer_reason; + __le32 vdev_id; +} __packed; + enum wmi_txbf_conf { WMI_TXBF_CONF_UNSUPPORTED, WMI_TXBF_CONF_BEFORE_ASSOC, diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c index 77100d42f401..0d46d6dc7578 100644 --- a/drivers/net/wireless/ath/ath10k/wow.c +++ b/drivers/net/wireless/ath/ath10k/wow.c @@ -277,6 +277,18 @@ exit: return ret ? 1 : 0; } +void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath10k *ar = hw->priv; + + mutex_lock(&ar->conf_mutex); + if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, + ar->running_fw->fw_file.fw_features)) { + device_set_wakeup_enable(ar->dev, enabled); + } + mutex_unlock(&ar->conf_mutex); +} + int ath10k_wow_op_resume(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; @@ -336,5 +348,7 @@ int ath10k_wow_init(struct ath10k *ar) ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns; ar->hw->wiphy->wowlan = &ar->wow.wowlan_support; + device_set_wakeup_capable(ar->dev, true); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wow.h b/drivers/net/wireless/ath/ath10k/wow.h index abbb04b6d1bd..9745b9ddc7f5 100644 --- a/drivers/net/wireless/ath/ath10k/wow.h +++ b/drivers/net/wireless/ath/ath10k/wow.h @@ -28,6 +28,7 @@ int ath10k_wow_init(struct ath10k *ar); int ath10k_wow_op_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int ath10k_wow_op_resume(struct ieee80211_hw *hw); +void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled); #else diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 9da3594fd010..4defb7a0330f 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1201,7 +1201,7 @@ static int ath6kl_usb_pm_resume(struct usb_interface *interface) #endif /* table of devices that work with this driver */ -static struct usb_device_id ath6kl_usb_ids[] = { +static const struct usb_device_id ath6kl_usb_ids[] = { {USB_DEVICE(0x0cf3, 0x9375)}, {USB_DEVICE(0x0cf3, 0x9374)}, { /* Terminating entry */ }, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 2e64977a8ab6..01fa30117288 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1452,7 +1452,7 @@ int ath9k_init_debug(struct ath_hw *ah) #endif #ifdef CONFIG_ATH9K_DYNACK - debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("ack_to", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_ackto); #endif debugfs_create_file("tpc", S_IRUSR | S_IWUSR, diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 0d9687a2aa98..c5f4dd808745 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -20,7 +20,7 @@ MODULE_FIRMWARE(HTC_7010_MODULE_FW); MODULE_FIRMWARE(HTC_9271_MODULE_FW); -static struct usb_device_id ath9k_hif_usb_ids[] = { +static const struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x0cf3, 0x9271) }, /* Atheros */ { USB_DEVICE(0x0cf3, 0x1006) }, /* Atheros */ { USB_DEVICE(0x0846, 0x9030) }, /* Netgear N150 */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index defacc6c9c99..da2164b0cccc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -71,7 +71,7 @@ static void ath9k_htc_op_ps_restore(struct ath_common *common) ath9k_htc_ps_restore((struct ath9k_htc_priv *) common->priv); } -static struct ath_ps_ops ath9k_htc_ps_ops = { +static const struct ath_ps_ops ath9k_htc_ps_ops = { .wakeup = ath9k_htc_op_ps_wakeup, .restore = ath9k_htc_op_ps_restore, }; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index fd9a61834c17..bb7936090b91 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -104,7 +104,7 @@ static void ath9k_op_ps_restore(struct ath_common *common) ath9k_ps_restore((struct ath_softc *) common->priv); } -static struct ath_ps_ops ath9k_ps_ops = { +static const struct ath_ps_ops ath9k_ps_ops = { .wakeup = ath9k_op_ps_wakeup, .restore = ath9k_op_ps_restore, }; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 7b7627f85d3a..223606311261 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -388,6 +388,11 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_DELL, 0x020B), .driver_data = ATH9K_PCI_WOW }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0034, + PCI_VENDOR_ID_DELL, + 0x0300), + .driver_data = ATH9K_PCI_WOW }, /* Killer Wireless (2x2) */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index 99ab20334d21..e7c3f3b8457d 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -64,7 +64,7 @@ MODULE_ALIAS("arusb_lnx"); * http://wireless.kernel.org/en/users/Drivers/ar9170/devices ), * whenever you add a new device. */ -static struct usb_device_id carl9170_usb_ids[] = { +static const struct usb_device_id carl9170_usb_ids[] = { /* Atheros 9170 */ { USB_DEVICE(0x0cf3, 0x9170) }, /* Atheros TG121N */ diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 87dfdaf9044c..d5c810a8cc52 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -289,6 +289,11 @@ static int wcn36xx_dxe_fill_skb(struct device *dev, struct wcn36xx_dxe_ctl *ctl) skb_tail_pointer(skb), WCN36XX_PKT_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dxe->dst_addr_l)) { + dev_err(dev, "unable to map skb\n"); + kfree_skb(skb); + return -ENOMEM; + } ctl->skb = skb; return 0; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 517a315e259b..35bd50bcbbd5 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -372,6 +372,8 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed); + mutex_lock(&wcn->conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { int ch = WCN36XX_HW_CHANNEL(wcn); wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", @@ -382,6 +384,8 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) } } + mutex_unlock(&wcn->conf_mutex); + return 0; } @@ -396,6 +400,8 @@ static void wcn36xx_configure_filter(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n"); + mutex_lock(&wcn->conf_mutex); + *total &= FIF_ALLMULTI; fp = (void *)(unsigned long)multicast; @@ -408,6 +414,8 @@ static void wcn36xx_configure_filter(struct ieee80211_hw *hw, else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc) wcn36xx_smd_set_mc_list(wcn, vif, fp); } + + mutex_unlock(&wcn->conf_mutex); kfree(fp); } @@ -471,6 +479,8 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key_conf->key, key_conf->keylen); + mutex_lock(&wcn->conf_mutex); + switch (key_conf->cipher) { case WLAN_CIPHER_SUITE_WEP40: vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40; @@ -565,6 +575,8 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } out: + mutex_unlock(&wcn->conf_mutex); + return ret; } @@ -725,6 +737,8 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n", vif, changed); + mutex_lock(&wcn->conf_mutex); + if (changed & BSS_CHANGED_BEACON_INFO) { wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed dtim period %d\n", @@ -787,7 +801,13 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, bss_conf->aid); vif_priv->sta_assoc = true; - rcu_read_lock(); + + /* + * Holding conf_mutex ensures mutal exclusion with + * wcn36xx_sta_remove() and as such ensures that sta + * won't be freed while we're operating on it. As such + * we do not need to hold the rcu_read_lock(). + */ sta = ieee80211_find_sta(vif, bss_conf->bssid); if (!sta) { wcn36xx_err("sta %pM is not found\n", @@ -811,7 +831,6 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, * place where AID is available. */ wcn36xx_smd_config_sta(wcn, vif, sta); - rcu_read_unlock(); } else { wcn36xx_dbg(WCN36XX_DBG_MAC, "disassociated bss %pM vif %pM AID=%d\n", @@ -873,6 +892,9 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, } } out: + + mutex_unlock(&wcn->conf_mutex); + return; } @@ -882,7 +904,10 @@ static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) struct wcn36xx *wcn = hw->priv; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value); + mutex_lock(&wcn->conf_mutex); wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value); + mutex_unlock(&wcn->conf_mutex); + return 0; } @@ -893,8 +918,12 @@ static void wcn36xx_remove_interface(struct ieee80211_hw *hw, struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif); + mutex_lock(&wcn->conf_mutex); + list_del(&vif_priv->list); wcn36xx_smd_delete_sta_self(wcn, vif->addr); + + mutex_unlock(&wcn->conf_mutex); } static int wcn36xx_add_interface(struct ieee80211_hw *hw, @@ -915,9 +944,13 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw, return -EOPNOTSUPP; } + mutex_lock(&wcn->conf_mutex); + list_add(&vif_priv->list, &wcn->vif_list); wcn36xx_smd_add_sta_self(wcn, vif); + mutex_unlock(&wcn->conf_mutex); + return 0; } @@ -930,6 +963,8 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n", vif, sta->addr); + mutex_lock(&wcn->conf_mutex); + spin_lock_init(&sta_priv->ampdu_lock); sta_priv->vif = vif_priv; /* @@ -941,6 +976,9 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sta_priv->aid = sta->aid; wcn36xx_smd_config_sta(wcn, vif, sta); } + + mutex_unlock(&wcn->conf_mutex); + return 0; } @@ -954,8 +992,13 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n", vif, sta->addr, sta_priv->sta_index); + mutex_lock(&wcn->conf_mutex); + wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index); sta_priv->vif = NULL; + + mutex_unlock(&wcn->conf_mutex); + return 0; } @@ -999,6 +1042,8 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); + mutex_lock(&wcn->conf_mutex); + switch (action) { case IEEE80211_AMPDU_RX_START: sta_priv->tid = tid; @@ -1038,6 +1083,8 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, wcn36xx_err("Unknown AMPDU action\n"); } + mutex_unlock(&wcn->conf_mutex); + return 0; } @@ -1216,6 +1263,7 @@ static int wcn36xx_probe(struct platform_device *pdev) wcn = hw->priv; wcn->hw = hw; wcn->dev = &pdev->dev; + mutex_init(&wcn->conf_mutex); mutex_init(&wcn->hal_mutex); mutex_init(&wcn->scan_lock); diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index b52b4da9a967..6aefba4c0cda 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -202,6 +202,9 @@ struct wcn36xx { struct qcom_smem_state *tx_rings_empty_state; unsigned tx_rings_empty_state_bit; + /* prevents concurrent FW reconfiguration */ + struct mutex conf_mutex; + /* * smd_buf must be protected with smd_mutex to garantee * that all messages are sent one after another diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig index 6dfedc8bd6a3..b448926b0c0f 100644 --- a/drivers/net/wireless/ath/wil6210/Kconfig +++ b/drivers/net/wireless/ath/wil6210/Kconfig @@ -40,3 +40,15 @@ config WIL6210_TRACING option if you are interested in debugging the driver. If unsure, say Y to make it easier to debug problems. + +config WIL6210_DEBUGFS + bool "wil6210 debugfs support" + depends on WIL6210 + depends on DEBUG_FS + default y + ---help--- + Say Y here to enable wil6210 debugfs support, using the + kernel debugfs infrastructure. Select this + option if you are interested in debugging the driver. + + If unsure, say Y to make it easier to debug problems. diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 4ae21da78e9e..d27efe83748b 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -4,7 +4,7 @@ wil6210-y := main.o wil6210-y += netdev.o wil6210-y += cfg80211.o wil6210-y += pcie_bus.o -wil6210-y += debugfs.o +wil6210-$(CONFIG_WIL6210_DEBUGFS) += debugfs.o wil6210-y += wmi.o wil6210-y += interrupt.o wil6210-y += txrx.o diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 0b5383a62d42..85d5c04618eb 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -26,6 +26,12 @@ bool disable_ap_sme; module_param(disable_ap_sme, bool, 0444); MODULE_PARM_DESC(disable_ap_sme, " let user space handle AP mode SME"); +#ifdef CONFIG_PM +static struct wiphy_wowlan_support wil_wowlan_support = { + .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT, +}; +#endif + #define CHAN60G(_channel, _flags) { \ .band = NL80211_BAND_60GHZ, \ .center_freq = 56160 + (2160 * (_channel)), \ @@ -273,12 +279,12 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, wil_dbg_wmi(wil, "Link status for CID %d: {\n" " MCS %d TSF 0x%016llx\n" - " BF status 0x%08x SNR 0x%08x SQI %d%%\n" + " BF status 0x%08x RSSI %d SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", cid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, - le32_to_cpu(reply.evt.snr_val), + reply.evt.rssi, reply.evt.sqi, le32_to_cpu(reply.evt.tx_tpt), le32_to_cpu(reply.evt.tx_goodput), @@ -311,7 +317,11 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, if (test_bit(wil_status_fwconnected, wil->status)) { sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); - sinfo->signal = reply.evt.sqi; + if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, + wil->fw_capabilities)) + sinfo->signal = reply.evt.rssi; + else + sinfo->signal = reply.evt.sqi; } return rc; @@ -372,6 +382,34 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, return rc; } +static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + wil_dbg_misc(wil, "start_p2p_device: entered\n"); + wil->p2p.p2p_dev_started = 1; + return 0; +} + +static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil_p2p_info *p2p = &wil->p2p; + + if (!p2p->p2p_dev_started) + return; + + wil_dbg_misc(wil, "stop_p2p_device: entered\n"); + mutex_lock(&wil->mutex); + mutex_lock(&wil->p2p_wdev_mutex); + wil_p2p_stop_radio_operations(wil); + p2p->p2p_dev_started = 0; + mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->mutex); +} + static struct wireless_dev * wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, @@ -420,6 +458,7 @@ static int wil_cfg80211_del_iface(struct wiphy *wiphy, return -EINVAL; } + wil_cfg80211_stop_p2p_device(wiphy, wdev); wil_p2p_wdev_free(wil); return 0; @@ -801,7 +840,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, wil->bss = bss; /* Connect can take lots of time */ mod_timer(&wil->connect_timer, - jiffies + msecs_to_jiffies(2000)); + jiffies + msecs_to_jiffies(5000)); } else { clear_bit(wil_status_fwconnecting, wil->status); } @@ -884,6 +923,9 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); + if (len < sizeof(struct ieee80211_hdr_3addr)) + return -EINVAL; + cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL); if (!cmd) { rc = -ENOMEM; @@ -1648,34 +1690,6 @@ static int wil_cfg80211_change_bss(struct wiphy *wiphy, return 0; } -static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, - struct wireless_dev *wdev) -{ - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - - wil_dbg_misc(wil, "start_p2p_device: entered\n"); - wil->p2p.p2p_dev_started = 1; - return 0; -} - -static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, - struct wireless_dev *wdev) -{ - struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wil_p2p_info *p2p = &wil->p2p; - - if (!p2p->p2p_dev_started) - return; - - wil_dbg_misc(wil, "stop_p2p_device: entered\n"); - mutex_lock(&wil->mutex); - mutex_lock(&wil->p2p_wdev_mutex); - wil_p2p_stop_radio_operations(wil); - p2p->p2p_dev_started = 0; - mutex_unlock(&wil->p2p_wdev_mutex); - mutex_unlock(&wil->mutex); -} - static int wil_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) @@ -1791,7 +1805,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->bands[NL80211_BAND_60GHZ] = &wil_band_60ghz; - /* TODO: figure this out */ + /* may change after reading FW capabilities */ wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; wiphy->cipher_suites = wil_cipher_suites; @@ -1801,6 +1815,10 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands); wiphy->vendor_commands = wil_nl80211_vendor_commands; + +#ifdef CONFIG_PM + wiphy->wowlan = &wil_wowlan_support; +#endif } struct wireless_dev *wil_cfg80211_init(struct device *dev) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index f82506d276d3..6db00c167d2e 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -20,7 +20,6 @@ #include <linux/pci.h> #include <linux/rtnetlink.h> #include <linux/power_supply.h> - #include "wil6210.h" #include "wmi.h" #include "txrx.h" @@ -30,7 +29,6 @@ static u32 mem_addr; static u32 dbg_txdesc_index; static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */ -u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */ enum dbg_off_type { doff_u32 = 0, @@ -801,6 +799,9 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, int rc; void *frame; + if (!len) + return -EINVAL; + frame = memdup_user(buf, len); if (IS_ERR(frame)) return PTR_ERR(frame); @@ -1013,6 +1014,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) " TSF = 0x%016llx\n" " TxMCS = %2d TxTpt = %4d\n" " SQI = %4d\n" + " RSSI = %4d\n" " Status = 0x%08x %s\n" " Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n" " Goodput(rx:tx) %4d:%4d\n" @@ -1022,6 +1024,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) le16_to_cpu(reply.evt.bf_mcs), le32_to_cpu(reply.evt.tx_tpt), reply.evt.sqi, + reply.evt.rssi, status, wil_bfstatus_str(status), le16_to_cpu(reply.evt.my_rx_sector), le16_to_cpu(reply.evt.my_tx_sector), @@ -1612,6 +1615,8 @@ static ssize_t wil_write_suspend_stats(struct file *file, struct wil6210_priv *wil = file->private_data; memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); + wil->suspend_stats.min_suspend_time = ULONG_MAX; + wil->suspend_stats.collection_start = ktime_get(); return len; } @@ -1623,18 +1628,27 @@ static ssize_t wil_read_suspend_stats(struct file *file, struct wil6210_priv *wil = file->private_data; static char text[400]; int n; + unsigned long long stats_collection_time = + ktime_to_us(ktime_sub(ktime_get(), + wil->suspend_stats.collection_start)); n = snprintf(text, sizeof(text), "Suspend statistics:\n" "successful suspends:%ld failed suspends:%ld\n" "successful resumes:%ld failed resumes:%ld\n" - "rejected by host:%ld rejected by device:%ld\n", + "rejected by host:%ld rejected by device:%ld\n" + "total suspend time:%lld min suspend time:%lld\n" + "max suspend time:%lld stats collection time: %lld\n", wil->suspend_stats.successful_suspends, wil->suspend_stats.failed_suspends, wil->suspend_stats.successful_resumes, wil->suspend_stats.failed_resumes, wil->suspend_stats.rejected_by_host, - wil->suspend_stats.rejected_by_device); + wil->suspend_stats.rejected_by_device, + wil->suspend_stats.total_suspend_time, + wil->suspend_stats.min_suspend_time, + wil->suspend_stats.max_suspend_time, + stats_collection_time); n = min_t(int, n, sizeof(text)); @@ -1747,6 +1761,7 @@ static const struct dbg_off dbg_wil_off[] = { WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8), WIL_FIELD(wakeup_trigger, 0644, doff_u8), + WIL_FIELD(vring_idle_trsh, 0644, doff_u32), {}, }; @@ -1762,8 +1777,6 @@ static const struct dbg_off dbg_statics[] = { {"desc_index", 0644, (ulong)&dbg_txdesc_index, doff_u32}, {"vring_index", 0644, (ulong)&dbg_vring_index, doff_u32}, {"mem_addr", 0644, (ulong)&mem_addr, doff_u32}, - {"vring_idle_trsh", 0644, (ulong)&vring_idle_trsh, - doff_u32}, {"led_polarity", 0644, (ulong)&led_polarity, doff_u8}, {}, }; @@ -1790,6 +1803,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil) wil6210_debugfs_create_ITR_CNT(wil, dbg); + wil->suspend_stats.collection_start = ktime_get(); + return 0; } diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index cad8a95c4e4e..59def4f3fcf3 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -244,7 +244,7 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) wil_dbg_irq(wil, "ISR RX 0x%08x\n", isr); if (unlikely(!isr)) { - wil_err(wil, "spurious IRQ: RX\n"); + wil_err_ratelimited(wil, "spurious IRQ: RX\n"); return IRQ_NONE; } @@ -269,11 +269,12 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie) need_unmask = false; napi_schedule(&wil->napi_rx); } else { - wil_err(wil, + wil_err_ratelimited( + wil, "Got Rx interrupt while stopping interface\n"); } } else { - wil_err(wil, "Got Rx interrupt while in reset\n"); + wil_err_ratelimited(wil, "Got Rx interrupt while in reset\n"); } } @@ -302,7 +303,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) wil_dbg_irq(wil, "ISR TX 0x%08x\n", isr); if (unlikely(!isr)) { - wil_err(wil, "spurious IRQ: TX\n"); + wil_err_ratelimited(wil, "spurious IRQ: TX\n"); return IRQ_NONE; } @@ -318,12 +319,13 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) need_unmask = false; napi_schedule(&wil->napi_tx); } else { - wil_err(wil, "Got Tx interrupt while in reset\n"); + wil_err_ratelimited(wil, "Got Tx interrupt while in reset\n"); } } if (unlikely(isr)) - wil_err(wil, "un-handled TX ISR bits 0x%08x\n", isr); + wil_err_ratelimited(wil, "un-handled TX ISR bits 0x%08x\n", + isr); /* Tx IRQ will be enabled when NAPI processing finished */ diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index daf944a71901..bac829aa950d 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -394,10 +394,11 @@ static void wil_fw_error_worker(struct work_struct *work) struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct wireless_dev *wdev = wil->wdev; + struct net_device *ndev = wil_to_ndev(wil); wil_dbg_misc(wil, "fw error worker\n"); - if (!netif_running(wil_to_ndev(wil))) { + if (!(ndev->flags & IFF_UP)) { wil_info(wil, "No recovery - interface is down\n"); return; } @@ -578,6 +579,9 @@ int wil_priv_init(struct wil6210_priv *wil) wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST | WMI_WAKEUP_TRIGGER_BCAST; + memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); + wil->suspend_stats.min_suspend_time = ULONG_MAX; + wil->vring_idle_trsh = 16; return 0; @@ -926,6 +930,29 @@ int wil_ps_update(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) return rc; } +static void wil_pre_fw_config(struct wil6210_priv *wil) +{ + /* Mark FW as loaded from host */ + wil_s(wil, RGF_USER_USAGE_6, 1); + + /* clear any interrupts which on-card-firmware + * may have set + */ + wil6210_clear_irq(wil); + /* CAF_ICR - clear and mask */ + /* it is W1C, clear by writing back same value */ + wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + /* clear PAL_UNIT_ICR (potential D0->D3 leftover) */ + wil_s(wil, RGF_PAL_UNIT_ICR + offsetof(struct RGF_ICR, ICR), 0); + + if (wil->fw_calib_result > 0) { + __le32 val = cpu_to_le32(wil->fw_calib_result | + (CALIB_RESULT_SIGNATURE << 8)); + wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val); + } +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -1019,18 +1046,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (rc) return rc; - /* Mark FW as loaded from host */ - wil_s(wil, RGF_USER_USAGE_6, 1); - - /* clear any interrupts which on-card-firmware - * may have set - */ - wil6210_clear_irq(wil); - /* CAF_ICR - clear and mask */ - /* it is W1C, clear by writing back same value */ - wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); - wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); - + wil_pre_fw_config(wil); wil_release_cpu(wil); } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index d571feb2370e..6a3ab4bf916d 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -84,6 +84,9 @@ void wil_set_capabilities(struct wil6210_priv *wil) /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, wil->wil_fw_name, false); + + if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities)) + wil_to_wiphy(wil)->signal_type = CFG80211_SIGNAL_TYPE_MBM; } void wil_disable_irq(struct wil6210_priv *wil) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index ce1f384e7f8e..8f5d1b447aaa 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -21,10 +21,11 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) { int rc = 0; struct wireless_dev *wdev = wil->wdev; + struct net_device *ndev = wil_to_ndev(wil); wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); - if (!netif_running(wil_to_ndev(wil))) { + if (!(ndev->flags & IFF_UP)) { /* can always sleep when down */ wil_dbg_pm(wil, "Interface is down\n"); goto out; @@ -85,7 +86,9 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil) /* Send WMI resume request to the device */ rc = wmi_resume(wil); if (rc) { - wil_err(wil, "device failed to resume (%d), resetting\n", rc); + wil_err(wil, "device failed to resume (%d)\n", rc); + if (no_fw_recovery) + goto out; rc = wil_down(wil); if (rc) { wil_err(wil, "wil_down failed (%d)\n", rc); @@ -298,6 +301,9 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); + if (!rc) + wil->suspend_stats.suspend_start_time = ktime_get(); + return rc; } @@ -307,6 +313,7 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) struct net_device *ndev = wil_to_ndev(wil); bool keep_radio_on = ndev->flags & IFF_UP && wil->keep_radio_on_during_sleep; + unsigned long long suspend_time_usec = 0; wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); @@ -324,8 +331,20 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) else rc = wil_resume_radio_off(wil); + if (rc) + goto out; + + suspend_time_usec = + ktime_to_us(ktime_sub(ktime_get(), + wil->suspend_stats.suspend_start_time)); + wil->suspend_stats.total_suspend_time += suspend_time_usec; + if (suspend_time_usec < wil->suspend_stats.min_suspend_time) + wil->suspend_stats.min_suspend_time = suspend_time_usec; + if (suspend_time_usec > wil->suspend_stats.max_suspend_time) + wil->suspend_stats.max_suspend_time = suspend_time_usec; + out: - wil_dbg_pm(wil, "resume: %s => %d\n", - is_runtime ? "runtime" : "system", rc); + wil_dbg_pm(wil, "resume: %s => %d, suspend time %lld usec\n", + is_runtime ? "runtime" : "system", rc, suspend_time_usec); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index ec57bcce9601..389c718cd257 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1666,7 +1666,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, /* performance monitoring */ used = wil_vring_used_tx(vring); - if (wil_val_in_range(vring_idle_trsh, + if (wil_val_in_range(wil->vring_idle_trsh, used, used + descs_used)) { txdata->idle += get_cycles() - txdata->last_idle; wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", @@ -1813,7 +1813,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /* performance monitoring */ used = wil_vring_used_tx(vring); - if (wil_val_in_range(vring_idle_trsh, + if (wil_val_in_range(wil->vring_idle_trsh, used, used + nr_frags + 1)) { txdata->idle += get_cycles() - txdata->last_idle; wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n", @@ -2175,7 +2175,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) /* performance monitoring */ used_new = wil_vring_used_tx(vring); - if (wil_val_in_range(vring_idle_trsh, + if (wil_val_in_range(wil->vring_idle_trsh, used_new, used_before_complete)) { wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n", ringid, used_before_complete, used_new); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index d085ccfc7228..315ec8b59662 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -30,7 +30,6 @@ extern bool no_fw_recovery; extern unsigned int mtu_max; extern unsigned short rx_ring_overflow_thrsh; extern int agg_wsize; -extern u32 vring_idle_trsh; extern bool rx_align_2; extern bool rx_large_buf; extern bool debug_fw; @@ -90,6 +89,11 @@ struct wil_suspend_stats { unsigned long failed_resumes; unsigned long rejected_by_device; unsigned long rejected_by_host; + unsigned long long total_suspend_time; + unsigned long long min_suspend_time; + unsigned long long max_suspend_time; + ktime_t collection_start; + ktime_t suspend_start_time; }; /* Calculate MAC buffer size for the firmware. It includes all overhead, @@ -166,6 +170,10 @@ struct RGF_ICR { #define RGF_USER_USER_SCRATCH_PAD (0x8802bc) #define RGF_USER_BL (0x880A3C) /* Boot Loader */ #define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */ +#define RGF_USER_FW_CALIB_RESULT (0x880a90) /* b0-7:result + * b8-15:signature + */ + #define CALIB_RESULT_SIGNATURE (0x11) #define RGF_USER_CLKS_CTL_0 (0x880abc) #define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */ #define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */ @@ -260,6 +268,7 @@ struct RGF_ICR { #define BIT_DMA_PSEUDO_CAUSE_MISC BIT(2) #define RGF_HP_CTRL (0x88265c) +#define RGF_PAL_UNIT_ICR (0x88266c) /* struct RGF_ICR */ #define RGF_PCIE_LOS_COUNTER_CTL (0x882dc4) /* MAC timer, usec, for packet lifetime */ @@ -684,6 +693,7 @@ struct wil6210_priv { u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ struct wil_sta_info sta[WIL6210_MAX_CID]; int bcast_vring; + u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */ bool use_extended_dma_addr; /* indicates whether we are using 48 bits */ /* scan */ struct cfg80211_scan_request *scan_request; @@ -719,6 +729,8 @@ struct wil6210_priv { enum wmi_ps_profile_type ps_profile; + int fw_calib_result; + #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP struct notifier_block pm_notify; @@ -929,8 +941,14 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params, u64 *cookie); +#if defined(CONFIG_WIL6210_DEBUGFS) int wil6210_debugfs_init(struct wil6210_priv *wil); void wil6210_debugfs_remove(struct wil6210_priv *wil); +#else +static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; } +static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {} +#endif + int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, struct station_info *sinfo); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 65ef67321fc0..ffdd2fa401b1 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -344,6 +344,11 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) strlcpy(wdev->wiphy->fw_version, wil->fw_version, sizeof(wdev->wiphy->fw_version)); + if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) { + wil_dbg_wmi(wil, "rfc calibration result %d\n", + evt->rfc_read_calib_result); + wil->fw_calib_result = evt->rfc_read_calib_result; + } wil_set_recovery_state(wil, fw_recovery_idle); set_bit(wil_status_fwready, wil->status); /* let the reset sequence continue */ @@ -381,12 +386,15 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) ch_no = data->info.channel + 1; freq = ieee80211_channel_to_frequency(ch_no, NL80211_BAND_60GHZ); channel = ieee80211_get_channel(wiphy, freq); - signal = data->info.sqi; + if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities)) + signal = 100 * data->info.rssi; + else + signal = data->info.sqi; d_status = le16_to_cpu(data->info.status); fc = rx_mgmt_frame->frame_control; - wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d SNR %d SQI %d%%\n", - data->info.channel, data->info.mcs, data->info.snr, + wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n", + data->info.channel, data->info.mcs, data->info.rssi, data->info.sqi); wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len, le16_to_cpu(fc)); diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 256f63c57da0..5263ee717a4f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -36,6 +36,11 @@ #define WMI_PROX_RANGE_NUM (3) #define WMI_MAX_LOSS_DMG_BEACONS (20) #define MAX_NUM_OF_SECTORS (128) +#define WMI_SCHED_MAX_ALLOCS_PER_CMD (4) +#define WMI_RF_DTYPE_LENGTH (3) +#define WMI_RF_ETYPE_LENGTH (3) +#define WMI_RF_RX2TX_LENGTH (3) +#define WMI_RF_ETYPE_VAL_PER_RANGE (5) /* Mailbox interface * used for commands and events @@ -52,14 +57,20 @@ enum wmi_mid { * the host */ enum wmi_fw_capability { - WMI_FW_CAPABILITY_FTM = 0, - WMI_FW_CAPABILITY_PS_CONFIG = 1, - WMI_FW_CAPABILITY_RF_SECTORS = 2, - WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3, - WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, - WMI_FW_CAPABILITY_WMI_ONLY = 5, - WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, - WMI_FW_CAPABILITY_D3_SUSPEND = 8, + WMI_FW_CAPABILITY_FTM = 0, + WMI_FW_CAPABILITY_PS_CONFIG = 1, + WMI_FW_CAPABILITY_RF_SECTORS = 2, + WMI_FW_CAPABILITY_MGMT_RETRY_LIMIT = 3, + WMI_FW_CAPABILITY_DISABLE_AP_SME = 4, + WMI_FW_CAPABILITY_WMI_ONLY = 5, + WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7, + WMI_FW_CAPABILITY_D3_SUSPEND = 8, + WMI_FW_CAPABILITY_LONG_RANGE = 9, + WMI_FW_CAPABILITY_FIXED_SCHEDULING = 10, + WMI_FW_CAPABILITY_MULTI_DIRECTED_OMNIS = 11, + WMI_FW_CAPABILITY_RSSI_REPORTING = 12, + WMI_FW_CAPABILITY_SET_SILENT_RSSI_TABLE = 13, + WMI_FW_CAPABILITY_LO_POWER_CALIB_FROM_OTP = 14, WMI_FW_CAPABILITY_MAX, }; @@ -79,6 +90,7 @@ enum wmi_command_id { WMI_START_SCAN_CMDID = 0x07, WMI_SET_BSS_FILTER_CMDID = 0x09, WMI_SET_PROBED_SSID_CMDID = 0x0A, + /* deprecated */ WMI_SET_LISTEN_INT_CMDID = 0x0B, WMI_BCON_CTRL_CMDID = 0x0F, WMI_ADD_CIPHER_KEY_CMDID = 0x16, @@ -93,26 +105,28 @@ enum wmi_command_id { WMI_ECHO_CMDID = 0x803, WMI_DEEP_ECHO_CMDID = 0x804, WMI_CONFIG_MAC_CMDID = 0x805, + /* deprecated */ WMI_CONFIG_PHY_DEBUG_CMDID = 0x806, WMI_ADD_DEBUG_TX_PCKT_CMDID = 0x808, WMI_PHY_GET_STATISTICS_CMDID = 0x809, + /* deprecated */ WMI_FS_TUNE_CMDID = 0x80A, + /* deprecated */ WMI_CORR_MEASURE_CMDID = 0x80B, WMI_READ_RSSI_CMDID = 0x80C, WMI_TEMP_SENSE_CMDID = 0x80E, WMI_DC_CALIB_CMDID = 0x80F, + /* deprecated */ WMI_SEND_TONE_CMDID = 0x810, + /* deprecated */ WMI_IQ_TX_CALIB_CMDID = 0x811, + /* deprecated */ WMI_IQ_RX_CALIB_CMDID = 0x812, - WMI_SET_UCODE_IDLE_CMDID = 0x813, WMI_SET_WORK_MODE_CMDID = 0x815, WMI_LO_LEAKAGE_CALIB_CMDID = 0x816, - WMI_MARLON_R_READ_CMDID = 0x818, - WMI_MARLON_R_WRITE_CMDID = 0x819, - WMI_MARLON_R_TXRX_SEL_CMDID = 0x81A, - MAC_IO_STATIC_PARAMS_CMDID = 0x81B, - MAC_IO_DYNAMIC_PARAMS_CMDID = 0x81C, + WMI_LO_POWER_CALIB_FROM_OTP_CMDID = 0x817, WMI_SILENT_RSSI_CALIB_CMDID = 0x81D, + /* deprecated */ WMI_RF_RX_TEST_CMDID = 0x81E, WMI_CFG_RX_CHAIN_CMDID = 0x820, WMI_VRING_CFG_CMDID = 0x821, @@ -126,11 +140,6 @@ enum wmi_command_id { WMI_SET_PCP_CHANNEL_CMDID = 0x829, WMI_GET_PCP_CHANNEL_CMDID = 0x82A, WMI_SW_TX_REQ_CMDID = 0x82B, - WMI_READ_MAC_RXQ_CMDID = 0x830, - WMI_READ_MAC_TXQ_CMDID = 0x831, - WMI_WRITE_MAC_RXQ_CMDID = 0x832, - WMI_WRITE_MAC_TXQ_CMDID = 0x833, - WMI_WRITE_MAC_XQ_FIELD_CMDID = 0x834, WMI_MLME_PUSH_CMDID = 0x835, WMI_BEAMFORMING_MGMT_CMDID = 0x836, WMI_BF_TXSS_MGMT_CMDID = 0x837, @@ -144,9 +153,13 @@ enum wmi_command_id { WMI_MAINTAIN_RESUME_CMDID = 0x851, WMI_RS_MGMT_CMDID = 0x852, WMI_RF_MGMT_CMDID = 0x853, - WMI_OTP_READ_CMDID = 0x856, - WMI_OTP_WRITE_CMDID = 0x857, + WMI_RF_XPM_READ_CMDID = 0x856, + WMI_RF_XPM_WRITE_CMDID = 0x857, WMI_LED_CFG_CMDID = 0x858, + WMI_SET_CONNECT_SNR_THR_CMDID = 0x85B, + WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID = 0x85C, + WMI_RF_PWR_ON_DELAY_CMDID = 0x85D, + WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID = 0x85E, /* Performance monitoring commands */ WMI_BF_CTRL_CMDID = 0x862, WMI_NOTIFY_REQ_CMDID = 0x863, @@ -154,7 +167,6 @@ enum wmi_command_id { WMI_GET_RF_STATUS_CMDID = 0x866, WMI_GET_BASEBAND_TYPE_CMDID = 0x867, WMI_UNIT_TEST_CMDID = 0x900, - WMI_HICCUP_CMDID = 0x901, WMI_FLASH_READ_CMDID = 0x902, WMI_FLASH_WRITE_CMDID = 0x903, /* Power management */ @@ -174,16 +186,6 @@ enum wmi_command_id { WMI_GET_PCP_FACTOR_CMDID = 0x91B, /* Power Save Configuration Commands */ WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C, - /* Not supported yet */ - WMI_PS_DEV_CFG_CMDID = 0x91D, - /* Not supported yet */ - WMI_PS_DEV_CFG_READ_CMDID = 0x91E, - /* Per MAC Power Save Configuration commands - * Not supported yet - */ - WMI_PS_MID_CFG_CMDID = 0x91F, - /* Not supported yet */ - WMI_PS_MID_CFG_READ_CMDID = 0x920, WMI_RS_CFG_CMDID = 0x921, WMI_GET_DETAILED_RS_RES_CMDID = 0x922, WMI_AOA_MEAS_CMDID = 0x923, @@ -194,13 +196,16 @@ enum wmi_command_id { WMI_DEL_STA_CMDID = 0x936, WMI_SET_THERMAL_THROTTLING_CFG_CMDID = 0x940, WMI_GET_THERMAL_THROTTLING_CFG_CMDID = 0x941, + /* Read Power Save profile type */ + WMI_PS_DEV_PROFILE_CFG_READ_CMDID = 0x942, WMI_TOF_SESSION_START_CMDID = 0x991, WMI_TOF_GET_CAPABILITIES_CMDID = 0x992, WMI_TOF_SET_LCR_CMDID = 0x993, WMI_TOF_SET_LCI_CMDID = 0x994, - WMI_TOF_CHANNEL_INFO_CMDID = 0x995, + WMI_TOF_CFG_RESPONDER_CMDID = 0x996, WMI_TOF_SET_TX_RX_OFFSET_CMDID = 0x997, WMI_TOF_GET_TX_RX_OFFSET_CMDID = 0x998, + WMI_TOF_CHANNEL_INFO_CMDID = 0x999, WMI_GET_RF_SECTOR_PARAMS_CMDID = 0x9A0, WMI_SET_RF_SECTOR_PARAMS_CMDID = 0x9A1, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID = 0x9A2, @@ -209,12 +214,20 @@ enum wmi_command_id { WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5, WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7, + WMI_SCHEDULING_SCHEME_CMDID = 0xA01, + WMI_FIXED_SCHEDULING_CONFIG_CMDID = 0xA02, + WMI_ENABLE_FIXED_SCHEDULING_CMDID = 0xA03, + WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID = 0xA04, + WMI_SET_LONG_RANGE_CONFIG_CMDID = 0xA05, WMI_SET_MAC_ADDRESS_CMDID = 0xF003, WMI_ABORT_SCAN_CMDID = 0xF007, WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041, + /* deprecated */ WMI_GET_PMK_CMDID = 0xF048, WMI_SET_PASSPHRASE_CMDID = 0xF049, + /* deprecated */ WMI_SEND_ASSOC_RES_CMDID = 0xF04A, + /* deprecated */ WMI_SET_ASSOC_REQ_RELAY_CMDID = 0xF04B, WMI_MAC_ADDR_REQ_CMDID = 0xF04D, WMI_FW_VER_CMDID = 0xF04E, @@ -440,11 +453,6 @@ struct wmi_rf_mgmt_cmd { __le32 rf_mgmt_type; } __packed; -/* WMI_RF_RX_TEST_CMDID */ -struct wmi_rf_rx_test_cmd { - __le32 sector; -} __packed; - /* WMI_CORR_MEASURE_CMDID */ struct wmi_corr_measure_cmd { __le32 freq_mhz; @@ -657,6 +665,20 @@ struct wmi_bcast_vring_cfg_cmd { struct wmi_bcast_vring_cfg vring_cfg; } __packed; +/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */ +struct wmi_lo_power_calib_from_otp_cmd { + /* index to read from OTP. zero based */ + u8 index; + u8 reserved[3]; +} __packed; + +/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */ +struct wmi_lo_power_calib_from_otp_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_VRING_BA_EN_CMDID */ struct wmi_vring_ba_en_cmd { u8 ringid; @@ -692,6 +714,24 @@ enum wmi_sniffer_cfg_mode { WMI_SNIFFER_ON = 0x01, }; +/* WMI_SILENT_RSSI_TABLE */ +enum wmi_silent_rssi_table { + RF_TEMPERATURE_CALIB_DEFAULT_DB = 0x00, + RF_TEMPERATURE_CALIB_HIGH_POWER_DB = 0x01, +}; + +/* WMI_SILENT_RSSI_STATUS */ +enum wmi_silent_rssi_status { + SILENT_RSSI_SUCCESS = 0x00, + SILENT_RSSI_FAILURE = 0x01, +}; + +/* WMI_SET_ACTIVE_SILENT_RSSI_TABLE_CMDID */ +struct wmi_set_active_silent_rssi_table_cmd { + /* enum wmi_silent_rssi_table */ + __le32 table; +} __packed; + enum wmi_sniffer_cfg_phy_info_mode { WMI_SNIFFER_PHY_INFO_DISABLED = 0x00, WMI_SNIFFER_PHY_INFO_ENABLED = 0x01, @@ -835,18 +875,85 @@ struct wmi_echo_cmd { __le32 value; } __packed; -/* WMI_OTP_READ_CMDID */ -struct wmi_otp_read_cmd { - __le32 addr; - __le32 size; - __le32 values; +/* WMI_RF_PWR_ON_DELAY_CMDID + * set FW time parameters used through RF resetting + * RF reset consists of bringing its power down for a period of time, then + * bringing the power up + * Returned event: WMI_RF_PWR_ON_DELAY_RSP_EVENTID + */ +struct wmi_rf_pwr_on_delay_cmd { + /* time in usec the FW waits after bringing the RF PWR down, + * set 0 for default + */ + __le16 down_delay_usec; + /* time in usec the FW waits after bringing the RF PWR up, + * set 0 for default + */ + __le16 up_delay_usec; +} __packed; + +/* \WMI_SET_HIGH_POWER_TABLE_PARAMS_CMDID + * This API controls the Tx and Rx gain over temperature. + * It controls the Tx D-type, Rx D-type and Rx E-type amplifiers. + * It also controls the Tx gain index, by controlling the Rx to Tx gain index + * offset. + * The control is divided by 3 temperature values to 4 temperature ranges. + * Each parameter uses its own temperature values. + * Returned event: WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID + */ +struct wmi_set_high_power_table_params_cmd { + /* Temperature range for Tx D-type parameters */ + u8 tx_dtype_temp[WMI_RF_DTYPE_LENGTH]; + u8 reserved0; + /* Tx D-type values to be used for each temperature range */ + __le32 tx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1]; + /* Temperature range for Rx D-type parameters */ + u8 rx_dtype_temp[WMI_RF_DTYPE_LENGTH]; + u8 reserved1; + /* Rx D-type values to be used for each temperature range */ + __le32 rx_dtype_conf[WMI_RF_DTYPE_LENGTH + 1]; + /* Temperature range for Rx E-type parameters */ + u8 rx_etype_temp[WMI_RF_ETYPE_LENGTH]; + u8 reserved2; + /* Rx E-type values to be used for each temperature range. + * The last 4 values of any range are the first 4 values of the next + * range and so on + */ + __le32 rx_etype_conf[WMI_RF_ETYPE_VAL_PER_RANGE + WMI_RF_ETYPE_LENGTH]; + /* Temperature range for rx_2_tx_offs parameters */ + u8 rx_2_tx_temp[WMI_RF_RX2TX_LENGTH]; + u8 reserved3; + /* Rx to Tx gain index offset */ + s8 rx_2_tx_offs[WMI_RF_RX2TX_LENGTH + 1]; +} __packed; + +/* CMD: WMI_RF_XPM_READ_CMDID */ +struct wmi_rf_xpm_read_cmd { + u8 rf_id; + u8 reserved[3]; + /* XPM bit start address in range [0,8191]bits - rounded by FW to + * multiple of 8bits + */ + __le32 xpm_bit_address; + __le32 num_bytes; } __packed; -/* WMI_OTP_WRITE_CMDID */ -struct wmi_otp_write_cmd { - __le32 addr; - __le32 size; - __le32 values; +/* CMD: WMI_RF_XPM_WRITE_CMDID */ +struct wmi_rf_xpm_write_cmd { + u8 rf_id; + u8 reserved0[3]; + /* XPM bit start address in range [0,8191]bits - rounded by FW to + * multiple of 8bits + */ + __le32 xpm_bit_address; + __le32 num_bytes; + /* boolean flag indicating whether FW should verify the write + * operation + */ + u8 verify; + u8 reserved1[3]; + /* actual size=num_bytes */ + u8 data_bytes[0]; } __packed; /* WMI_TEMP_SENSE_CMDID @@ -989,19 +1096,26 @@ struct wmi_ftm_dest_info { */ __le16 burst_period; u8 dst_mac[WMI_MAC_LEN]; - __le16 reserved; + u8 reserved; + u8 num_burst_per_aoa_meas; } __packed; /* WMI_TOF_SESSION_START_CMDID */ struct wmi_tof_session_start_cmd { __le32 session_id; - u8 num_of_aoa_measures; + u8 reserved1; u8 aoa_type; __le16 num_of_dest; u8 reserved[4]; struct wmi_ftm_dest_info ftm_dest_info[0]; } __packed; +/* WMI_TOF_CFG_RESPONDER_CMDID */ +struct wmi_tof_cfg_responder_cmd { + u8 enable; + u8 reserved[3]; +} __packed; + enum wmi_tof_channel_info_report_type { WMI_TOF_CHANNEL_INFO_TYPE_CIR = 0x1, WMI_TOF_CHANNEL_INFO_TYPE_RSSI = 0x2, @@ -1022,7 +1136,99 @@ struct wmi_tof_set_tx_rx_offset_cmd { __le32 tx_offset; /* RX delay offset */ __le32 rx_offset; - __le32 reserved[2]; + /* Mask to define which RFs to configure. 0 means all RFs */ + __le32 rf_mask; + /* Offset to strongest tap of CIR */ + __le32 precursor; +} __packed; + +/* WMI_TOF_GET_TX_RX_OFFSET_CMDID */ +struct wmi_tof_get_tx_rx_offset_cmd { + /* rf index to read offsets from */ + u8 rf_index; + u8 reserved[3]; +} __packed; + +/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */ +struct wmi_map_mcs_to_schd_params { + u8 mcs; + /* time in usec from start slot to start tx flow - default 15 */ + u8 time_in_usec_before_initiate_tx; + /* RD enable - if yes consider RD according to STA mcs */ + u8 rd_enabled; + u8 reserved; + /* time in usec from start slot to stop vring */ + __le16 time_in_usec_to_stop_vring; + /* timeout to force flush from start of slot */ + __le16 flush_to_in_usec; + /* per mcs the mac buffer limit size in bytes */ + __le32 mac_buff_size_in_bytes; +} __packed; + +/* WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID */ +struct wmi_fixed_scheduling_config_complete_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +#define WMI_NUM_MCS (13) + +/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */ +struct wmi_fixed_scheduling_config_cmd { + /* defaults in the SAS table */ + struct wmi_map_mcs_to_schd_params mcs_to_schd_params_map[WMI_NUM_MCS]; + /* default 150 uSec */ + __le16 max_sta_rd_ppdu_duration_in_usec; + /* default 300 uSec */ + __le16 max_sta_grant_ppdu_duration_in_usec; + /* default 1000 uSec */ + __le16 assoc_slot_duration_in_usec; + /* default 360 uSec */ + __le16 virtual_slot_duration_in_usec; + /* each this field value slots start with grant frame to the station + * - default 2 + */ + u8 number_of_ap_slots_for_initiate_grant; + u8 reserved[3]; +} __packed; + +/* WMI_ENABLE_FIXED_SCHEDULING_CMDID */ +struct wmi_enable_fixed_scheduling_cmd { + __le32 reserved; +} __packed; + +/* WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID */ +struct wmi_enable_fixed_scheduling_complete_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_CMDID */ +struct wmi_set_multi_directed_omnis_config_cmd { + /* number of directed omnis at destination AP */ + u8 dest_ap_num_directed_omnis; + u8 reserved[3]; +} __packed; + +/* WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID */ +struct wmi_set_multi_directed_omnis_config_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_LONG_RANGE_CONFIG_CMDID */ +struct wmi_set_long_range_config_cmd { + __le32 reserved; +} __packed; + +/* WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID */ +struct wmi_set_long_range_config_complete_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; } __packed; /* WMI Events @@ -1038,19 +1244,22 @@ enum wmi_event_id { WMI_FW_READY_EVENTID = 0x1801, WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200, WMI_ECHO_RSP_EVENTID = 0x1803, + /* deprecated */ WMI_FS_TUNE_DONE_EVENTID = 0x180A, + /* deprecated */ WMI_CORR_MEASURE_EVENTID = 0x180B, WMI_READ_RSSI_EVENTID = 0x180C, WMI_TEMP_SENSE_DONE_EVENTID = 0x180E, WMI_DC_CALIB_DONE_EVENTID = 0x180F, + /* deprecated */ WMI_IQ_TX_CALIB_DONE_EVENTID = 0x1811, + /* deprecated */ WMI_IQ_RX_CALIB_DONE_EVENTID = 0x1812, WMI_SET_WORK_MODE_DONE_EVENTID = 0x1815, WMI_LO_LEAKAGE_CALIB_DONE_EVENTID = 0x1816, - WMI_MARLON_R_READ_DONE_EVENTID = 0x1818, - WMI_MARLON_R_WRITE_DONE_EVENTID = 0x1819, - WMI_MARLON_R_TXRX_SEL_DONE_EVENTID = 0x181A, + WMI_LO_POWER_CALIB_FROM_OTP_EVENTID = 0x1817, WMI_SILENT_RSSI_CALIB_DONE_EVENTID = 0x181D, + /* deprecated */ WMI_RF_RX_TEST_DONE_EVENTID = 0x181E, WMI_CFG_RX_CHAIN_DONE_EVENTID = 0x1820, WMI_VRING_CFG_DONE_EVENTID = 0x1821, @@ -1061,11 +1270,6 @@ enum wmi_event_id { WMI_GET_SSID_EVENTID = 0x1828, WMI_GET_PCP_CHANNEL_EVENTID = 0x182A, WMI_SW_TX_COMPLETE_EVENTID = 0x182B, - WMI_READ_MAC_RXQ_EVENTID = 0x1830, - WMI_READ_MAC_TXQ_EVENTID = 0x1831, - WMI_WRITE_MAC_RXQ_EVENTID = 0x1832, - WMI_WRITE_MAC_TXQ_EVENTID = 0x1833, - WMI_WRITE_MAC_XQ_FIELD_EVENTID = 0x1834, WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836, WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837, WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839, @@ -1076,8 +1280,12 @@ enum wmi_event_id { WMI_TX_MGMT_PACKET_EVENTID = 0x1841, WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID = 0x1842, WMI_LINK_MAINTAIN_CFG_READ_DONE_EVENTID = 0x1843, - WMI_OTP_READ_RESULT_EVENTID = 0x1856, + WMI_RF_XPM_READ_RESULT_EVENTID = 0x1856, + WMI_RF_XPM_WRITE_RESULT_EVENTID = 0x1857, WMI_LED_CFG_DONE_EVENTID = 0x1858, + WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID = 0x185C, + WMI_RF_PWR_ON_DELAY_RSP_EVENTID = 0x185D, + WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID = 0x185E, /* Performance monitoring events */ WMI_DATA_PORT_OPEN_EVENTID = 0x1860, WMI_WBE_LINK_DOWN_EVENTID = 0x1861, @@ -1106,14 +1314,6 @@ enum wmi_event_id { WMI_PCP_FACTOR_EVENTID = 0x191A, /* Power Save Configuration Events */ WMI_PS_DEV_PROFILE_CFG_EVENTID = 0x191C, - /* Not supported yet */ - WMI_PS_DEV_CFG_EVENTID = 0x191D, - /* Not supported yet */ - WMI_PS_DEV_CFG_READ_EVENTID = 0x191E, - /* Not supported yet */ - WMI_PS_MID_CFG_EVENTID = 0x191F, - /* Not supported yet */ - WMI_PS_MID_CFG_READ_EVENTID = 0x1920, WMI_RS_CFG_DONE_EVENTID = 0x1921, WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922, WMI_AOA_MEAS_EVENTID = 0x1923, @@ -1122,14 +1322,17 @@ enum wmi_event_id { WMI_GET_MGMT_RETRY_LIMIT_EVENTID = 0x1931, WMI_SET_THERMAL_THROTTLING_CFG_EVENTID = 0x1940, WMI_GET_THERMAL_THROTTLING_CFG_EVENTID = 0x1941, + /* return the Power Save profile */ + WMI_PS_DEV_PROFILE_CFG_READ_EVENTID = 0x1942, WMI_TOF_SESSION_END_EVENTID = 0x1991, WMI_TOF_GET_CAPABILITIES_EVENTID = 0x1992, WMI_TOF_SET_LCR_EVENTID = 0x1993, WMI_TOF_SET_LCI_EVENTID = 0x1994, WMI_TOF_FTM_PER_DEST_RES_EVENTID = 0x1995, - WMI_TOF_CHANNEL_INFO_EVENTID = 0x1996, + WMI_TOF_CFG_RESPONDER_EVENTID = 0x1996, WMI_TOF_SET_TX_RX_OFFSET_EVENTID = 0x1997, WMI_TOF_GET_TX_RX_OFFSET_EVENTID = 0x1998, + WMI_TOF_CHANNEL_INFO_EVENTID = 0x1999, WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A0, WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID = 0x19A1, WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID = 0x19A2, @@ -1138,12 +1341,18 @@ enum wmi_event_id { WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5, WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6, WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7, + WMI_SCHEDULING_SCHEME_EVENTID = 0x1A01, + WMI_FIXED_SCHEDULING_CONFIG_COMPLETE_EVENTID = 0x1A02, + WMI_ENABLE_FIXED_SCHEDULING_COMPLETE_EVENTID = 0x1A03, + WMI_SET_MULTI_DIRECTED_OMNIS_CONFIG_EVENTID = 0x1A04, + WMI_SET_LONG_RANGE_CONFIG_COMPLETE_EVENTID = 0x1A05, WMI_SET_CHANNEL_EVENTID = 0x9000, WMI_ASSOC_REQ_EVENTID = 0x9001, WMI_EAPOL_RX_EVENTID = 0x9002, WMI_MAC_ADDR_RESP_EVENTID = 0x9003, WMI_FW_VER_EVENTID = 0x9004, WMI_ACS_PASSIVE_SCAN_COMPLETE_EVENTID = 0x9005, + WMI_COMMAND_NOT_SUPPORTED_EVENTID = 0xFFFF, }; /* Events data structures */ @@ -1200,7 +1409,7 @@ struct wmi_fw_ver_event { __le32 bl_minor; __le32 bl_subminor; __le32 bl_build; - /* The number of entries in the FW capabilies array */ + /* The number of entries in the FW capabilities array */ u8 fw_capabilities_len; u8 reserved[3]; /* FW capabilities info @@ -1245,7 +1454,9 @@ struct wmi_get_rf_status_event { __le32 board_file_platform_type; /* board file version */ __le32 board_file_version; - __le32 reserved[2]; + /* enabled XIFs bit vector */ + __le32 enabled_xif_vector; + __le32 reserved; } __packed; /* WMI_GET_BASEBAND_TYPE_EVENTID */ @@ -1299,6 +1510,9 @@ struct wmi_ready_event { /* enum wmi_phy_capability */ u8 phy_capability; u8 numof_additional_mids; + /* rfc read calibration result. 5..15 */ + u8 rfc_read_calib_result; + u8 reserved[3]; } __packed; /* WMI_NOTIFY_REQ_DONE_EVENTID */ @@ -1306,7 +1520,8 @@ struct wmi_notify_req_done_event { /* beamforming status, 0: fail; 1: OK; 2: retrying */ __le32 status; __le64 tsf; - __le32 snr_val; + s8 rssi; + u8 reserved0[3]; __le32 tx_tpt; __le32 tx_goodput; __le32 rx_goodput; @@ -1576,7 +1791,7 @@ struct wmi_sw_tx_complete_event { u8 reserved[3]; } __packed; -/* WMI_CORR_MEASURE_EVENTID */ +/* WMI_CORR_MEASURE_EVENTID - deprecated */ struct wmi_corr_measure_event { /* signed */ __le32 i; @@ -1602,31 +1817,35 @@ struct wmi_get_ssid_event { /* wmi_rx_mgmt_info */ struct wmi_rx_mgmt_info { u8 mcs; - s8 snr; + s8 rssi; u8 range; u8 sqi; __le16 stype; __le16 status; __le32 len; - /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */ + /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */ u8 qid; - /* Not resolved when == 0xFFFFFFFF ==> Broadcast to all MIDS */ + /* Not resolved when == 0xFFFFFFFF == > Broadcast to all MIDS */ u8 mid; u8 cid; /* From Radio MNGR */ u8 channel; } __packed; -/* wmi_otp_read_write_cmd */ -struct wmi_otp_read_write_cmd { - __le32 addr; - __le32 size; - u8 values[0]; +/* EVENT: WMI_RF_XPM_READ_RESULT_EVENTID */ +struct wmi_rf_xpm_read_result_event { + /* enum wmi_fw_status_e - success=0 or fail=1 */ + u8 status; + u8 reserved[3]; + /* requested num_bytes of data */ + u8 data_bytes[0]; } __packed; -/* WMI_OTP_READ_RESULT_EVENTID */ -struct wmi_otp_read_result_event { - u8 payload[0]; +/* EVENT: WMI_RF_XPM_WRITE_RESULT_EVENTID */ +struct wmi_rf_xpm_write_result_event { + /* enum wmi_fw_status_e - success=0 or fail=1 */ + u8 status; + u8 reserved[3]; } __packed; /* WMI_TX_MGMT_PACKET_EVENTID */ @@ -1645,6 +1864,20 @@ struct wmi_echo_rsp_event { __le32 echoed_value; } __packed; +/* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */ +struct wmi_rf_pwr_on_delay_rsp_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_SET_HIGH_POWER_TABLE_PARAMS_EVENTID */ +struct wmi_set_high_power_table_params_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* WMI_TEMP_SENSE_DONE_EVENTID * * Measure MAC and radio temperatures @@ -1722,14 +1955,22 @@ struct wmi_led_cfg_cmd { u8 reserved; } __packed; +/* \WMI_SET_CONNECT_SNR_THR_CMDID */ +struct wmi_set_connect_snr_thr_cmd { + u8 enable; + u8 reserved; + /* 1/4 Db units */ + __le16 omni_snr_thr; + /* 1/4 Db units */ + __le16 direct_snr_thr; +} __packed; + /* WMI_LED_CFG_DONE_EVENTID */ struct wmi_led_cfg_done_event { /* led config status */ __le32 status; } __packed; -#define WMI_NUM_MCS (13) - /* Rate search parameters configuration per connection */ struct wmi_rs_cfg { /* The maximal allowed PER for each MCS @@ -1754,6 +1995,98 @@ struct wmi_rs_cfg { __le32 mcs_en_vec; } __packed; +/* Slot types */ +enum wmi_sched_scheme_slot_type { + WMI_SCHED_SLOT_SP = 0x0, + WMI_SCHED_SLOT_CBAP = 0x1, + WMI_SCHED_SLOT_IDLE = 0x2, + WMI_SCHED_SLOT_ANNOUNCE_NO_ACK = 0x3, + WMI_SCHED_SLOT_DISCOVERY = 0x4, +}; + +enum wmi_sched_scheme_slot_flags { + WMI_SCHED_SCHEME_SLOT_PERIODIC = 0x1, +}; + +struct wmi_sched_scheme_slot { + /* in microsecond */ + __le32 tbtt_offset; + /* wmi_sched_scheme_slot_flags */ + u8 flags; + /* wmi_sched_scheme_slot_type */ + u8 type; + /* in microsecond */ + __le16 duration; + /* frame_exchange_sequence_duration */ + __le16 tx_op; + /* time in microseconds between two consecutive slots + * relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set + */ + __le16 period; + /* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set + * number of times to repeat allocation + */ + u8 num_of_blocks; + /* relevant only if flag WMI_SCHED_SCHEME_SLOT_PERIODIC set + * every idle_period allocation will be idle + */ + u8 idle_period; + u8 src_aid; + u8 dest_aid; + __le32 reserved; +} __packed; + +enum wmi_sched_scheme_flags { + /* should not be set when clearing scheduling scheme */ + WMI_SCHED_SCHEME_ENABLE = 0x01, + WMI_SCHED_PROTECTED_SP = 0x02, + /* should be set only on first WMI fragment of scheme */ + WMI_SCHED_FIRST = 0x04, + /* should be set only on last WMI fragment of scheme */ + WMI_SCHED_LAST = 0x08, + WMI_SCHED_IMMEDIATE_START = 0x10, +}; + +enum wmi_sched_scheme_advertisment { + /* ESE is not advertised at all, STA has to be configured with WMI + * also + */ + WMI_ADVERTISE_ESE_DISABLED = 0x0, + WMI_ADVERTISE_ESE_IN_BEACON = 0x1, + WMI_ADVERTISE_ESE_IN_ANNOUNCE_FRAME = 0x2, +}; + +/* WMI_SCHEDULING_SCHEME_CMD */ +struct wmi_scheduling_scheme_cmd { + u8 serial_num; + /* wmi_sched_scheme_advertisment */ + u8 ese_advertisment; + /* wmi_sched_scheme_flags */ + __le16 flags; + u8 num_allocs; + u8 reserved[3]; + __le64 start_tbtt; + /* allocations list */ + struct wmi_sched_scheme_slot allocs[WMI_SCHED_MAX_ALLOCS_PER_CMD]; +} __packed; + +enum wmi_sched_scheme_failure_type { + WMI_SCHED_SCHEME_FAILURE_NO_ERROR = 0x00, + WMI_SCHED_SCHEME_FAILURE_OLD_START_TSF_ERR = 0x01, +}; + +/* WMI_SCHEDULING_SCHEME_EVENTID */ +struct wmi_scheduling_scheme_event { + /* wmi_fw_status_e */ + u8 status; + /* serial number given in command */ + u8 serial_num; + /* wmi_sched_scheme_failure_type */ + u8 failure_type; + /* alignment to 32b */ + u8 reserved[1]; +} __packed; + /* WMI_RS_CFG_CMDID */ struct wmi_rs_cfg_cmd { /* connection id */ @@ -1971,6 +2304,19 @@ enum wmi_ps_profile_type { WMI_PS_PROFILE_TYPE_LOW_LATENCY_PS = 0x03, }; +/* WMI_PS_DEV_PROFILE_CFG_READ_CMDID */ +struct wmi_ps_dev_profile_cfg_read_cmd { + /* reserved */ + __le32 reserved; +} __packed; + +/* WMI_PS_DEV_PROFILE_CFG_READ_EVENTID */ +struct wmi_ps_dev_profile_cfg_read_event { + /* wmi_ps_profile_type_e */ + u8 ps_profile; + u8 reserved[3]; +} __packed; + /* WMI_PS_DEV_PROFILE_CFG_CMDID * * Power save profile to be used by the device @@ -2019,157 +2365,6 @@ enum wmi_ps_d3_resp_policy { WMI_PS_D3_RESP_POLICY_APPROVED = 0x02, }; -/* Device common power save configurations */ -struct wmi_ps_dev_cfg { - /* lowest level of PS allowed while unassociated, enum wmi_ps_level_e - */ - u8 ps_unassoc_min_level; - /* lowest deep sleep clock level while nonassoc, enum - * wmi_ps_deep_sleep_clk_level_e - */ - u8 ps_unassoc_deep_sleep_min_level; - /* lowest level of PS allowed while associated, enum wmi_ps_level_e */ - u8 ps_assoc_min_level; - /* lowest deep sleep clock level while assoc, enum - * wmi_ps_deep_sleep_clk_level_e - */ - u8 ps_assoc_deep_sleep_min_level; - /* enum wmi_ps_deep_sleep_clk_level_e */ - u8 ps_assoc_low_latency_ds_min_level; - /* enum wmi_ps_d3_resp_policy_e */ - u8 ps_D3_response_policy; - /* BOOL */ - u8 ps_D3_pm_pme_enabled; - /* BOOL */ - u8 ps_halp_enable; - u8 ps_deep_sleep_enter_thresh_msec; - /* BOOL */ - u8 ps_voltage_scaling_en; -} __packed; - -/* WMI_PS_DEV_CFG_CMDID - * - * Configure common Power Save parameters of the device and all MIDs. - * - * Returned event: - * - WMI_PS_DEV_CFG_EVENTID - */ -struct wmi_ps_dev_cfg_cmd { - /* Device Power Save configuration to be applied */ - struct wmi_ps_dev_cfg ps_dev_cfg; - /* alignment to 32b */ - u8 reserved[2]; -} __packed; - -/* WMI_PS_DEV_CFG_EVENTID */ -struct wmi_ps_dev_cfg_event { - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; -} __packed; - -/* WMI_PS_DEV_CFG_READ_CMDID - * - * request to retrieve device Power Save configuration - * (WMI_PS_DEV_CFG_CMD params) - * - * Returned event: - * - WMI_PS_DEV_CFG_READ_EVENTID - */ -struct wmi_ps_dev_cfg_read_cmd { - __le32 reserved; -} __packed; - -/* WMI_PS_DEV_CFG_READ_EVENTID */ -struct wmi_ps_dev_cfg_read_event { - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; - /* Retrieved device Power Save configuration (WMI_PS_DEV_CFG_CMD - * params) - */ - struct wmi_ps_dev_cfg dev_ps_cfg; - /* alignment to 32b */ - u8 reserved[2]; -} __packed; - -/* Per Mac Power Save configurations */ -struct wmi_ps_mid_cfg { - /* Low power RX in BTI is enabled, BOOL */ - u8 beacon_lprx_enable; - /* Sync to sector ID enabled, BOOL */ - u8 beacon_sync_to_sectorId_enable; - /* Low power RX in DTI is enabled, BOOL */ - u8 frame_exchange_lprx_enable; - /* Sleep Cycle while in scheduled PS, 1-31 */ - u8 scheduled_sleep_cycle_pow2; - /* Stay Awake for k BIs every (sleep_cycle - k) BIs, 1-31 */ - u8 scheduled_num_of_awake_bis; - u8 am_to_traffic_load_thresh_mbp; - u8 traffic_to_am_load_thresh_mbps; - u8 traffic_to_am_num_of_no_traffic_bis; - /* BOOL */ - u8 continuous_traffic_psm; - __le16 no_traffic_to_min_usec; - __le16 no_traffic_to_max_usec; - __le16 snoozing_sleep_interval_milisec; - u8 max_no_data_awake_events; - /* Trigger WEB after k failed beacons */ - u8 num_of_failed_beacons_rx_to_trigger_web; - /* Trigger BF after k failed beacons */ - u8 num_of_failed_beacons_rx_to_trigger_bf; - /* Trigger SOB after k successful beacons */ - u8 num_of_successful_beacons_rx_to_trigger_sob; -} __packed; - -/* WMI_PS_MID_CFG_CMDID - * - * Configure Power Save parameters of a specific MID. - * These parameters are relevant for the specific BSS this MID belongs to. - * - * Returned event: - * - WMI_PS_MID_CFG_EVENTID - */ -struct wmi_ps_mid_cfg_cmd { - /* MAC ID */ - u8 mid; - /* mid PS configuration to be applied */ - struct wmi_ps_mid_cfg ps_mid_cfg; -} __packed; - -/* WMI_PS_MID_CFG_EVENTID */ -struct wmi_ps_mid_cfg_event { - /* MAC ID */ - u8 mid; - /* alignment to 32b */ - u8 reserved[3]; - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; -} __packed; - -/* WMI_PS_MID_CFG_READ_CMDID - * - * request to retrieve Power Save configuration of mid - * (WMI_PS_MID_CFG_CMD params) - * - * Returned event: - * - WMI_PS_MID_CFG_READ_EVENTID - */ -struct wmi_ps_mid_cfg_read_cmd { - /* MAC ID */ - u8 mid; - /* alignment to 32b */ - u8 reserved[3]; -} __packed; - -/* WMI_PS_MID_CFG_READ_EVENTID */ -struct wmi_ps_mid_cfg_read_event { - /* MAC ID */ - u8 mid; - /* Retrieved MID Power Save configuration(WMI_PS_MID_CFG_CMD params) */ - struct wmi_ps_mid_cfg mid_ps_cfg; - /* wmi_ps_cfg_cmd_status_e */ - __le32 status; -} __packed; - #define WMI_AOA_MAX_DATA_SIZE (128) enum wmi_aoa_meas_status { @@ -2260,6 +2455,20 @@ struct wmi_tof_session_end_event { u8 reserved[3]; } __packed; +/* WMI_TOF_SET_LCI_EVENTID */ +struct wmi_tof_set_lci_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_TOF_SET_LCR_EVENTID */ +struct wmi_tof_set_lcr_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + /* Responder FTM Results */ struct wmi_responder_ftm_res { u8 t1[6]; @@ -2313,10 +2522,19 @@ struct wmi_tof_ftm_per_dest_res_event { __le32 tsf_sync; /* actual received ftm per burst */ u8 actual_ftm_per_burst; - u8 reserved0[7]; + /* Measurments are from RFs, defined by the mask */ + __le32 meas_rf_mask; + u8 reserved0[3]; struct wmi_responder_ftm_res responder_ftm_res[0]; } __packed; +/* WMI_TOF_CFG_RESPONDER_EVENTID */ +struct wmi_tof_cfg_responder_event { + /* enum wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + enum wmi_tof_channel_info_type { WMI_TOF_CHANNEL_INFO_AOA = 0x00, WMI_TOF_CHANNEL_INFO_LCI = 0x01, @@ -2353,12 +2571,15 @@ struct wmi_tof_set_tx_rx_offset_event { struct wmi_tof_get_tx_rx_offset_event { /* enum wmi_fw_status */ u8 status; - u8 reserved1[3]; + /* RF index used to read the offsets */ + u8 rf_index; + u8 reserved1[2]; /* TX delay offset */ __le32 tx_offset; /* RX delay offset */ __le32 rx_offset; - __le32 reserved2[2]; + /* Offset to strongest tap of CIR */ + __le32 precursor; } __packed; /* Result status codes for WMI commands */ @@ -2621,4 +2842,23 @@ struct wmi_prio_tx_sectors_set_default_cfg_event { u8 reserved[3]; } __packed; +/* WMI_SET_SILENT_RSSI_TABLE_DONE_EVENTID */ +struct wmi_set_silent_rssi_table_done_event { + /* enum wmi_silent_rssi_status */ + __le32 status; + /* enum wmi_silent_rssi_table */ + __le32 table; +} __packed; + +/* \WMI_COMMAND_NOT_SUPPORTED_EVENTID */ +struct wmi_command_not_supported_event { + /* device id */ + u8 mid; + u8 reserved0; + __le16 command_id; + /* for UT command only, otherwise reserved */ + __le16 command_subtype; + __le16 reserved1; +} __packed; + #endif /* __WILOCITY_WMI_H__ */ diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 09defbcedd5e..94bf01f8b2a8 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -130,7 +130,7 @@ MODULE_FIRMWARE("atmel_at76c505amx-rfmd.bin"); #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) -static struct usb_device_id dev_table[] = { +static const struct usb_device_id dev_table[] = { /* * at76c503-i3861 */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 984c1d0560b1..cd587325e286 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1105,6 +1105,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373), { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 7e689c86d565..aaed4ab503ad 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -3940,6 +3940,7 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) { s32 err; + s32 wpa_val; /* set auth */ err = brcmf_fil_bsscfg_int_set(ifp, "auth", 0); @@ -3954,7 +3955,11 @@ static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) return err; } /* set upper-layer auth */ - err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", WPA_AUTH_NONE); + if (brcmf_is_ibssmode(ifp->vif)) + wpa_val = WPA_AUTH_NONE; + else + wpa_val = WPA_AUTH_DISABLED; + err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_val); if (err < 0) { brcmf_err("wpa_auth error %d\n", err); return err; @@ -5693,10 +5698,13 @@ brcmf_notify_roaming_status(struct brcmf_if *ifp, u32 status = e->status; if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { - if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) + if (test_bit(BRCMF_VIF_STATUS_CONNECTED, + &ifp->vif->sme_state)) { brcmf_bss_roaming_done(cfg, ifp->ndev, e); - else + } else { brcmf_bss_connect_done(cfg, ifp->ndev, e, true); + brcmf_net_setcarrier(ifp, true); + } } return 0; @@ -6456,6 +6464,8 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) if (p2p) { if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) combo[c].num_different_channels = 2; + else + combo[c].num_different_channels = 1; wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); @@ -6465,10 +6475,10 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); } else { + combo[c].num_different_channels = 1; c0_limits[i].max = 1; c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); } - combo[c].num_different_channels = 1; combo[c].max_interfaces = i; combo[c].n_limits = i; combo[c].limits = c0_limits; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 05f22ff81d60..c5d1a1cbf601 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -690,6 +690,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_4365_CHIP_ID: case BRCM_CC_4366_CHIP_ID: return 0x200000; + case CY_CC_4373_CHIP_ID: + return 0x160000; default: brcmf_err("unknown chip: %s\n", ci->pub.name); break; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c index 1447a8352383..2d3e5e263a32 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c @@ -78,10 +78,7 @@ int brcmf_debug_attach(struct brcmf_pub *drvr) return -ENODEV; drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); - if (IS_ERR(drvr->dbgfs_dir)) - return PTR_ERR(drvr->dbgfs_dir); - - return 0; + return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); } void brcmf_debug_detach(struct brcmf_pub *drvr) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index d231042f19d6..091b52979e03 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -601,6 +601,9 @@ int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, if ((nvram_name) && (mapping_table[i].nvram)) strlcat(nvram_name, mapping_table[i].nvram, BRCMF_FW_NAME_LEN); + brcmf_info("using %s for chip %#08x(%d) rev %#08x\n", + fw_name, chip, chip, chiprev); + return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index f878706613e6..e6e9b00b79d7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1951,7 +1951,7 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } -static struct pci_device_id brcmf_pcie_devid_table[] = { +static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_4356_DEVICE_ID), BRCMF_PCIE_DEVICE(BRCM_PCIE_43567_DEVICE_ID), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index f3556122c6ac..613caca7dc02 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -618,6 +618,7 @@ BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt"); BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt"); BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt"); +BRCMF_FW_NVRAM_DEF(4373, "brcmfmac4373-sdio.bin", "brcmfmac4373-sdio.txt"); static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), @@ -636,7 +637,8 @@ static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356) + BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), + BRCMF_FW_NVRAM_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373) }; static void pkt_align(struct sk_buff *p, int len, int align) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 0eea48e73331..11ffaa01599e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -50,6 +50,7 @@ BRCMF_FW_DEF(43143, "brcmfmac43143.bin"); BRCMF_FW_DEF(43236B, "brcmfmac43236b.bin"); BRCMF_FW_DEF(43242A, "brcmfmac43242a.bin"); BRCMF_FW_DEF(43569, "brcmfmac43569.bin"); +BRCMF_FW_DEF(4373, "brcmfmac4373.bin"); static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), @@ -58,7 +59,8 @@ static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43238_CHIP_ID, 0x00000008, 43236B), BRCMF_FW_ENTRY(BRCM_CC_43242_CHIP_ID, 0xFFFFFFFF, 43242A), BRCMF_FW_ENTRY(BRCM_CC_43566_CHIP_ID, 0xFFFFFFFF, 43569), - BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43569) + BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43569), + BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373) }; #define TRX_MAGIC 0x30524448 /* "HDR0" */ @@ -1463,15 +1465,20 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf) #define LINKSYS_USB_DEVICE(dev_id) \ { USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id) } -static struct usb_device_id brcmf_usb_devid_table[] = { +#define CYPRESS_USB_DEVICE(dev_id) \ + { USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, dev_id) } + +static const struct usb_device_id brcmf_usb_devid_table[] = { BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID), BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID), BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID), BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID), LINKSYS_USB_DEVICE(BRCM_USB_43235_LINKSYS_DEVICE_ID), + CYPRESS_USB_DEVICE(CY_USB_4373_DEVICE_ID), { USB_DEVICE(BRCM_USB_VENDOR_ID_LG, BRCM_USB_43242_LG_DEVICE_ID) }, /* special entry for device with firmware loaded and running */ BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID), + CYPRESS_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index f1fb8a3c7a32..57544a3a3ce4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -23,6 +23,7 @@ #define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c #define BRCM_USB_VENDOR_ID_LG 0x043e #define BRCM_USB_VENDOR_ID_LINKSYS 0x13b1 +#define CY_USB_VENDOR_ID_CYPRESS 0x04b4 #define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM /* Chipcommon Core Chip IDs */ @@ -57,6 +58,7 @@ #define BRCM_CC_4365_CHIP_ID 0x4365 #define BRCM_CC_4366_CHIP_ID 0x4366 #define BRCM_CC_4371_CHIP_ID 0x4371 +#define CY_CC_4373_CHIP_ID 0x4373 /* USB Device IDs */ #define BRCM_USB_43143_DEVICE_ID 0xbd1e @@ -66,6 +68,7 @@ #define BRCM_USB_43242_LG_DEVICE_ID 0x3101 #define BRCM_USB_43569_DEVICE_ID 0xbd27 #define BRCM_USB_BCMFW_DEVICE_ID 0x0bdc +#define CY_USB_4373_DEVICE_ID 0xbd29 /* PCIE Device IDs */ #define BRCM_PCIE_4350_DEVICE_ID 0x43a3 diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index 84143a02adce..54201c02fdb8 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -7837,7 +7837,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { struct airo_info *ai = dev->ml_priv; int ridcode; int enabled; - static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); + int (*writer)(struct airo_info *, u16 rid, const void *, int, int); unsigned char *iobuf; /* Only super-user can write RIDs */ diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index aaaca4d08e2b..19c442cb93e4 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -340,7 +340,7 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw); static void ipw2100_wx_event_work(struct work_struct *work); static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev); -static struct iw_handler_def ipw2100_wx_handler_def; +static const struct iw_handler_def ipw2100_wx_handler_def; static inline void read_register(struct net_device *dev, u32 reg, u32 * val) { @@ -1724,7 +1724,7 @@ static const struct libipw_geo ipw_geos[] = { static int ipw2100_up(struct ipw2100_priv *priv, int deferred) { unsigned long flags; - int rc = 0; + int err = 0; u32 lock; u32 ord_len = sizeof(lock); @@ -1757,33 +1757,33 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) if (priv->status & STATUS_POWERED || (priv->status & STATUS_RESET_PENDING)) { /* Power cycle the card ... */ - if (ipw2100_power_cycle_adapter(priv)) { + err = ipw2100_power_cycle_adapter(priv); + if (err) { printk(KERN_WARNING DRV_NAME ": %s: Could not cycle adapter.\n", priv->net_dev->name); - rc = 1; goto exit; } } else priv->status |= STATUS_POWERED; /* Load the firmware, start the clocks, etc. */ - if (ipw2100_start_adapter(priv)) { + err = ipw2100_start_adapter(priv); + if (err) { printk(KERN_ERR DRV_NAME ": %s: Failed to start the firmware.\n", priv->net_dev->name); - rc = 1; goto exit; } ipw2100_initialize_ordinals(priv); /* Determine capabilities of this particular HW configuration */ - if (ipw2100_get_hw_features(priv)) { + err = ipw2100_get_hw_features(priv); + if (err) { printk(KERN_ERR DRV_NAME ": %s: Failed to determine HW features.\n", priv->net_dev->name); - rc = 1; goto exit; } @@ -1792,11 +1792,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) priv->ieee->freq_band = LIBIPW_24GHZ_BAND; lock = LOCK_NONE; - if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { + err = ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len); + if (err) { printk(KERN_ERR DRV_NAME ": %s: Failed to clear ordinal lock.\n", priv->net_dev->name); - rc = 1; goto exit; } @@ -1820,21 +1820,21 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) /* Send all of the commands that must be sent prior to * HOST_COMPLETE */ - if (ipw2100_adapter_setup(priv)) { + err = ipw2100_adapter_setup(priv); + if (err) { printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n", priv->net_dev->name); - rc = 1; goto exit; } if (!deferred) { /* Enable the adapter - sends HOST_COMPLETE */ - if (ipw2100_enable_adapter(priv)) { + err = ipw2100_enable_adapter(priv); + if (err) { printk(KERN_ERR DRV_NAME ": " "%s: failed in call to enable adapter.\n", priv->net_dev->name); ipw2100_hw_stop_adapter(priv); - rc = 1; goto exit; } @@ -1844,7 +1844,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) } exit: - return rc; + return err; } static void ipw2100_down(struct ipw2100_priv *priv) @@ -4324,7 +4324,7 @@ static struct attribute *ipw2100_sysfs_entries[] = { NULL, }; -static struct attribute_group ipw2100_attribute_group = { +static const struct attribute_group ipw2100_attribute_group = { .attrs = ipw2100_sysfs_entries, }; @@ -8273,7 +8273,7 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev) return (struct iw_statistics *)NULL; } -static struct iw_handler_def ipw2100_wx_handler_def = { +static const struct iw_handler_def ipw2100_wx_handler_def = { .standard = ipw2100_wx_handlers, .num_standard = ARRAY_SIZE(ipw2100_wx_handlers), .num_private = ARRAY_SIZE(ipw2100_private_handler), diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 9368abdf18e2..8da87496cb58 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -3209,7 +3209,7 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) struct fw_chunk *chunk; int total_nr = 0; int i; - struct pci_pool *pool; + struct dma_pool *pool; void **virts; dma_addr_t *phys; @@ -3226,9 +3226,10 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) kfree(virts); return -ENOMEM; } - pool = pci_pool_create("ipw2200", priv->pci_dev, CB_MAX_LENGTH, 0, 0); + pool = dma_pool_create("ipw2200", &priv->pci_dev->dev, CB_MAX_LENGTH, 0, + 0); if (!pool) { - IPW_ERROR("pci_pool_create failed\n"); + IPW_ERROR("dma_pool_create failed\n"); kfree(phys); kfree(virts); return -ENOMEM; @@ -3253,7 +3254,7 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) nr = (chunk_len + CB_MAX_LENGTH - 1) / CB_MAX_LENGTH; for (i = 0; i < nr; i++) { - virts[total_nr] = pci_pool_alloc(pool, GFP_KERNEL, + virts[total_nr] = dma_pool_alloc(pool, GFP_KERNEL, &phys[total_nr]); if (!virts[total_nr]) { ret = -ENOMEM; @@ -3297,9 +3298,9 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) } out: for (i = 0; i < total_nr; i++) - pci_pool_free(pool, virts[i], phys[i]); + dma_pool_free(pool, virts[i], phys[i]); - pci_pool_destroy(pool); + dma_pool_destroy(pool); kfree(phys); kfree(virts); @@ -10008,7 +10009,7 @@ static iw_handler ipw_priv_handler[] = { #endif }; -static struct iw_handler_def ipw_wx_handler_def = { +static const struct iw_handler_def ipw_wx_handler_def = { .standard = ipw_wx_handlers, .num_standard = ARRAY_SIZE(ipw_wx_handlers), .num_private = ARRAY_SIZE(ipw_priv_handler), @@ -11500,7 +11501,7 @@ static struct attribute *ipw_sysfs_entries[] = { NULL }; -static struct attribute_group ipw_attribute_group = { +static const struct attribute_group ipw_attribute_group = { .name = NULL, /* put in device directory */ .attrs = ipw_sysfs_entries, }; diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 38bf403bb1e1..329f3a63dadd 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3464,7 +3464,7 @@ static struct attribute *il3945_sysfs_entries[] = { NULL }; -static struct attribute_group il3945_attribute_group = { +static const struct attribute_group il3945_attribute_group = { .name = NULL, /* put in device directory */ .attrs = il3945_sysfs_entries, }; diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 5b51fba75595..de9b6522c43f 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4654,7 +4654,7 @@ static struct attribute *il_sysfs_entries[] = { NULL }; -static struct attribute_group il_attribute_group = { +static const struct attribute_group il_attribute_group = { .name = NULL, /* put in device directory */ .attrs = il_sysfs_entries, }; diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 20bd261223af..35a32a3ec882 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -11,6 +11,8 @@ iwlwifi-$(CONFIG_IWLDVM) += cfg/1000.o cfg/2000.o cfg/5000.o cfg/6000.o iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/a000.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += fw/notif-wait.o +iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o +iwlwifi-$(CONFIG_IWLMVM) += fw/common_rx.o fw/nvm.o iwlwifi-objs += $(iwlwifi-m) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c index 5081720608af..2e6c52664cee 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c @@ -70,8 +70,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 33 -#define IWL8265_UCODE_API_MAX 33 +#define IWL8000_UCODE_API_MAX 34 +#define IWL8265_UCODE_API_MAX 34 /* Lowest firmware API version supported */ #define IWL8000_UCODE_API_MIN 22 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 97208ce19f92..2babe0a1f18b 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 33 +#define IWL9000_UCODE_API_MAX 34 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c index 98f24cd1b44f..76ba1f8bc72f 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/a000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/a000.c @@ -55,7 +55,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL_A000_UCODE_API_MAX 33 +#define IWL_A000_UCODE_API_MAX 34 /* Lowest firmware API version supported */ #define IWL_A000_UCODE_API_MIN 24 @@ -75,11 +75,20 @@ #define IWL_A000_JF_FW_PRE "iwlwifi-Qu-a0-jf-b0-" #define IWL_A000_HR_FW_PRE "iwlwifi-Qu-a0-hr-a0-" #define IWL_A000_HR_CDB_FW_PRE "iwlwifi-QuIcp-z0-hrcdb-a0-" +#define IWL_A000_HR_F0_FW_PRE "iwlwifi-QuQnj-f0-hr-a0-" +#define IWL_A000_JF_B0_FW_PRE "iwlwifi-QuQnj-a0-jf-b0-" +#define IWL_A000_HR_A0_FW_PRE "iwlwifi-QuQnj-a0-hr-a0-" #define IWL_A000_HR_MODULE_FIRMWARE(api) \ IWL_A000_HR_FW_PRE "-" __stringify(api) ".ucode" #define IWL_A000_JF_MODULE_FIRMWARE(api) \ IWL_A000_JF_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_A000_HR_F0_QNJ_MODULE_FIRMWARE(api) \ + IWL_A000_HR_F0_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_A000_JF_B0_QNJ_MODULE_FIRMWARE(api) \ + IWL_A000_JF_B0_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_A000_HR_A0_QNJ_MODULE_FIRMWARE(api) \ + IWL_A000_HR_A0_FW_PRE "-" __stringify(api) ".ucode" #define NVM_HW_SECTION_NUM_FAMILY_A000 10 @@ -168,5 +177,38 @@ const struct iwl_cfg iwla000_2ax_cfg_hr = { .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, }; +const struct iwl_cfg iwla000_2ax_cfg_qnj_hr_f0 = { + .name = "Intel(R) Dual Band Wireless AX a000", + .fw_name_pre = IWL_A000_HR_F0_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwla000_2ax_cfg_qnj_jf_b0 = { + .name = "Intel(R) Dual Band Wireless AX a000", + .fw_name_pre = IWL_A000_JF_B0_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + +const struct iwl_cfg iwla000_2ax_cfg_qnj_hr_a0 = { + .name = "Intel(R) Dual Band Wireless AX a000", + .fw_name_pre = IWL_A000_HR_A0_FW_PRE, + IWL_DEVICE_A000, + .ht_params = &iwl_a000_ht_params, + .nvm_ver = IWL_A000_NVM_VERSION, + .nvm_calib_ver = IWL_A000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, +}; + MODULE_FIRMWARE(IWL_A000_HR_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_A000_JF_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_A000_HR_F0_QNJ_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_A000_JF_B0_QNJ_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_A000_HR_A0_QNJ_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h index 2ab2773655a8..f89736d60a3d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h @@ -311,11 +311,6 @@ enum { /** * rate_n_flags Tx antenna masks - * 4965 has 2 transmitters - * 5100 has 1 transmitter B - * 5150 has 1 transmitter A - * 5300 has 3 transmitters - * 5350 has 3 transmitters * bit14:16 */ #define RATE_MCS_ANT_POS 14 @@ -1230,7 +1225,6 @@ struct iwl_rx_mpdu_res_start { */ /* - * 4965 uCode updates these Tx attempt count values in host DRAM. * Used for managing Tx retries when expecting block-acks. * Driver should set these fields to 0. */ @@ -1437,22 +1431,6 @@ struct agg_tx_status { __le16 sequence; } __packed; -/* - * definitions for initial rate index field - * bits [3:0] initial rate index - * bits [6:4] rate table color, used for the initial rate - * bit-7 invalid rate indication - * i.e. rate was not chosen from rate table - * or rate table color was changed during frame retries - * refer tlc rate info - */ - -#define IWL50_TX_RES_INIT_RATE_INDEX_POS 0 -#define IWL50_TX_RES_INIT_RATE_INDEX_MSK 0x0f -#define IWL50_TX_RES_RATE_TABLE_COLOR_POS 4 -#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK 0x70 -#define IWL50_TX_RES_INV_RATE_INDEX_MSK 0x80 - /* refer to ra_tid */ #define IWLAGN_TX_RES_TID_POS 0 #define IWLAGN_TX_RES_TID_MSK 0x0f @@ -1556,7 +1534,7 @@ struct iwl_link_qual_general_params { /* Best single antenna to use for single stream (legacy, SISO). */ u8 single_stream_ant_msk; /* LINK_QUAL_ANT_* */ - /* Best antennas to use for MIMO (unused for 4965, assumes both). */ + /* Best antennas to use for MIMO */ u8 dual_stream_ant_msk; /* LINK_QUAL_ANT_* */ /* diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h new file mode 100644 index 000000000000..3684a3e180e5 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h @@ -0,0 +1,206 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_alive_h__ +#define __iwl_fw_api_alive_h__ + +/* alive response is_valid values */ +#define ALIVE_RESP_UCODE_OK BIT(0) +#define ALIVE_RESP_RFKILL BIT(1) + +/* alive response ver_type values */ +enum { + FW_TYPE_HW = 0, + FW_TYPE_PROT = 1, + FW_TYPE_AP = 2, + FW_TYPE_WOWLAN = 3, + FW_TYPE_TIMING = 4, + FW_TYPE_WIPAN = 5 +}; + +/* alive response ver_subtype values */ +enum { + FW_SUBTYPE_FULL_FEATURE = 0, + FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */ + FW_SUBTYPE_REDUCED = 2, + FW_SUBTYPE_ALIVE_ONLY = 3, + FW_SUBTYPE_WOWLAN = 4, + FW_SUBTYPE_AP_SUBTYPE = 5, + FW_SUBTYPE_WIPAN = 6, + FW_SUBTYPE_INITIALIZE = 9 +}; + +#define IWL_ALIVE_STATUS_ERR 0xDEAD +#define IWL_ALIVE_STATUS_OK 0xCAFE + +#define IWL_ALIVE_FLG_RFKILL BIT(0) + +struct iwl_lmac_alive { + __le32 ucode_minor; + __le32 ucode_major; + u8 ver_subtype; + u8 ver_type; + u8 mac; + u8 opt; + __le32 timestamp; + __le32 error_event_table_ptr; /* SRAM address for error log */ + __le32 log_event_table_ptr; /* SRAM address for LMAC event log */ + __le32 cpu_register_ptr; + __le32 dbgm_config_ptr; + __le32 alive_counter_ptr; + __le32 scd_base_ptr; /* SRAM address for SCD */ + __le32 st_fwrd_addr; /* pointer to Store and forward */ + __le32 st_fwrd_size; +} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_3 */ + +struct iwl_umac_alive { + __le32 umac_minor; /* UMAC version: minor */ + __le32 umac_major; /* UMAC version: major */ + __le32 error_info_addr; /* SRAM address for UMAC error log */ + __le32 dbg_print_buff_addr; +} __packed; /* UMAC_ALIVE_DATA_API_S_VER_2 */ + +struct mvm_alive_resp_v3 { + __le16 status; + __le16 flags; + struct iwl_lmac_alive lmac_data; + struct iwl_umac_alive umac_data; +} __packed; /* ALIVE_RES_API_S_VER_3 */ + +struct mvm_alive_resp { + __le16 status; + __le16 flags; + struct iwl_lmac_alive lmac_data[2]; + struct iwl_umac_alive umac_data; +} __packed; /* ALIVE_RES_API_S_VER_4 */ + +/** + * enum iwl_extended_cfg_flag - commands driver may send before + * finishing init flow + * @IWL_INIT_DEBUG_CFG: driver is going to send debug config command + * @IWL_INIT_NVM: driver is going to send NVM_ACCESS commands + * @IWL_INIT_PHY: driver is going to send PHY_DB commands + */ +enum iwl_extended_cfg_flags { + IWL_INIT_DEBUG_CFG, + IWL_INIT_NVM, + IWL_INIT_PHY, +}; + +/** + * struct iwl_extended_cfg_cmd - mark what commands ucode should wait for + * before finishing init flows + * @init_flags: values from iwl_extended_cfg_flags + */ +struct iwl_init_extended_cfg_cmd { + __le32 init_flags; +} __packed; /* INIT_EXTENDED_CFG_CMD_API_S_VER_1 */ + +/** + * struct iwl_radio_version_notif - information on the radio version + * ( RADIO_VERSION_NOTIFICATION = 0x68 ) + * @radio_flavor: radio flavor + * @radio_step: radio version step + * @radio_dash: radio version dash + */ +struct iwl_radio_version_notif { + __le32 radio_flavor; + __le32 radio_step; + __le32 radio_dash; +} __packed; /* RADIO_VERSION_NOTOFICATION_S_VER_1 */ + +enum iwl_card_state_flags { + CARD_ENABLED = 0x00, + HW_CARD_DISABLED = 0x01, + SW_CARD_DISABLED = 0x02, + CT_KILL_CARD_DISABLED = 0x04, + HALT_CARD_DISABLED = 0x08, + CARD_DISABLED_MSK = 0x0f, + CARD_IS_RX_ON = 0x10, +}; + +/** + * struct iwl_radio_version_notif - information on the card state + * ( CARD_STATE_NOTIFICATION = 0xa1 ) + * @flags: &enum iwl_card_state_flags + */ +struct iwl_card_state_notif { + __le32 flags; +} __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ + +/** + * struct iwl_fseq_ver_mismatch_nty - Notification about version + * + * This notification does not have a direct impact on the init flow. + * It means that another core (not WiFi) has initiated the FSEQ flow + * and updated the FSEQ version. The driver only prints an error when + * this occurs. + * + * @aux_read_fseq_ver: auxiliary read FSEQ version + * @wifi_fseq_ver: FSEQ version (embedded in WiFi) + */ +struct iwl_fseq_ver_mismatch_ntf { + __le32 aux_read_fseq_ver; + __le32 wifi_fseq_ver; +} __packed; /* FSEQ_VER_MISMATCH_NTFY_API_S_VER_1 */ + +#endif /* __iwl_fw_api_alive_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h new file mode 100644 index 000000000000..d2717fafdf5b --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/binding.h @@ -0,0 +1,144 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_binding_h__ +#define __iwl_fw_api_binding_h__ + +#define MAX_MACS_IN_BINDING (3) +#define MAX_BINDINGS (4) + +/** + * struct iwl_binding_cmd_v1 - configuring bindings + * ( BINDING_CONTEXT_CMD = 0x2b ) + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_ctxt_id_and_color + * @action: action to perform, one of FW_CTXT_ACTION_* + * @macs: array of MAC id and colors which belong to the binding, + * &enum iwl_ctxt_id_and_color + * @phy: PHY id and color which belongs to the binding, + * &enum iwl_ctxt_id_and_color + */ +struct iwl_binding_cmd_v1 { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + /* BINDING_DATA_API_S_VER_1 */ + __le32 macs[MAX_MACS_IN_BINDING]; + __le32 phy; +} __packed; /* BINDING_CMD_API_S_VER_1 */ + +/** + * struct iwl_binding_cmd - configuring bindings + * ( BINDING_CONTEXT_CMD = 0x2b ) + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_ctxt_id_and_color + * @action: action to perform, one of FW_CTXT_ACTION_* + * @macs: array of MAC id and colors which belong to the binding + * &enum iwl_ctxt_id_and_color + * @phy: PHY id and color which belongs to the binding + * &enum iwl_ctxt_id_and_color + * @lmac_id: the lmac id the binding belongs to + */ +struct iwl_binding_cmd { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + /* BINDING_DATA_API_S_VER_1 */ + __le32 macs[MAX_MACS_IN_BINDING]; + __le32 phy; + __le32 lmac_id; +} __packed; /* BINDING_CMD_API_S_VER_2 */ + +#define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1) +#define IWL_LMAC_24G_INDEX 0 +#define IWL_LMAC_5G_INDEX 1 + +/* The maximal number of fragments in the FW's schedule session */ +#define IWL_MVM_MAX_QUOTA 128 + +/** + * struct iwl_time_quota_data - configuration of time quota per binding + * @id_and_color: ID and color of the relevant Binding, + * &enum iwl_ctxt_id_and_color + * @quota: absolute time quota in TU. The scheduler will try to divide the + * remainig quota (after Time Events) according to this quota. + * @max_duration: max uninterrupted context duration in TU + */ +struct iwl_time_quota_data { + __le32 id_and_color; + __le32 quota; + __le32 max_duration; +} __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */ + +/** + * struct iwl_time_quota_cmd - configuration of time quota between bindings + * ( TIME_QUOTA_CMD = 0x2c ) + * @quotas: allocations per binding + * Note: on non-CDB the fourth one is the auxilary mac and is + * essentially zero. + * On CDB the fourth one is a regular binding. + */ +struct iwl_time_quota_cmd { + struct iwl_time_quota_data quotas[MAX_BINDINGS]; +} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ + +#endif /* __iwl_fw_api_binding_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api.h b/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h index 0e107f916ce3..ea4a3f04a83a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h @@ -59,8 +59,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#ifndef __iwl_fw_api_h__ -#define __iwl_fw_api_h__ +#ifndef __iwl_fw_api_cmdhdr_h__ +#define __iwl_fw_api_cmdhdr_h__ /** * DOC: Host command section @@ -112,15 +112,24 @@ static inline u32 iwl_cmd_id(u8 opcode, u8 groupid, u8 version) #define IWL_ALWAYS_LONG_GROUP 1 /** - * struct iwl_cmd_header + * struct iwl_cmd_header - (short) command header format * * This header format appears in the beginning of each command sent from the * driver, and each response/notification received from uCode. */ struct iwl_cmd_header { - u8 cmd; /* Command ID: REPLY_RXON, etc. */ + /** + * @cmd: Command ID: REPLY_RXON, etc. + */ + u8 cmd; + /** + * @group_id: group ID, for commands with groups + */ u8 group_id; - /* + /** + * @sequence: + * Sequence number for the command. + * * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so @@ -150,6 +159,13 @@ struct iwl_cmd_header { * driver, and each response/notification received from uCode. * this is the wide version that contains more information about the command * like length, version and command type + * + * @cmd: command ID, like in &struct iwl_cmd_header + * @group_id: group ID, like in &struct iwl_cmd_header + * @sequence: sequence, like in &struct iwl_cmd_header + * @length: length of the command + * @reserved: reserved + * @version: command version */ struct iwl_cmd_header_wide { u8 cmd; @@ -161,48 +177,6 @@ struct iwl_cmd_header_wide { } __packed; /** - * iwl_tx_queue_cfg_actions - TXQ config options - * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue - * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format - */ -enum iwl_tx_queue_cfg_actions { - TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), - TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), -}; - -/** - * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command - * @sta_id: station id - * @tid: tid of the queue - * @flags: see &enum iwl_tx_queue_cfg_actions - * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. - * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) - * @byte_cnt_addr: address of byte count table - * @tfdq_addr: address of TFD circular buffer - */ -struct iwl_tx_queue_cfg_cmd { - u8 sta_id; - u8 tid; - __le16 flags; - __le32 cb_size; - __le64 byte_cnt_addr; - __le64 tfdq_addr; -} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ - -/** - * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config - * @queue_number: queue number assigned to this RA -TID - * @flags: set on failure - * @write_pointer: initial value for write pointer - */ -struct iwl_tx_queue_cfg_rsp { - __le16 queue_number; - __le16 flags; - __le16 write_pointer; - __le16 reserved; -} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ - -/** * struct iwl_calib_res_notif_phy_db - Receive phy db chunk after calibrations * @type: type of the result - mostly ignored * @length: length of the data @@ -226,4 +200,12 @@ struct iwl_phy_db_cmd { u8 data[]; } __packed; -#endif /* __iwl_fw_api_h__*/ +/** + * struct iwl_cmd_response - generic response struct for most commands + * @status: status of the command asked, changes for each one + */ +struct iwl_cmd_response { + __le32 status; +}; + +#endif /* __iwl_fw_api_cmdhdr_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h index 8cd06aaa1f54..d09555afe2c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/coex.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -64,8 +59,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __fw_api_bt_coex_h__ -#define __fw_api_bt_coex_h__ +#ifndef __iwl_fw_api_coex_h__ +#define __iwl_fw_api_coex_h__ #include <linux/types.h> #include <linux/bitops.h> @@ -81,7 +76,6 @@ enum iwl_bt_coex_lut_type { BT_COEX_INVALID_LUT = 0xff, }; /* BT_COEX_DECISION_LUT_INDEX_API_E_VER_1 */ -#define BT_COEX_CORUN_LUT_SIZE (32) #define BT_REDUCED_TX_POWER_BIT BIT(7) enum iwl_bt_coex_mode { @@ -112,18 +106,6 @@ struct iwl_bt_coex_cmd { } __packed; /* BT_COEX_CMD_API_S_VER_6 */ /** - * struct iwl_bt_coex_corun_lut_update - bt coex update the corun lut - * @corun_lut20: co-running 20 MHz LUT configuration - * @corun_lut40: co-running 40 MHz LUT configuration - * - * The structure is used for the BT_COEX_UPDATE_CORUN_LUT command. - */ -struct iwl_bt_coex_corun_lut_update_cmd { - __le32 corun_lut20[BT_COEX_CORUN_LUT_SIZE]; - __le32 corun_lut40[BT_COEX_CORUN_LUT_SIZE]; -} __packed; /* BT_COEX_UPDATE_CORUN_LUT_API_S_VER_1 */ - -/** * struct iwl_bt_coex_reduced_txp_update_cmd * @reduced_txp: bit BT_REDUCED_TX_POWER_BIT to enable / disable, rest of the * bits are the sta_id (value) @@ -196,6 +178,7 @@ enum iwl_bt_mxbox_dw3 { BT_MBOX(3, ACL_STATE, 3, 1), BT_MBOX(3, MSTR_STATE, 4, 1), BT_MBOX(3, OBX_STATE, 5, 1), + BT_MBOX(3, A2DP_SRC, 6, 1), BT_MBOX(3, OPEN_CON_2, 8, 2), BT_MBOX(3, TRAFFIC_LOAD, 10, 2), BT_MBOX(3, CHL_SEQN_LSB, 12, 1), @@ -205,10 +188,21 @@ enum iwl_bt_mxbox_dw3 { BT_MBOX(3, UPDATE_REQUEST, 21, 1), }; +enum iwl_bt_mxbox_dw4 { + BT_MBOX(4, ATS_BT_INTERVAL, 0, 7), + BT_MBOX(4, ATS_BT_ACTIVE_MAX_TH, 7, 7), +}; + #define BT_MBOX_MSG(_notif, _num, _field) \ ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ >> BT_MBOX##_num##_##_field##_POS) +#define BT_MBOX_PRINT(_num, _field, _end) \ + pos += scnprintf(buf + pos, bufsz - pos, \ + "\t%s: %d%s", \ + #_field, \ + BT_MBOX_MSG(notif, _num, _field), \ + true ? "\n" : ", "); enum iwl_bt_activity_grading { BT_OFF = 0, BT_ON_NO_CONNECTION = 1, @@ -225,11 +219,30 @@ enum iwl_bt_ci_compliance { BT_CI_COMPLIANCE_BOTH = 3, }; /* BT_COEX_CI_COMPLIENCE_E_VER_1 */ -#define IWL_COEX_IS_TTC_ON(_ttc_rrc_status, _phy_id) \ - (_ttc_rrc_status & BIT(_phy_id)) +/** + * struct iwl_bt_coex_profile_notif - notification about BT coex + * @mbox_msg: message from BT to WiFi + * @msg_idx: the index of the message + * @bt_ci_compliance: enum %iwl_bt_ci_compliance + * @primary_ch_lut: LUT used for primary channel &enum iwl_bt_coex_lut_type + * @secondary_ch_lut: LUT used for secondary channel &enum iwl_bt_coex_lut_type + * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading + * @ttc_status: is TTC enabled - one bit per PHY + * @rrc_status: is RRC enabled - one bit per PHY + * @reserved: reserved + */ +struct iwl_bt_coex_profile_notif { + __le32 mbox_msg[8]; + __le32 msg_idx; + __le32 bt_ci_compliance; -#define IWL_COEX_IS_RRC_ON(_ttc_rrc_status, _phy_id) \ - ((_ttc_rrc_status >> 4) & BIT(_phy_id)) + __le32 primary_ch_lut; + __le32 secondary_ch_lut; + __le32 bt_activity_grading; + u8 ttc_status; + u8 rrc_status; + __le16 reserved; +} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_5 */ /** * struct iwl_bt_coex_profile_notif - notification about BT coex @@ -239,10 +252,11 @@ enum iwl_bt_ci_compliance { * @primary_ch_lut: LUT used for primary channel &enum iwl_bt_coex_lut_type * @secondary_ch_lut: LUT used for secondary channel &enum iwl_bt_coex_lut_type * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading - * @ttc_rrc_status: is TTC or RRC enabled - one bit per PHY + * @ttc_status: is TTC enabled - one bit per PHY + * @rrc_status: is RRC enabled - one bit per PHY * @reserved: reserved */ -struct iwl_bt_coex_profile_notif { +struct iwl_bt_coex_profile_notif_v4 { __le32 mbox_msg[4]; __le32 msg_idx; __le32 bt_ci_compliance; @@ -250,8 +264,9 @@ struct iwl_bt_coex_profile_notif { __le32 primary_ch_lut; __le32 secondary_ch_lut; __le32 bt_activity_grading; - u8 ttc_rrc_status; - u8 reserved[3]; + u8 ttc_status; + u8 rrc_status; + __le16 reserved; } __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 */ -#endif /* __fw_api_bt_coex_h__ */ +#endif /* __iwl_fw_api_coex_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h new file mode 100644 index 000000000000..074868394427 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -0,0 +1,657 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_commands_h__ +#define __iwl_fw_api_commands_h__ + +/** + * enum iwl_mvm_command_groups - command groups for the firmware + * @LEGACY_GROUP: legacy group, uses command IDs from &enum iwl_legacy_cmds + * @LONG_GROUP: legacy group with long header, also uses command IDs + * from &enum iwl_legacy_cmds + * @SYSTEM_GROUP: system group, uses command IDs from + * &enum iwl_system_subcmd_ids + * @MAC_CONF_GROUP: MAC configuration group, uses command IDs from + * &enum iwl_mac_conf_subcmd_ids + * @PHY_OPS_GROUP: PHY operations group, uses command IDs from + * &enum iwl_phy_ops_subcmd_ids + * @DATA_PATH_GROUP: data path group, uses command IDs from + * &enum iwl_data_path_subcmd_ids + * @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids + * @TOF_GROUP: TOF group, uses command IDs from &enum iwl_tof_subcmd_ids + * @PROT_OFFLOAD_GROUP: protocol offload group, uses command IDs from + * &enum iwl_prot_offload_subcmd_ids + * @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from + * &enum iwl_regulatory_and_nvm_subcmd_ids + * @DEBUG_GROUP: Debug group, uses command IDs from &enum iwl_debug_cmds + */ +enum iwl_mvm_command_groups { + LEGACY_GROUP = 0x0, + LONG_GROUP = 0x1, + SYSTEM_GROUP = 0x2, + MAC_CONF_GROUP = 0x3, + PHY_OPS_GROUP = 0x4, + DATA_PATH_GROUP = 0x5, + NAN_GROUP = 0x7, + TOF_GROUP = 0x8, + PROT_OFFLOAD_GROUP = 0xb, + REGULATORY_AND_NVM_GROUP = 0xc, + DEBUG_GROUP = 0xf, +}; + +/** + * enum iwl_legacy_cmds - legacy group command IDs + */ +enum iwl_legacy_cmds { + /** + * @MVM_ALIVE: + * Alive data from the firmware, as described in + * &struct mvm_alive_resp_v3 or &struct mvm_alive_resp. + */ + MVM_ALIVE = 0x1, + + /** + * @REPLY_ERROR: Cause an error in the firmware, for testing purposes. + */ + REPLY_ERROR = 0x2, + + /** + * @ECHO_CMD: Send data to the device to have it returned immediately. + */ + ECHO_CMD = 0x3, + + /** + * @INIT_COMPLETE_NOTIF: Notification that initialization is complete. + */ + INIT_COMPLETE_NOTIF = 0x4, + + /** + * @PHY_CONTEXT_CMD: + * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd. + */ + PHY_CONTEXT_CMD = 0x8, + + /** + * @DBG_CFG: Debug configuration command. + */ + DBG_CFG = 0x9, + + /** + * @SCAN_ITERATION_COMPLETE_UMAC: + * Firmware indicates a scan iteration completed, using + * &struct iwl_umac_scan_iter_complete_notif. + */ + SCAN_ITERATION_COMPLETE_UMAC = 0xb5, + + /** + * @SCAN_CFG_CMD: + * uses &struct iwl_scan_config_v1 or &struct iwl_scan_config + */ + SCAN_CFG_CMD = 0xc, + + /** + * @SCAN_REQ_UMAC: uses &struct iwl_scan_req_umac + */ + SCAN_REQ_UMAC = 0xd, + + /** + * @SCAN_ABORT_UMAC: uses &struct iwl_umac_scan_abort + */ + SCAN_ABORT_UMAC = 0xe, + + /** + * @SCAN_COMPLETE_UMAC: uses &struct iwl_umac_scan_complete + */ + SCAN_COMPLETE_UMAC = 0xf, + + /** + * @BA_WINDOW_STATUS_NOTIFICATION_ID: + * uses &struct iwl_ba_window_status_notif + */ + BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13, + + /** + * @ADD_STA_KEY: + * &struct iwl_mvm_add_sta_key_cmd_v1 or + * &struct iwl_mvm_add_sta_key_cmd. + */ + ADD_STA_KEY = 0x17, + + /** + * @ADD_STA: + * &struct iwl_mvm_add_sta_cmd or &struct iwl_mvm_add_sta_cmd_v7. + */ + ADD_STA = 0x18, + + /** + * @REMOVE_STA: &struct iwl_mvm_rm_sta_cmd + */ + REMOVE_STA = 0x19, + + /** + * @FW_GET_ITEM_CMD: uses &struct iwl_fw_get_item_cmd + */ + FW_GET_ITEM_CMD = 0x1a, + + /** + * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2, + * response in &struct iwl_mvm_tx_resp or + * &struct iwl_mvm_tx_resp_v3 + */ + TX_CMD = 0x1c, + + /** + * @TXPATH_FLUSH: &struct iwl_tx_path_flush_cmd + */ + TXPATH_FLUSH = 0x1e, + + /** + * @MGMT_MCAST_KEY: + * &struct iwl_mvm_mgmt_mcast_key_cmd or + * &struct iwl_mvm_mgmt_mcast_key_cmd_v1 + */ + MGMT_MCAST_KEY = 0x1f, + + /* scheduler config */ + /** + * @SCD_QUEUE_CFG: &struct iwl_scd_txq_cfg_cmd for older hardware, + * &struct iwl_tx_queue_cfg_cmd with &struct iwl_tx_queue_cfg_rsp + * for newer (A000) hardware. + */ + SCD_QUEUE_CFG = 0x1d, + + /** + * @WEP_KEY: uses &struct iwl_mvm_wep_key_cmd + */ + WEP_KEY = 0x20, + + /** + * @SHARED_MEM_CFG: + * retrieve shared memory configuration - response in + * &struct iwl_shared_mem_cfg + */ + SHARED_MEM_CFG = 0x25, + + /** + * @TDLS_CHANNEL_SWITCH_CMD: uses &struct iwl_tdls_channel_switch_cmd + */ + TDLS_CHANNEL_SWITCH_CMD = 0x27, + + /** + * @TDLS_CHANNEL_SWITCH_NOTIFICATION: + * uses &struct iwl_tdls_channel_switch_notif + */ + TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, + + /** + * @TDLS_CONFIG_CMD: + * &struct iwl_tdls_config_cmd, response in &struct iwl_tdls_config_res + */ + TDLS_CONFIG_CMD = 0xa7, + + /** + * @MAC_CONTEXT_CMD: &struct iwl_mac_ctx_cmd + */ + MAC_CONTEXT_CMD = 0x28, + + /** + * @TIME_EVENT_CMD: + * &struct iwl_time_event_cmd, response in &struct iwl_time_event_resp + */ + TIME_EVENT_CMD = 0x29, /* both CMD and response */ + + /** + * @TIME_EVENT_NOTIFICATION: &struct iwl_time_event_notif + */ + TIME_EVENT_NOTIFICATION = 0x2a, + + /** + * @BINDING_CONTEXT_CMD: + * &struct iwl_binding_cmd or &struct iwl_binding_cmd_v1 + */ + BINDING_CONTEXT_CMD = 0x2b, + + /** + * @TIME_QUOTA_CMD: &struct iwl_time_quota_cmd + */ + TIME_QUOTA_CMD = 0x2c, + + /** + * @NON_QOS_TX_COUNTER_CMD: + * command is &struct iwl_nonqos_seq_query_cmd + */ + NON_QOS_TX_COUNTER_CMD = 0x2d, + + /** + * @LEDS_CMD: command is &struct iwl_led_cmd + */ + LEDS_CMD = 0x48, + + /** + * @LQ_CMD: using &struct iwl_lq_cmd + */ + LQ_CMD = 0x4e, + + /** + * @FW_PAGING_BLOCK_CMD: + * &struct iwl_fw_paging_cmd + */ + FW_PAGING_BLOCK_CMD = 0x4f, + + /** + * @SCAN_OFFLOAD_REQUEST_CMD: uses &struct iwl_scan_req_lmac + */ + SCAN_OFFLOAD_REQUEST_CMD = 0x51, + + /** + * @SCAN_OFFLOAD_ABORT_CMD: abort the scan - no further contents + */ + SCAN_OFFLOAD_ABORT_CMD = 0x52, + + /** + * @HOT_SPOT_CMD: uses &struct iwl_hs20_roc_req + */ + HOT_SPOT_CMD = 0x53, + + /** + * @SCAN_OFFLOAD_COMPLETE: + * notification, &struct iwl_periodic_scan_complete + */ + SCAN_OFFLOAD_COMPLETE = 0x6D, + + /** + * @SCAN_OFFLOAD_UPDATE_PROFILES_CMD: + * update scan offload (scheduled scan) profiles/blacklist/etc. + */ + SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, + + /** + * @MATCH_FOUND_NOTIFICATION: scan match found + */ + MATCH_FOUND_NOTIFICATION = 0xd9, + + /** + * @SCAN_ITERATION_COMPLETE: + * uses &struct iwl_lmac_scan_complete_notif + */ + SCAN_ITERATION_COMPLETE = 0xe7, + + /* Phy */ + /** + * @PHY_CONFIGURATION_CMD: &struct iwl_phy_cfg_cmd + */ + PHY_CONFIGURATION_CMD = 0x6a, + + /** + * @CALIB_RES_NOTIF_PHY_DB: &struct iwl_calib_res_notif_phy_db + */ + CALIB_RES_NOTIF_PHY_DB = 0x6b, + + /** + * @PHY_DB_CMD: &struct iwl_phy_db_cmd + */ + PHY_DB_CMD = 0x6c, + + /** + * @TOF_CMD: &struct iwl_tof_config_cmd + */ + TOF_CMD = 0x10, + + /** + * @TOF_NOTIFICATION: &struct iwl_tof_gen_resp_cmd + */ + TOF_NOTIFICATION = 0x11, + + /** + * @POWER_TABLE_CMD: &struct iwl_device_power_cmd + */ + POWER_TABLE_CMD = 0x77, + + /** + * @PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION: + * &struct iwl_uapsd_misbehaving_ap_notif + */ + PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, + + /** + * @LTR_CONFIG: &struct iwl_ltr_config_cmd + */ + LTR_CONFIG = 0xee, + + /** + * @REPLY_THERMAL_MNG_BACKOFF: + * Thermal throttling command + */ + REPLY_THERMAL_MNG_BACKOFF = 0x7e, + + /** + * @DC2DC_CONFIG_CMD: + * Set/Get DC2DC frequency tune + * Command is &struct iwl_dc2dc_config_cmd, + * response is &struct iwl_dc2dc_config_resp + */ + DC2DC_CONFIG_CMD = 0x83, + + /** + * @NVM_ACCESS_CMD: using &struct iwl_nvm_access_cmd + */ + NVM_ACCESS_CMD = 0x88, + + /** + * @BEACON_NOTIFICATION: &struct iwl_extended_beacon_notif + */ + BEACON_NOTIFICATION = 0x90, + + /** + * @BEACON_TEMPLATE_CMD: + * Uses one of &struct iwl_mac_beacon_cmd_v6, + * &struct iwl_mac_beacon_cmd_v7 or &struct iwl_mac_beacon_cmd + * depending on the device version. + */ + BEACON_TEMPLATE_CMD = 0x91, + /** + * @TX_ANT_CONFIGURATION_CMD: &struct iwl_tx_ant_cfg_cmd + */ + TX_ANT_CONFIGURATION_CMD = 0x98, + + /** + * @STATISTICS_CMD: &struct iwl_statistics_cmd + */ + STATISTICS_CMD = 0x9c, + + /** + * @STATISTICS_NOTIFICATION: + * one of &struct iwl_notif_statistics_v10, + * &struct iwl_notif_statistics_v11, + * &struct iwl_notif_statistics_cdb + */ + STATISTICS_NOTIFICATION = 0x9d, + + /** + * @EOSP_NOTIFICATION: + * Notify that a service period ended, + * &struct iwl_mvm_eosp_notification + */ + EOSP_NOTIFICATION = 0x9e, + + /** + * @REDUCE_TX_POWER_CMD: + * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd + */ + REDUCE_TX_POWER_CMD = 0x9f, + + /** + * @CARD_STATE_NOTIFICATION: + * Card state (RF/CT kill) notification, + * uses &struct iwl_card_state_notif + */ + CARD_STATE_NOTIFICATION = 0xa1, + + /** + * @MISSED_BEACONS_NOTIFICATION: &struct iwl_missed_beacons_notif + */ + MISSED_BEACONS_NOTIFICATION = 0xa2, + + /** + * @MAC_PM_POWER_TABLE: using &struct iwl_mac_power_cmd + */ + MAC_PM_POWER_TABLE = 0xa9, + + /** + * @MFUART_LOAD_NOTIFICATION: &struct iwl_mfuart_load_notif + */ + MFUART_LOAD_NOTIFICATION = 0xb1, + + /** + * @RSS_CONFIG_CMD: &struct iwl_rss_config_cmd + */ + RSS_CONFIG_CMD = 0xb3, + + /** + * @REPLY_RX_PHY_CMD: &struct iwl_rx_phy_info + */ + REPLY_RX_PHY_CMD = 0xc0, + + /** + * @REPLY_RX_MPDU_CMD: + * &struct iwl_rx_mpdu_res_start or &struct iwl_rx_mpdu_desc + */ + REPLY_RX_MPDU_CMD = 0xc1, + + /** + * @FRAME_RELEASE: + * Frame release (reorder helper) notification, uses + * &struct iwl_frame_release + */ + FRAME_RELEASE = 0xc3, + + /** + * @BA_NOTIF: + * BlockAck notification, uses &struct iwl_mvm_compressed_ba_notif + * or &struct iwl_mvm_ba_notif depending on the HW + */ + BA_NOTIF = 0xc5, + + /* Location Aware Regulatory */ + /** + * @MCC_UPDATE_CMD: using &struct iwl_mcc_update_cmd + */ + MCC_UPDATE_CMD = 0xc8, + + /** + * @MCC_CHUB_UPDATE_CMD: using &struct iwl_mcc_chub_notif + */ + MCC_CHUB_UPDATE_CMD = 0xc9, + + /** + * @MARKER_CMD: trace marker command, uses &struct iwl_mvm_marker + */ + MARKER_CMD = 0xcb, + + /** + * @BT_PROFILE_NOTIFICATION: &struct iwl_bt_coex_profile_notif + */ + BT_PROFILE_NOTIFICATION = 0xce, + + /** + * @BT_CONFIG: &struct iwl_bt_coex_cmd + */ + BT_CONFIG = 0x9b, + + /** + * @BT_COEX_UPDATE_REDUCED_TXP: + * &struct iwl_bt_coex_reduced_txp_update_cmd + */ + BT_COEX_UPDATE_REDUCED_TXP = 0x5c, + + /** + * @BT_COEX_CI: &struct iwl_bt_coex_ci_cmd + */ + BT_COEX_CI = 0x5d, + + /** + * @REPLY_SF_CFG_CMD: &struct iwl_sf_cfg_cmd + */ + REPLY_SF_CFG_CMD = 0xd1, + /** + * @REPLY_BEACON_FILTERING_CMD: &struct iwl_beacon_filter_cmd + */ + REPLY_BEACON_FILTERING_CMD = 0xd2, + + /** + * @DTS_MEASUREMENT_NOTIFICATION: + * &struct iwl_dts_measurement_notif_v1 or + * &struct iwl_dts_measurement_notif_v2 + */ + DTS_MEASUREMENT_NOTIFICATION = 0xdd, + + /** + * @LDBG_CONFIG_CMD: configure continuous trace recording + */ + LDBG_CONFIG_CMD = 0xf6, + + /** + * @DEBUG_LOG_MSG: Debugging log data from firmware + */ + DEBUG_LOG_MSG = 0xf7, + + /** + * @BCAST_FILTER_CMD: &struct iwl_bcast_filter_cmd + */ + BCAST_FILTER_CMD = 0xcf, + + /** + * @MCAST_FILTER_CMD: &struct iwl_mcast_filter_cmd + */ + MCAST_FILTER_CMD = 0xd0, + + /** + * @D3_CONFIG_CMD: &struct iwl_d3_manager_config + */ + D3_CONFIG_CMD = 0xd3, + + /** + * @PROT_OFFLOAD_CONFIG_CMD: Depending on firmware, uses one of + * &struct iwl_proto_offload_cmd_v1, &struct iwl_proto_offload_cmd_v2, + * &struct iwl_proto_offload_cmd_v3_small, + * &struct iwl_proto_offload_cmd_v3_large + */ + PROT_OFFLOAD_CONFIG_CMD = 0xd4, + + /** + * @OFFLOADS_QUERY_CMD: + * No data in command, response in &struct iwl_wowlan_status + */ + OFFLOADS_QUERY_CMD = 0xd5, + + /** + * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config + */ + REMOTE_WAKE_CONFIG_CMD = 0xd6, + + /** + * @D0I3_END_CMD: End D0i3/D3 state, no command data + */ + D0I3_END_CMD = 0xed, + + /** + * @WOWLAN_PATTERNS: &struct iwl_wowlan_patterns_cmd + */ + WOWLAN_PATTERNS = 0xe0, + + /** + * @WOWLAN_CONFIGURATION: &struct iwl_wowlan_config_cmd + */ + WOWLAN_CONFIGURATION = 0xe1, + + /** + * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd + */ + WOWLAN_TSC_RSC_PARAM = 0xe2, + + /** + * @WOWLAN_TKIP_PARAM: &struct iwl_wowlan_tkip_params_cmd + */ + WOWLAN_TKIP_PARAM = 0xe3, + + /** + * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd + */ + WOWLAN_KEK_KCK_MATERIAL = 0xe4, + + /** + * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status + */ + WOWLAN_GET_STATUSES = 0xe5, + + /** + * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: + * No command data, response is &struct iwl_scan_offload_profiles_query + */ + SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, +}; + +/** + * enum iwl_system_subcmd_ids - system group command IDs + */ +enum iwl_system_subcmd_ids { + /** + * @SHARED_MEM_CFG_CMD: + * response in &struct iwl_shared_mem_cfg or + * &struct iwl_shared_mem_cfg_v2 + */ + SHARED_MEM_CFG_CMD = 0x0, + + /** + * @INIT_EXTENDED_CFG_CMD: &struct iwl_init_extended_cfg_cmd + */ + INIT_EXTENDED_CFG_CMD = 0x03, + + /** + * @FSEQ_VER_MISMATCH_NTF: Notification about fseq version + * mismatch during init. The format is specified in + * &struct iwl_fseq_ver_mismatch_ntf. + */ + FSEQ_VER_MISMATCH_NTF = 0xFF, +}; + +#endif /* __iwl_fw_api_commands_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/config.h b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h new file mode 100644 index 000000000000..7f645b62804e --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/config.h @@ -0,0 +1,184 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_config_h__ +#define __iwl_fw_api_config_h__ + +/* + * struct iwl_dqa_enable_cmd + * @cmd_queue: the TXQ number of the command queue + */ +struct iwl_dqa_enable_cmd { + __le32 cmd_queue; +} __packed; /* DQA_CONTROL_CMD_API_S_VER_1 */ + +/* + * struct iwl_tx_ant_cfg_cmd + * @valid: valid antenna configuration + */ +struct iwl_tx_ant_cfg_cmd { + __le32 valid; +} __packed; + +/** + * struct iwl_calib_ctrl - Calibration control struct. + * Sent as part of the phy configuration command. + * @flow_trigger: bitmap for which calibrations to perform according to + * flow triggers, using &enum iwl_calib_cfg + * @event_trigger: bitmap for which calibrations to perform according to + * event triggers, using &enum iwl_calib_cfg + */ +struct iwl_calib_ctrl { + __le32 flow_trigger; + __le32 event_trigger; +} __packed; + +/* This enum defines the bitmap of various calibrations to enable in both + * init ucode and runtime ucode through CALIBRATION_CFG_CMD. + */ +enum iwl_calib_cfg { + IWL_CALIB_CFG_XTAL_IDX = BIT(0), + IWL_CALIB_CFG_TEMPERATURE_IDX = BIT(1), + IWL_CALIB_CFG_VOLTAGE_READ_IDX = BIT(2), + IWL_CALIB_CFG_PAPD_IDX = BIT(3), + IWL_CALIB_CFG_TX_PWR_IDX = BIT(4), + IWL_CALIB_CFG_DC_IDX = BIT(5), + IWL_CALIB_CFG_BB_FILTER_IDX = BIT(6), + IWL_CALIB_CFG_LO_LEAKAGE_IDX = BIT(7), + IWL_CALIB_CFG_TX_IQ_IDX = BIT(8), + IWL_CALIB_CFG_TX_IQ_SKEW_IDX = BIT(9), + IWL_CALIB_CFG_RX_IQ_IDX = BIT(10), + IWL_CALIB_CFG_RX_IQ_SKEW_IDX = BIT(11), + IWL_CALIB_CFG_SENSITIVITY_IDX = BIT(12), + IWL_CALIB_CFG_CHAIN_NOISE_IDX = BIT(13), + IWL_CALIB_CFG_DISCONNECTED_ANT_IDX = BIT(14), + IWL_CALIB_CFG_ANT_COUPLING_IDX = BIT(15), + IWL_CALIB_CFG_DAC_IDX = BIT(16), + IWL_CALIB_CFG_ABS_IDX = BIT(17), + IWL_CALIB_CFG_AGC_IDX = BIT(18), +}; + +/** + * struct iwl_phy_cfg_cmd - Phy configuration command + * @phy_cfg: PHY configuration value, uses &enum iwl_fw_phy_cfg + * @calib_control: calibration control data + */ +struct iwl_phy_cfg_cmd { + __le32 phy_cfg; + struct iwl_calib_ctrl calib_control; +} __packed; + +#define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1)) +#define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3)) +#define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5)) +#define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7)) +#define PHY_CFG_TX_CHAIN_A BIT(8) +#define PHY_CFG_TX_CHAIN_B BIT(9) +#define PHY_CFG_TX_CHAIN_C BIT(10) +#define PHY_CFG_RX_CHAIN_A BIT(12) +#define PHY_CFG_RX_CHAIN_B BIT(13) +#define PHY_CFG_RX_CHAIN_C BIT(14) + +/* + * enum iwl_dc2dc_config_id - flag ids + * + * Ids of dc2dc configuration flags + */ +enum iwl_dc2dc_config_id { + DCDC_LOW_POWER_MODE_MSK_SET = 0x1, /* not used */ + DCDC_FREQ_TUNE_SET = 0x2, +}; /* MARKER_ID_API_E_VER_1 */ + +/** + * struct iwl_dc2dc_config_cmd - configure dc2dc values + * + * (DC2DC_CONFIG_CMD = 0x83) + * + * Set/Get & configure dc2dc values. + * The command always returns the current dc2dc values. + * + * @flags: set/get dc2dc + * @enable_low_power_mode: not used. + * @dc2dc_freq_tune0: frequency divider - digital domain + * @dc2dc_freq_tune1: frequency divider - analog domain + */ +struct iwl_dc2dc_config_cmd { + __le32 flags; + __le32 enable_low_power_mode; /* not used */ + __le32 dc2dc_freq_tune0; + __le32 dc2dc_freq_tune1; +} __packed; /* DC2DC_CONFIG_CMD_API_S_VER_1 */ + +/** + * struct iwl_dc2dc_config_resp - response for iwl_dc2dc_config_cmd + * + * Current dc2dc values returned by the FW. + * + * @dc2dc_freq_tune0: frequency divider - digital domain + * @dc2dc_freq_tune1: frequency divider - analog domain + */ +struct iwl_dc2dc_config_resp { + __le32 dc2dc_freq_tune0; + __le32 dc2dc_freq_tune1; +} __packed; /* DC2DC_CONFIG_RESP_API_S_VER_1 */ + +#endif /* __iwl_fw_api_config_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/context.h b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h new file mode 100644 index 000000000000..2f0d7c498b3e --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/context.h @@ -0,0 +1,94 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_context_h__ +#define __iwl_fw_api_context_h__ + +/** + * enum iwl_ctxt_id_and_color - ID and color fields in context dword + * @FW_CTXT_ID_POS: position of the ID + * @FW_CTXT_ID_MSK: mask of the ID + * @FW_CTXT_COLOR_POS: position of the color + * @FW_CTXT_COLOR_MSK: mask of the color + * @FW_CTXT_INVALID: value used to indicate unused/invalid + */ +enum iwl_ctxt_id_and_color { + FW_CTXT_ID_POS = 0, + FW_CTXT_ID_MSK = 0xff << FW_CTXT_ID_POS, + FW_CTXT_COLOR_POS = 8, + FW_CTXT_COLOR_MSK = 0xff << FW_CTXT_COLOR_POS, + FW_CTXT_INVALID = 0xffffffff, +}; + +#define FW_CMD_ID_AND_COLOR(_id, _color) (((_id) << FW_CTXT_ID_POS) |\ + ((_color) << FW_CTXT_COLOR_POS)) + +/* Possible actions on PHYs, MACs and Bindings */ +enum iwl_ctxt_action { + FW_CTXT_ACTION_STUB = 0, + FW_CTXT_ACTION_ADD, + FW_CTXT_ACTION_MODIFY, + FW_CTXT_ACTION_REMOVE, + FW_CTXT_ACTION_NUM +}; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ + +#endif /* __iwl_fw_api_context_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index d4a4c28b7192..57f4bc242023 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -64,8 +59,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __fw_api_d3_h__ -#define __fw_api_d3_h__ +#ifndef __iwl_fw_api_d3_h__ +#define __iwl_fw_api_d3_h__ /** * enum iwl_d3_wakeup_flags - D3 manager wakeup flags @@ -468,4 +463,4 @@ struct iwl_wowlan_remote_wake_config { /* TODO: NetDetect API */ -#endif /* __fw_api_d3_h__ */ +#endif /* __iwl_fw_api_d3_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h new file mode 100644 index 000000000000..aa76dcc148bd --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -0,0 +1,127 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_datapath_h__ +#define __iwl_fw_api_datapath_h__ + +/** + * enum iwl_data_path_subcmd_ids - data path group commands + */ +enum iwl_data_path_subcmd_ids { + /** + * @DQA_ENABLE_CMD: &struct iwl_dqa_enable_cmd + */ + DQA_ENABLE_CMD = 0x0, + + /** + * @UPDATE_MU_GROUPS_CMD: &struct iwl_mu_group_mgmt_cmd + */ + UPDATE_MU_GROUPS_CMD = 0x1, + + /** + * @TRIGGER_RX_QUEUES_NOTIF_CMD: &struct iwl_rxq_sync_cmd + */ + TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, + + /** + * @STA_PM_NOTIF: &struct iwl_mvm_pm_state_notification + */ + STA_PM_NOTIF = 0xFD, + + /** + * @MU_GROUP_MGMT_NOTIF: &struct iwl_mu_group_mgmt_notif + */ + MU_GROUP_MGMT_NOTIF = 0xFE, + + /** + * @RX_QUEUES_NOTIFICATION: &struct iwl_rxq_sync_notification + */ + RX_QUEUES_NOTIFICATION = 0xFF, +}; + +/** + * struct iwl_mu_group_mgmt_cmd - VHT MU-MIMO group configuration + * + * @reserved: reserved + * @membership_status: a bitmap of MU groups + * @user_position:the position of station in a group. If the station is in the + * group then bits (group * 2) is the position -1 + */ +struct iwl_mu_group_mgmt_cmd { + __le32 reserved; + __le32 membership_status[2]; + __le32 user_position[4]; +} __packed; /* MU_GROUP_ID_MNG_TABLE_API_S_VER_1 */ + +/** + * struct iwl_mu_group_mgmt_notif - VHT MU-MIMO group id notification + * + * @membership_status: a bitmap of MU groups + * @user_position: the position of station in a group. If the station is in the + * group then bits (group * 2) is the position -1 + */ +struct iwl_mu_group_mgmt_notif { + __le32 membership_status[2]; + __le32 user_position[4]; +} __packed; /* MU_GROUP_MNG_NTFY_API_S_VER_1 */ + +#endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h new file mode 100644 index 000000000000..9f88b61536bc --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h @@ -0,0 +1,345 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_debug_h__ +#define __iwl_fw_api_debug_h__ + +/** + * enum iwl_debug_cmds - debug commands + */ +enum iwl_debug_cmds { + /** + * @LMAC_RD_WR: + * LMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and + * &struct iwl_dbg_mem_access_rsp + */ + LMAC_RD_WR = 0x0, + /** + * @UMAC_RD_WR: + * UMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and + * &struct iwl_dbg_mem_access_rsp + */ + UMAC_RD_WR = 0x1, + /** + * @MFU_ASSERT_DUMP_NTF: + * &struct iwl_mfu_assert_dump_notif + */ + MFU_ASSERT_DUMP_NTF = 0xFE, +}; + +/* Error response/notification */ +enum { + FW_ERR_UNKNOWN_CMD = 0x0, + FW_ERR_INVALID_CMD_PARAM = 0x1, + FW_ERR_SERVICE = 0x2, + FW_ERR_ARC_MEMORY = 0x3, + FW_ERR_ARC_CODE = 0x4, + FW_ERR_WATCH_DOG = 0x5, + FW_ERR_WEP_GRP_KEY_INDX = 0x10, + FW_ERR_WEP_KEY_SIZE = 0x11, + FW_ERR_OBSOLETE_FUNC = 0x12, + FW_ERR_UNEXPECTED = 0xFE, + FW_ERR_FATAL = 0xFF +}; + +/** + * struct iwl_error_resp - FW error indication + * ( REPLY_ERROR = 0x2 ) + * @error_type: one of FW_ERR_* + * @cmd_id: the command ID for which the error occurred + * @reserved1: reserved + * @bad_cmd_seq_num: sequence number of the erroneous command + * @error_service: which service created the error, applicable only if + * error_type = 2, otherwise 0 + * @timestamp: TSF in usecs. + */ +struct iwl_error_resp { + __le32 error_type; + u8 cmd_id; + u8 reserved1; + __le16 bad_cmd_seq_num; + __le32 error_service; + __le64 timestamp; +} __packed; + +#define TX_FIFO_MAX_NUM_9000 8 +#define TX_FIFO_MAX_NUM 15 +#define RX_FIFO_MAX_NUM 2 +#define TX_FIFO_INTERNAL_MAX_NUM 6 + +/** + * struct iwl_shared_mem_cfg_v2 - Shared memory configuration information + * + * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not + * accessible) + * @shared_mem_size: shared memory size + * @sample_buff_addr: internal sample (mon/adc) buff addr (pre 8000 HW set to + * 0x0 as accessible only via DBGM RDAT) + * @sample_buff_size: internal sample buff size + * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB), (pre + * 8000 HW set to 0x0 as not accessible) + * @txfifo_size: size of TXF0 ... TXF7 + * @rxfifo_size: RXF1, RXF2 sizes. If there is no RXF2, it'll have a value of 0 + * @page_buff_addr: used by UMAC and performance debug (page miss analysis), + * when paging is not supported this should be 0 + * @page_buff_size: size of %page_buff_addr + * @rxfifo_addr: Start address of rxFifo + * @internal_txfifo_addr: start address of internalFifo + * @internal_txfifo_size: internal fifos' size + * + * NOTE: on firmware that don't have IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG + * set, the last 3 members don't exist. + */ +struct iwl_shared_mem_cfg_v2 { + __le32 shared_mem_addr; + __le32 shared_mem_size; + __le32 sample_buff_addr; + __le32 sample_buff_size; + __le32 txfifo_addr; + __le32 txfifo_size[TX_FIFO_MAX_NUM_9000]; + __le32 rxfifo_size[RX_FIFO_MAX_NUM]; + __le32 page_buff_addr; + __le32 page_buff_size; + __le32 rxfifo_addr; + __le32 internal_txfifo_addr; + __le32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; +} __packed; /* SHARED_MEM_ALLOC_API_S_VER_2 */ + +/** + * struct iwl_shared_mem_lmac_cfg - LMAC shared memory configuration + * + * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB) + * @txfifo_size: size of TX FIFOs + * @rxfifo1_addr: RXF1 addr + * @rxfifo1_size: RXF1 size + */ +struct iwl_shared_mem_lmac_cfg { + __le32 txfifo_addr; + __le32 txfifo_size[TX_FIFO_MAX_NUM]; + __le32 rxfifo1_addr; + __le32 rxfifo1_size; + +} __packed; /* SHARED_MEM_ALLOC_LMAC_API_S_VER_1 */ + +/** + * struct iwl_shared_mem_cfg - Shared memory configuration information + * + * @shared_mem_addr: shared memory address + * @shared_mem_size: shared memory size + * @sample_buff_addr: internal sample (mon/adc) buff addr + * @sample_buff_size: internal sample buff size + * @rxfifo2_addr: start addr of RXF2 + * @rxfifo2_size: size of RXF2 + * @page_buff_addr: used by UMAC and performance debug (page miss analysis), + * when paging is not supported this should be 0 + * @page_buff_size: size of %page_buff_addr + * @lmac_num: number of LMACs (1 or 2) + * @lmac_smem: per - LMAC smem data + */ +struct iwl_shared_mem_cfg { + __le32 shared_mem_addr; + __le32 shared_mem_size; + __le32 sample_buff_addr; + __le32 sample_buff_size; + __le32 rxfifo2_addr; + __le32 rxfifo2_size; + __le32 page_buff_addr; + __le32 page_buff_size; + __le32 lmac_num; + struct iwl_shared_mem_lmac_cfg lmac_smem[2]; +} __packed; /* SHARED_MEM_ALLOC_API_S_VER_3 */ + +/** + * struct iwl_mfuart_load_notif - mfuart image version & status + * ( MFUART_LOAD_NOTIFICATION = 0xb1 ) + * @installed_ver: installed image version + * @external_ver: external image version + * @status: MFUART loading status + * @duration: MFUART loading time + * @image_size: MFUART image size in bytes +*/ +struct iwl_mfuart_load_notif { + __le32 installed_ver; + __le32 external_ver; + __le32 status; + __le32 duration; + /* image size valid only in v2 of the command */ + __le32 image_size; +} __packed; /* MFU_LOADER_NTFY_API_S_VER_2 */ + +/** + * struct iwl_mfu_assert_dump_notif - mfuart dump logs + * ( MFU_ASSERT_DUMP_NTF = 0xfe ) + * @assert_id: mfuart assert id that cause the notif + * @curr_reset_num: number of asserts since uptime + * @index_num: current chunk id + * @parts_num: total number of chunks + * @data_size: number of data bytes sent + * @data: data buffer + */ +struct iwl_mfu_assert_dump_notif { + __le32 assert_id; + __le32 curr_reset_num; + __le16 index_num; + __le16 parts_num; + __le32 data_size; + __le32 data[0]; +} __packed; /* MFU_DUMP_ASSERT_API_S_VER_1 */ + +/** + * enum iwl_mvm_marker_id - marker ids + * + * The ids for different type of markers to insert into the usniffer logs + * + * @MARKER_ID_TX_FRAME_LATENCY: TX latency marker + */ +enum iwl_mvm_marker_id { + MARKER_ID_TX_FRAME_LATENCY = 1, +}; /* MARKER_ID_API_E_VER_1 */ + +/** + * struct iwl_mvm_marker - mark info into the usniffer logs + * + * (MARKER_CMD = 0xcb) + * + * Mark the UTC time stamp into the usniffer logs together with additional + * metadata, so the usniffer output can be parsed. + * In the command response the ucode will return the GP2 time. + * + * @dw_len: The amount of dwords following this byte including this byte. + * @marker_id: A unique marker id (iwl_mvm_marker_id). + * @reserved: reserved. + * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC + * @metadata: additional meta data that will be written to the unsiffer log + */ +struct iwl_mvm_marker { + u8 dw_len; + u8 marker_id; + __le16 reserved; + __le64 timestamp; + __le32 metadata[0]; +} __packed; /* MARKER_API_S_VER_1 */ + +/* Operation types for the debug mem access */ +enum { + DEBUG_MEM_OP_READ = 0, + DEBUG_MEM_OP_WRITE = 1, + DEBUG_MEM_OP_WRITE_BYTES = 2, +}; + +#define DEBUG_MEM_MAX_SIZE_DWORDS 32 + +/** + * struct iwl_dbg_mem_access_cmd - Request the device to read/write memory + * @op: DEBUG_MEM_OP_* + * @addr: address to read/write from/to + * @len: in dwords, to read/write + * @data: for write opeations, contains the source buffer + */ +struct iwl_dbg_mem_access_cmd { + __le32 op; + __le32 addr; + __le32 len; + __le32 data[]; +} __packed; /* DEBUG_(U|L)MAC_RD_WR_CMD_API_S_VER_1 */ + +/* Status responses for the debug mem access */ +enum { + DEBUG_MEM_STATUS_SUCCESS = 0x0, + DEBUG_MEM_STATUS_FAILED = 0x1, + DEBUG_MEM_STATUS_LOCKED = 0x2, + DEBUG_MEM_STATUS_HIDDEN = 0x3, + DEBUG_MEM_STATUS_LENGTH = 0x4, +}; + +/** + * struct iwl_dbg_mem_access_rsp - Response to debug mem commands + * @status: DEBUG_MEM_STATUS_* + * @len: read dwords (0 for write operations) + * @data: contains the read DWs + */ +struct iwl_dbg_mem_access_rsp { + __le32 status; + __le32 len; + __le32 data[]; +} __packed; /* DEBUG_(U|L)MAC_RD_WR_RSP_API_S_VER_1 */ + +#define CONT_REC_COMMAND_SIZE 80 +#define ENABLE_CONT_RECORDING 0x15 +#define DISABLE_CONT_RECORDING 0x16 + +/* + * struct iwl_continuous_record_mode - recording mode + */ +struct iwl_continuous_record_mode { + __le16 enable_recording; +} __packed; + +/* + * struct iwl_continuous_record_cmd - enable/disable continuous recording + */ +struct iwl_continuous_record_cmd { + struct iwl_continuous_record_mode record_mode; + u8 pad[CONT_REC_COMMAND_SIZE - + sizeof(struct iwl_continuous_record_mode)]; +} __packed; + +#endif /* __iwl_fw_api_debug_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/filter.h b/drivers/net/wireless/intel/iwlwifi/fw/api/filter.h new file mode 100644 index 000000000000..befc3b126041 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/filter.h @@ -0,0 +1,183 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_filter_h__ +#define __iwl_fw_api_filter_h__ + +#include "fw/api/mac.h" + +#define MAX_PORT_ID_NUM 2 +#define MAX_MCAST_FILTERING_ADDRESSES 256 + +/** + * struct iwl_mcast_filter_cmd - configure multicast filter. + * @filter_own: Set 1 to filter out multicast packets sent by station itself + * @port_id: Multicast MAC addresses array specifier. This is a strange way + * to identify network interface adopted in host-device IF. + * It is used by FW as index in array of addresses. This array has + * MAX_PORT_ID_NUM members. + * @count: Number of MAC addresses in the array + * @pass_all: Set 1 to pass all multicast packets. + * @bssid: current association BSSID. + * @reserved: reserved + * @addr_list: Place holder for array of MAC addresses. + * IMPORTANT: add padding if necessary to ensure DWORD alignment. + */ +struct iwl_mcast_filter_cmd { + u8 filter_own; + u8 port_id; + u8 count; + u8 pass_all; + u8 bssid[6]; + u8 reserved[2]; + u8 addr_list[0]; +} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ + +#define MAX_BCAST_FILTERS 8 +#define MAX_BCAST_FILTER_ATTRS 2 + +/** + * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet + * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start. + * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e. + * start of ip payload). + */ +enum iwl_mvm_bcast_filter_attr_offset { + BCAST_FILTER_OFFSET_PAYLOAD_START = 0, + BCAST_FILTER_OFFSET_IP_END = 1, +}; + +/** + * struct iwl_fw_bcast_filter_attr - broadcast filter attribute + * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset. + * @offset: starting offset of this pattern. + * @reserved1: reserved + * @val: value to match - big endian (MSB is the first + * byte to match from offset pos). + * @mask: mask to match (big endian). + */ +struct iwl_fw_bcast_filter_attr { + u8 offset_type; + u8 offset; + __le16 reserved1; + __be32 val; + __be32 mask; +} __packed; /* BCAST_FILTER_ATT_S_VER_1 */ + +/** + * enum iwl_mvm_bcast_filter_frame_type - filter frame type + * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames. + * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames + */ +enum iwl_mvm_bcast_filter_frame_type { + BCAST_FILTER_FRAME_TYPE_ALL = 0, + BCAST_FILTER_FRAME_TYPE_IPV4 = 1, +}; + +/** + * struct iwl_fw_bcast_filter - broadcast filter + * @discard: discard frame (1) or let it pass (0). + * @frame_type: &enum iwl_mvm_bcast_filter_frame_type. + * @reserved1: reserved + * @num_attrs: number of valid attributes in this filter. + * @attrs: attributes of this filter. a filter is considered matched + * only when all its attributes are matched (i.e. AND relationship) + */ +struct iwl_fw_bcast_filter { + u8 discard; + u8 frame_type; + u8 num_attrs; + u8 reserved1; + struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS]; +} __packed; /* BCAST_FILTER_S_VER_1 */ + +/** + * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. + * @default_discard: default action for this mac (discard (1) / pass (0)). + * @reserved1: reserved + * @attached_filters: bitmap of relevant filters for this mac. + */ +struct iwl_fw_bcast_mac { + u8 default_discard; + u8 reserved1; + __le16 attached_filters; +} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */ + +/** + * struct iwl_bcast_filter_cmd - broadcast filtering configuration + * @disable: enable (0) / disable (1) + * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS) + * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER) + * @reserved1: reserved + * @filters: broadcast filters + * @macs: broadcast filtering configuration per-mac + */ +struct iwl_bcast_filter_cmd { + u8 disable; + u8 max_bcast_filters; + u8 max_macs; + u8 reserved1; + struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS]; + struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; +} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ + +#endif /* __iwl_fw_api_filter_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/led.h b/drivers/net/wireless/intel/iwlwifi/fw/api/led.h new file mode 100644 index 000000000000..b30c9d229d6e --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/led.h @@ -0,0 +1,71 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_led_h__ +#define __iwl_fw_api_led_h__ + +/** + * struct iwl_led_cmd - LED switching command + * + * @status: LED status (on/off) + */ +struct iwl_led_cmd { + __le32 status; +} __packed; /* LEDS_CMD_API_S_VER_2 */ + +#endif /* __iwl_fw_api_led_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h new file mode 100644 index 000000000000..39c89e85fd2f --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -0,0 +1,152 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_mac_cfg_h__ +#define __iwl_fw_api_mac_cfg_h__ + +/** + * enum iwl_mac_conf_subcmd_ids - mac configuration command IDs + */ +enum iwl_mac_conf_subcmd_ids { + /** + * @LINK_QUALITY_MEASUREMENT_CMD: &struct iwl_link_qual_msrmnt_cmd + */ + LINK_QUALITY_MEASUREMENT_CMD = 0x1, + + /** + * @LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF: + * &struct iwl_link_qual_msrmnt_notif + */ + LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE, + + /** + * @CHANNEL_SWITCH_NOA_NOTIF: &struct iwl_channel_switch_noa_notif + */ + CHANNEL_SWITCH_NOA_NOTIF = 0xFF, +}; + +#define LQM_NUMBER_OF_STATIONS_IN_REPORT 16 + +enum iwl_lqm_cmd_operatrions { + LQM_CMD_OPERATION_START_MEASUREMENT = 0x01, + LQM_CMD_OPERATION_STOP_MEASUREMENT = 0x02, +}; + +enum iwl_lqm_status { + LQM_STATUS_SUCCESS = 0, + LQM_STATUS_TIMEOUT = 1, + LQM_STATUS_ABORT = 2, +}; + +/** + * struct iwl_link_qual_msrmnt_cmd - Link Quality Measurement command + * @cmd_operation: command operation to be performed (start or stop) + * as defined above. + * @mac_id: MAC ID the measurement applies to. + * @measurement_time: time of the total measurement to be performed, in uSec. + * @timeout: maximum time allowed until a response is sent, in uSec. + */ +struct iwl_link_qual_msrmnt_cmd { + __le32 cmd_operation; + __le32 mac_id; + __le32 measurement_time; + __le32 timeout; +} __packed /* LQM_CMD_API_S_VER_1 */; + +/** + * struct iwl_link_qual_msrmnt_notif - Link Quality Measurement notification + * + * @frequent_stations_air_time: an array containing the total air time + * (in uSec) used by the most frequently transmitting stations. + * @number_of_stations: the number of uniqe stations included in the array + * (a number between 0 to 16) + * @total_air_time_other_stations: the total air time (uSec) used by all the + * stations which are not included in the above report. + * @time_in_measurement_window: the total time in uSec in which a measurement + * took place. + * @tx_frame_dropped: the number of TX frames dropped due to retry limit during + * measurement + * @mac_id: MAC ID the measurement applies to. + * @status: return status. may be one of the LQM_STATUS_* defined above. + * @reserved: reserved. + */ +struct iwl_link_qual_msrmnt_notif { + __le32 frequent_stations_air_time[LQM_NUMBER_OF_STATIONS_IN_REPORT]; + __le32 number_of_stations; + __le32 total_air_time_other_stations; + __le32 time_in_measurement_window; + __le32 tx_frame_dropped; + __le32 mac_id; + __le32 status; + u8 reserved[12]; +} __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */ + +/** + * struct iwl_channel_switch_noa_notif - Channel switch NOA notification + * + * @id_and_color: ID and color of the MAC + */ +struct iwl_channel_switch_noa_notif { + __le32 id_and_color; +} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ + +#endif /* __iwl_fw_api_mac_cfg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h index 0c3350ad2f2f..f2e31e040a7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac.h @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -16,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -31,6 +27,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,8 +57,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __fw_api_mac_h__ -#define __fw_api_mac_h__ +#ifndef __iwl_fw_api_mac_h__ +#define __iwl_fw_api_mac_h__ /* * The first MAC indices (starting from 0) are available to the driver, @@ -76,8 +73,6 @@ #define IWL_MVM_STATION_COUNT 16 #define IWL_MVM_INVALID_STA 0xFF -#define IWL_MVM_TDLS_STA_COUNT 4 - enum iwl_ac { AC_BK, AC_BE, @@ -393,4 +388,22 @@ struct iwl_nonqos_seq_query_cmd { __le16 reserved; } __packed; /* NON_QOS_TX_COUNTER_GET_SET_API_S_VER_1 */ -#endif /* __fw_api_mac_h__ */ +/** + * struct iwl_missed_beacons_notif - information on missed beacons + * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) + * @mac_id: interface ID + * @consec_missed_beacons_since_last_rx: number of consecutive missed + * beacons since last RX. + * @consec_missed_beacons: number of consecutive missed beacons + * @num_expected_beacons: number of expected beacons + * @num_recvd_beacons: number of received beacons + */ +struct iwl_missed_beacons_notif { + __le32 mac_id; + __le32 consec_missed_beacons_since_last_rx; + __le32 consec_missed_beacons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ + +#endif /* __iwl_fw_api_mac_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h new file mode 100644 index 000000000000..00bc7a25dece --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_nvm_reg_h__ +#define __iwl_fw_api_nvm_reg_h__ + +/** + * enum iwl_regulatory_and_nvm_subcmd_ids - regulatory/NVM commands + */ +enum iwl_regulatory_and_nvm_subcmd_ids { + /** + * @NVM_ACCESS_COMPLETE: &struct iwl_nvm_access_complete_cmd + */ + NVM_ACCESS_COMPLETE = 0x0, + + /** + * @NVM_GET_INFO: + * Command is &struct iwl_nvm_get_info, + * response is &struct iwl_nvm_get_info_rsp + */ + NVM_GET_INFO = 0x2, +}; + +/** + * enum iwl_nvm_access_op - NVM access opcode + * @IWL_NVM_READ: read NVM + * @IWL_NVM_WRITE: write NVM + */ +enum iwl_nvm_access_op { + IWL_NVM_READ = 0, + IWL_NVM_WRITE = 1, +}; + +/** + * enum iwl_nvm_access_target - target of the NVM_ACCESS_CMD + * @NVM_ACCESS_TARGET_CACHE: access the cache + * @NVM_ACCESS_TARGET_OTP: access the OTP + * @NVM_ACCESS_TARGET_EEPROM: access the EEPROM + */ +enum iwl_nvm_access_target { + NVM_ACCESS_TARGET_CACHE = 0, + NVM_ACCESS_TARGET_OTP = 1, + NVM_ACCESS_TARGET_EEPROM = 2, +}; + +/** + * enum iwl_nvm_section_type - section types for NVM_ACCESS_CMD + * @NVM_SECTION_TYPE_SW: software section + * @NVM_SECTION_TYPE_REGULATORY: regulatory section + * @NVM_SECTION_TYPE_CALIBRATION: calibration section + * @NVM_SECTION_TYPE_PRODUCTION: production section + * @NVM_SECTION_TYPE_MAC_OVERRIDE: MAC override section + * @NVM_SECTION_TYPE_PHY_SKU: PHY SKU section + * @NVM_MAX_NUM_SECTIONS: number of sections + */ +enum iwl_nvm_section_type { + NVM_SECTION_TYPE_SW = 1, + NVM_SECTION_TYPE_REGULATORY = 3, + NVM_SECTION_TYPE_CALIBRATION = 4, + NVM_SECTION_TYPE_PRODUCTION = 5, + NVM_SECTION_TYPE_MAC_OVERRIDE = 11, + NVM_SECTION_TYPE_PHY_SKU = 12, + NVM_MAX_NUM_SECTIONS = 13, +}; + +/** + * struct iwl_nvm_access_cmd - Request the device to send an NVM section + * @op_code: &enum iwl_nvm_access_op + * @target: &enum iwl_nvm_access_target + * @type: &enum iwl_nvm_section_type + * @offset: offset in bytes into the section + * @length: in bytes, to read/write + * @data: if write operation, the data to write. On read its empty + */ +struct iwl_nvm_access_cmd { + u8 op_code; + u8 target; + __le16 type; + __le16 offset; + __le16 length; + u8 data[]; +} __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ + +/** + * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD + * @offset: offset in bytes into the section + * @length: in bytes, either how much was written or read + * @type: NVM_SECTION_TYPE_* + * @status: 0 for success, fail otherwise + * @data: if read operation, the data returned. Empty on write. + */ +struct iwl_nvm_access_resp { + __le16 offset; + __le16 length; + __le16 type; + __le16 status; + u8 data[]; +} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_2 */ + +/* + * struct iwl_nvm_get_info - request to get NVM data + */ +struct iwl_nvm_get_info { + __le32 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */ + +/** + * enum iwl_nvm_info_general_flags - flags in NVM_GET_INFO resp + * @NVM_GENERAL_FLAGS_EMPTY_OTP: 1 if OTP is empty + */ +enum iwl_nvm_info_general_flags { + NVM_GENERAL_FLAGS_EMPTY_OTP = BIT(0), +}; + +/** + * struct iwl_nvm_get_info_general - general NVM data + * @flags: bit 0: 1 - empty, 0 - non-empty + * @nvm_version: nvm version + * @board_type: board type + * @reserved: reserved + */ +struct iwl_nvm_get_info_general { + __le32 flags; + __le16 nvm_version; + u8 board_type; + u8 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_sku - mac information + * @enable_24g: band 2.4G enabled + * @enable_5g: band 5G enabled + * @enable_11n: 11n enabled + * @enable_11ac: 11ac enabled + * @mimo_disable: MIMO enabled + * @ext_crypto: Extended crypto enabled + */ +struct iwl_nvm_get_info_sku { + __le32 enable_24g; + __le32 enable_5g; + __le32 enable_11n; + __le32 enable_11ac; + __le32 mimo_disable; + __le32 ext_crypto; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_phy - phy information + * @tx_chains: BIT 0 chain A, BIT 1 chain B + * @rx_chains: BIT 0 chain A, BIT 1 chain B + */ +struct iwl_nvm_get_info_phy { + __le32 tx_chains; + __le32 rx_chains; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ + +#define IWL_NUM_CHANNELS (51) + +/** + * struct iwl_nvm_get_info_regulatory - regulatory information + * @lar_enabled: is LAR enabled + * @channel_profile: regulatory data of this channel + * @reserved: reserved + */ +struct iwl_nvm_get_info_regulatory { + __le32 lar_enabled; + __le16 channel_profile[IWL_NUM_CHANNELS]; + __le16 reserved; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ + +/** + * struct iwl_nvm_get_info_rsp - response to get NVM data + * @general: general NVM data + * @mac_sku: data relating to MAC sku + * @phy_sku: data relating to PHY sku + * @regulatory: regulatory data + */ +struct iwl_nvm_get_info_rsp { + struct iwl_nvm_get_info_general general; + struct iwl_nvm_get_info_sku mac_sku; + struct iwl_nvm_get_info_phy phy_sku; + struct iwl_nvm_get_info_regulatory regulatory; +} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_1 */ + +/** + * struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed + * @reserved: reserved + */ +struct iwl_nvm_access_complete_cmd { + __le32 reserved; +} __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ + +/** + * struct iwl_mcc_update_cmd_v1 - Request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @source_id: the source from where we got the MCC, see iwl_mcc_source + * @reserved: reserved for alignment + */ +struct iwl_mcc_update_cmd_v1 { + __le16 mcc; + u8 source_id; + u8 reserved; +} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */ + +/** + * struct iwl_mcc_update_cmd - Request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @source_id: the source from where we got the MCC, see iwl_mcc_source + * @reserved: reserved for alignment + * @key: integrity key for MCC API OEM testing + * @reserved2: reserved + */ +struct iwl_mcc_update_cmd { + __le16 mcc; + u8 source_id; + u8 reserved; + __le32 key; + u8 reserved2[20]; +} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ + +/** + * struct iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: see &enum iwl_mcc_update_status + * @mcc: the new applied MCC + * @cap: capabilities for all channels which matches the MCC + * @source_id: the MCC source, see iwl_mcc_source + * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 + * channels, depending on platform) + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwl_mcc_update_resp_v1 { + __le32 status; + __le16 mcc; + u8 cap; + u8 source_id; + __le32 n_channels; + __le32 channels[0]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ + +/** + * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. + * Contains the new channel control profile map, if changed, and the new MCC + * (mobile country code). + * The new MCC may be different than what was requested in MCC_UPDATE_CMD. + * @status: see &enum iwl_mcc_update_status + * @mcc: the new applied MCC + * @cap: capabilities for all channels which matches the MCC + * @source_id: the MCC source, see iwl_mcc_source + * @time: time elapsed from the MCC test start (in 30 seconds TU) + * @reserved: reserved. + * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 + * channels, depending on platform) + * @channels: channel control data map, DWORD for each channel. Only the first + * 16bits are used. + */ +struct iwl_mcc_update_resp { + __le32 status; + __le16 mcc; + u8 cap; + u8 source_id; + __le16 time; + __le16 reserved; + __le32 n_channels; + __le32 channels[0]; +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */ + +/** + * struct iwl_mcc_chub_notif - chub notifies of mcc change + * (MCC_CHUB_UPDATE_CMD = 0xc9) + * The Chub (Communication Hub, CommsHUB) is a HW component that connects to + * the cellular and connectivity cores that gets updates of the mcc, and + * notifies the ucode directly of any mcc change. + * The ucode requests the driver to request the device to update geographic + * regulatory profile according to the given MCC (Mobile Country Code). + * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. + * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the + * MCC in the cmd response will be the relevant MCC in the NVM. + * @mcc: given mobile country code + * @source_id: identity of the change originator, see iwl_mcc_source + * @reserved1: reserved for alignment + */ +struct iwl_mcc_chub_notif { + __le16 mcc; + u8 source_id; + u8 reserved1; +} __packed; /* LAR_MCC_NOTIFY_S */ + +enum iwl_mcc_update_status { + MCC_RESP_NEW_CHAN_PROFILE, + MCC_RESP_SAME_CHAN_PROFILE, + MCC_RESP_INVALID, + MCC_RESP_NVM_DISABLED, + MCC_RESP_ILLEGAL, + MCC_RESP_LOW_PRIORITY, + MCC_RESP_TEST_MODE_ACTIVE, + MCC_RESP_TEST_MODE_NOT_ACTIVE, + MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE, +}; + +enum iwl_mcc_source { + MCC_SOURCE_OLD_FW = 0, + MCC_SOURCE_ME = 1, + MCC_SOURCE_BIOS = 2, + MCC_SOURCE_3G_LTE_HOST = 3, + MCC_SOURCE_3G_LTE_DEVICE = 4, + MCC_SOURCE_WIFI = 5, + MCC_SOURCE_RESERVED = 6, + MCC_SOURCE_DEFAULT = 7, + MCC_SOURCE_UNINITIALIZED = 8, + MCC_SOURCE_MCC_API = 9, + MCC_SOURCE_GET_CURRENT = 0x10, + MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11, +}; + +#endif /* __iwl_fw_api_nvm_reg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h new file mode 100644 index 000000000000..53cab993068f --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_offload_h__ +#define __iwl_fw_api_offload_h__ + +/** + * enum iwl_prot_offload_subcmd_ids - protocol offload commands + */ +enum iwl_prot_offload_subcmd_ids { + /** + * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif + */ + STORED_BEACON_NTF = 0xFF, +}; + +#define MAX_STORED_BEACON_SIZE 600 + +/** + * struct iwl_stored_beacon_notif - Stored beacon notification + * + * @system_time: system time on air rise + * @tsf: TSF on air rise + * @beacon_timestamp: beacon on air rise + * @band: band, matches &RX_RES_PHY_FLAGS_BAND_24 definition + * @channel: channel this beacon was received on + * @rates: rate in ucode internal format + * @byte_count: frame's byte count + * @data: beacon data, length in @byte_count + */ +struct iwl_stored_beacon_notif { + __le32 system_time; + __le64 tsf; + __le32 beacon_timestamp; + __le16 band; + __le16 channel; + __le32 rates; + __le32 byte_count; + u8 data[MAX_STORED_BEACON_SIZE]; +} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_2 */ + +#endif /* __iwl_fw_api_offload_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/paging.h b/drivers/net/wireless/intel/iwlwifi/fw/api/paging.h new file mode 100644 index 000000000000..e76f9cd4473d --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/paging.h @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_paging_h__ +#define __iwl_fw_api_paging_h__ + +#define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ + +/** + * struct iwl_fw_paging_cmd - paging layout + * + * Send to FW the paging layout in the driver. + * + * @flags: various flags for the command + * @block_size: the block size in powers of 2 + * @block_num: number of blocks specified in the command. + * @device_phy_addr: virtual addresses from device side + */ +struct iwl_fw_paging_cmd { + __le32 flags; + __le32 block_size; + __le32 block_num; + __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; +} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ + +/** + * enum iwl_fw_item_id - FW item IDs + * + * @IWL_FW_ITEM_ID_PAGING: Address of the pages that the FW will upload + * download + */ +enum iwl_fw_item_id { + IWL_FW_ITEM_ID_PAGING = 3, +}; + +/** + * struct iwl_fw_get_item_cmd - get an item from the fw + * @item_id: ID of item to obtain, see &enum iwl_fw_item_id + */ +struct iwl_fw_get_item_cmd { + __le32 item_id; +} __packed; /* FW_GET_ITEM_CMD_API_S_VER_1 */ + +struct iwl_fw_get_item_resp { + __le32 item_id; + __le32 item_byte_cnt; + __le32 item_val; +} __packed; /* FW_GET_ITEM_RSP_S_VER_1 */ + +#endif /* __iwl_fw_api_paging_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h new file mode 100644 index 000000000000..45f61c6af14e --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h @@ -0,0 +1,164 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_phy_ctxt_h__ +#define __iwl_fw_api_phy_ctxt_h__ + +/* Supported bands */ +#define PHY_BAND_5 (0) +#define PHY_BAND_24 (1) + +/* Supported channel width, vary if there is VHT support */ +#define PHY_VHT_CHANNEL_MODE20 (0x0) +#define PHY_VHT_CHANNEL_MODE40 (0x1) +#define PHY_VHT_CHANNEL_MODE80 (0x2) +#define PHY_VHT_CHANNEL_MODE160 (0x3) + +/* + * Control channel position: + * For legacy set bit means upper channel, otherwise lower. + * For VHT - bit-2 marks if the control is lower/upper relative to center-freq + * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. + * center_freq + * | + * 40Mhz |_______|_______| + * 80Mhz |_______|_______|_______|_______| + * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| + * code 011 010 001 000 | 100 101 110 111 + */ +#define PHY_VHT_CTRL_POS_1_BELOW (0x0) +#define PHY_VHT_CTRL_POS_2_BELOW (0x1) +#define PHY_VHT_CTRL_POS_3_BELOW (0x2) +#define PHY_VHT_CTRL_POS_4_BELOW (0x3) +#define PHY_VHT_CTRL_POS_1_ABOVE (0x4) +#define PHY_VHT_CTRL_POS_2_ABOVE (0x5) +#define PHY_VHT_CTRL_POS_3_ABOVE (0x6) +#define PHY_VHT_CTRL_POS_4_ABOVE (0x7) + +/* + * @band: PHY_BAND_* + * @channel: channel number + * @width: PHY_[VHT|LEGACY]_CHANNEL_* + * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* + */ +struct iwl_fw_channel_info { + u8 band; + u8 channel; + u8 width; + u8 ctrl_pos; +} __packed; + +#define PHY_RX_CHAIN_DRIVER_FORCE_POS (0) +#define PHY_RX_CHAIN_DRIVER_FORCE_MSK \ + (0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS) +#define PHY_RX_CHAIN_VALID_POS (1) +#define PHY_RX_CHAIN_VALID_MSK \ + (0x7 << PHY_RX_CHAIN_VALID_POS) +#define PHY_RX_CHAIN_FORCE_SEL_POS (4) +#define PHY_RX_CHAIN_FORCE_SEL_MSK \ + (0x7 << PHY_RX_CHAIN_FORCE_SEL_POS) +#define PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) +#define PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ + (0x7 << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) +#define PHY_RX_CHAIN_CNT_POS (10) +#define PHY_RX_CHAIN_CNT_MSK \ + (0x3 << PHY_RX_CHAIN_CNT_POS) +#define PHY_RX_CHAIN_MIMO_CNT_POS (12) +#define PHY_RX_CHAIN_MIMO_CNT_MSK \ + (0x3 << PHY_RX_CHAIN_MIMO_CNT_POS) +#define PHY_RX_CHAIN_MIMO_FORCE_POS (14) +#define PHY_RX_CHAIN_MIMO_FORCE_MSK \ + (0x1 << PHY_RX_CHAIN_MIMO_FORCE_POS) + +/* TODO: fix the value, make it depend on firmware at runtime? */ +#define NUM_PHY_CTX 3 + +/* TODO: complete missing documentation */ +/** + * struct iwl_phy_context_cmd - config of the PHY context + * ( PHY_CONTEXT_CMD = 0x8 ) + * @id_and_color: ID and color of the relevant Binding + * @action: action to perform, one of FW_CTXT_ACTION_* + * @apply_time: 0 means immediate apply and context switch. + * other value means apply new params after X usecs + * @tx_param_color: ??? + * @ci: channel info + * @txchain_info: ??? + * @rxchain_info: ??? + * @acquisition_data: ??? + * @dsp_cfg_flags: set to 0 + */ +struct iwl_phy_context_cmd { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + /* PHY_CONTEXT_DATA_API_S_VER_1 */ + __le32 apply_time; + __le32 tx_param_color; + struct iwl_fw_channel_info ci; + __le32 txchain_info; + __le32 rxchain_info; + __le32 acquisition_data; + __le32 dsp_cfg_flags; +} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ + +#endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h new file mode 100644 index 000000000000..9cc59e00bd95 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/phy.h @@ -0,0 +1,258 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_phy_h__ +#define __iwl_fw_api_phy_h__ + +/** + * enum iwl_phy_ops_subcmd_ids - PHY group commands + */ +enum iwl_phy_ops_subcmd_ids { + /** + * @CMD_DTS_MEASUREMENT_TRIGGER_WIDE: + * Uses either &struct iwl_dts_measurement_cmd or + * &struct iwl_ext_dts_measurement_cmd + */ + CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, + + /** + * @CTDP_CONFIG_CMD: &struct iwl_mvm_ctdp_cmd + */ + CTDP_CONFIG_CMD = 0x03, + + /** + * @TEMP_REPORTING_THRESHOLDS_CMD: &struct temp_report_ths_cmd + */ + TEMP_REPORTING_THRESHOLDS_CMD = 0x04, + + /** + * @GEO_TX_POWER_LIMIT: &struct iwl_geo_tx_power_profiles_cmd + */ + GEO_TX_POWER_LIMIT = 0x05, + + /** + * @CT_KILL_NOTIFICATION: &struct ct_kill_notif + */ + CT_KILL_NOTIFICATION = 0xFE, + + /** + * @DTS_MEASUREMENT_NOTIF_WIDE: + * &struct iwl_dts_measurement_notif_v1 or + * &struct iwl_dts_measurement_notif_v2 + */ + DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, +}; + +/* DTS measurements */ + +enum iwl_dts_measurement_flags { + DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0), + DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1), +}; + +/** + * struct iwl_dts_measurement_cmd - request DTS temp and/or voltage measurements + * + * @flags: indicates which measurements we want as specified in + * &enum iwl_dts_measurement_flags + */ +struct iwl_dts_measurement_cmd { + __le32 flags; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */ + +/** +* enum iwl_dts_control_measurement_mode - DTS measurement type +* @DTS_AUTOMATIC: Automatic mode (full SW control). Provide temperature read +* back (latest value. Not waiting for new value). Use automatic +* SW DTS configuration. +* @DTS_REQUEST_READ: Request DTS read. Configure DTS with manual settings, +* trigger DTS reading and provide read back temperature read +* when available. +* @DTS_OVER_WRITE: over-write the DTS temperatures in the SW until next read +* @DTS_DIRECT_WITHOUT_MEASURE: DTS returns its latest temperature result, +* without measurement trigger. +*/ +enum iwl_dts_control_measurement_mode { + DTS_AUTOMATIC = 0, + DTS_REQUEST_READ = 1, + DTS_OVER_WRITE = 2, + DTS_DIRECT_WITHOUT_MEASURE = 3, +}; + +/** +* enum iwl_dts_used - DTS to use or used for measurement in the DTS request +* @DTS_USE_TOP: Top +* @DTS_USE_CHAIN_A: chain A +* @DTS_USE_CHAIN_B: chain B +* @DTS_USE_CHAIN_C: chain C +* @XTAL_TEMPERATURE: read temperature from xtal +*/ +enum iwl_dts_used { + DTS_USE_TOP = 0, + DTS_USE_CHAIN_A = 1, + DTS_USE_CHAIN_B = 2, + DTS_USE_CHAIN_C = 3, + XTAL_TEMPERATURE = 4, +}; + +/** +* enum iwl_dts_bit_mode - bit-mode to use in DTS request read mode +* @DTS_BIT6_MODE: bit 6 mode +* @DTS_BIT8_MODE: bit 8 mode +*/ +enum iwl_dts_bit_mode { + DTS_BIT6_MODE = 0, + DTS_BIT8_MODE = 1, +}; + +/** + * struct iwl_ext_dts_measurement_cmd - request extended DTS temp measurements + * @control_mode: see &enum iwl_dts_control_measurement_mode + * @temperature: used when over write DTS mode is selected + * @sensor: set temperature sensor to use. See &enum iwl_dts_used + * @avg_factor: average factor to DTS in request DTS read mode + * @bit_mode: value defines the DTS bit mode to use. See &enum iwl_dts_bit_mode + * @step_duration: step duration for the DTS + */ +struct iwl_ext_dts_measurement_cmd { + __le32 control_mode; + __le32 temperature; + __le32 sensor; + __le32 avg_factor; + __le32 bit_mode; + __le32 step_duration; +} __packed; /* XVT_FW_DTS_CONTROL_MEASUREMENT_REQUEST_API_S */ + +/** + * struct iwl_dts_measurement_notif_v1 - measurements notification + * + * @temp: the measured temperature + * @voltage: the measured voltage + */ +struct iwl_dts_measurement_notif_v1 { + __le32 temp; + __le32 voltage; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_1*/ + +/** + * struct iwl_dts_measurement_notif_v2 - measurements notification + * + * @temp: the measured temperature + * @voltage: the measured voltage + * @threshold_idx: the trip index that was crossed + */ +struct iwl_dts_measurement_notif_v2 { + __le32 temp; + __le32 voltage; + __le32 threshold_idx; +} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_2 */ + +/** + * struct ct_kill_notif - CT-kill entry notification + * + * @temperature: the current temperature in celsius + * @reserved: reserved + */ +struct ct_kill_notif { + __le16 temperature; + __le16 reserved; +} __packed; /* GRP_PHY_CT_KILL_NTF */ + +/** +* enum ctdp_cmd_operation - CTDP command operations +* @CTDP_CMD_OPERATION_START: update the current budget +* @CTDP_CMD_OPERATION_STOP: stop ctdp +* @CTDP_CMD_OPERATION_REPORT: get the average budget +*/ +enum iwl_mvm_ctdp_cmd_operation { + CTDP_CMD_OPERATION_START = 0x1, + CTDP_CMD_OPERATION_STOP = 0x2, + CTDP_CMD_OPERATION_REPORT = 0x4, +};/* CTDP_CMD_OPERATION_TYPE_E */ + +/** + * struct iwl_mvm_ctdp_cmd - track and manage the FW power consumption budget + * + * @operation: see &enum iwl_mvm_ctdp_cmd_operation + * @budget: the budget in milliwatt + * @window_size: defined in API but not used + */ +struct iwl_mvm_ctdp_cmd { + __le32 operation; + __le32 budget; + __le32 window_size; +} __packed; + +#define IWL_MAX_DTS_TRIPS 8 + +/** + * struct temp_report_ths_cmd - set temperature thresholds + * + * @num_temps: number of temperature thresholds passed + * @thresholds: array with the thresholds to be configured + */ +struct temp_report_ths_cmd { + __le32 num_temps; + __le16 thresholds[IWL_MAX_DTS_TRIPS]; +} __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */ + +#endif /* __iwl_fw_api_phy_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 7da57ef2454e..a06afb5605d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -65,8 +60,8 @@ * *****************************************************************************/ -#ifndef __fw_api_power_h__ -#define __fw_api_power_h__ +#ifndef __iwl_fw_api_power_h__ +#define __iwl_fw_api_power_h__ /* Power Management Commands, Responses, Notifications */ @@ -224,7 +219,7 @@ struct iwl_device_power_cmd { /** * struct iwl_mac_power_cmd - New power command containing uAPSD support * MAC_PM_POWER_TABLE = 0xA9 (command, has simple generic response) - * @id_and_color: MAC contex identifier, &enum iwl_mvm_id_and_color + * @id_and_color: MAC contex identifier, &enum iwl_ctxt_id_and_color * @flags: Power table command flags from POWER_FLAGS_* * @keep_alive_seconds: Keep alive period in seconds. Default - 25 sec. * Minimum allowed:- 3 * DTIM. Keep alive period must be @@ -528,4 +523,4 @@ struct iwl_beacon_filter_cmd { #define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT) #define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3) -#endif +#endif /* __iwl_fw_api_power_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index bdf1228d050b..a13fd8a1be62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -62,10 +57,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __fw_api_rs_h__ -#define __fw_api_rs_h__ +#ifndef __iwl_fw_api_rs_h__ +#define __iwl_fw_api_rs_h__ -#include "fw-api-mac.h" +#include "mac.h" /* * These serve as indexes into @@ -410,4 +405,4 @@ struct iwl_lq_cmd { __le32 ss_params; }; /* LINK_QUALITY_CMD_API_S_VER_1 */ -#endif /* __fw_api_rs_h__ */ +#endif /* __iwl_fw_api_rs_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 59038ade08d8..e7565f37ece9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -65,8 +60,8 @@ * *****************************************************************************/ -#ifndef __fw_api_rx_h__ -#define __fw_api_rx_h__ +#ifndef __iwl_fw_api_rx_h__ +#define __iwl_fw_api_rx_h__ /* API for pre-9000 hardware */ @@ -571,4 +566,24 @@ struct iwl_mvm_pm_state_notification { __le16 reserved; } __packed; /* PEER_PM_NTFY_API_S_VER_1 */ -#endif /* __fw_api_rx_h__ */ +#define BA_WINDOW_STREAMS_MAX 16 +#define BA_WINDOW_STATUS_TID_MSK 0x000F +#define BA_WINDOW_STATUS_STA_ID_POS 4 +#define BA_WINDOW_STATUS_STA_ID_MSK 0x01F0 +#define BA_WINDOW_STATUS_VALID_MSK BIT(9) + +/** + * struct iwl_ba_window_status_notif - reordering window's status notification + * @bitmap: bitmap of received frames [start_seq_num + 0]..[start_seq_num + 63] + * @ra_tid: bit 3:0 - TID, bit 8:4 - STA_ID, bit 9 - valid + * @start_seq_num: the start sequence number of the bitmap + * @mpdu_rx_count: the number of received MPDUs since entering D0i3 + */ +struct iwl_ba_window_status_notif { + __le64 bitmap[BA_WINDOW_STREAMS_MAX]; + __le16 ra_tid[BA_WINDOW_STREAMS_MAX]; + __le32 start_seq_num[BA_WINDOW_STREAMS_MAX]; + __le16 mpdu_rx_count[BA_WINDOW_STREAMS_MAX]; +} __packed; /* BA_WINDOW_STATUS_NTFY_API_S_VER_1 */ + +#endif /* __iwl_fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 1cd7cc087936..5a40092febfb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -65,8 +60,8 @@ * *****************************************************************************/ -#ifndef __fw_api_scan_h__ -#define __fw_api_scan_h__ +#ifndef __iwl_fw_api_scan_h__ +#define __iwl_fw_api_scan_h__ /* Scan Commands, Responses, Notifications */ @@ -789,4 +784,4 @@ struct iwl_umac_scan_iter_complete_notif { struct iwl_scan_results_notif results[]; } __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_2 */ -#endif +#endif /* __iwl_fw_api_scan_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sf.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sf.h new file mode 100644 index 000000000000..e517b55f1bc6 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sf.h @@ -0,0 +1,138 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_sf_h__ +#define __iwl_fw_api_sf_h__ + +/* Smart Fifo state */ +enum iwl_sf_state { + SF_LONG_DELAY_ON = 0, /* should never be called by driver */ + SF_FULL_ON, + SF_UNINIT, + SF_INIT_OFF, + SF_HW_NUM_STATES +}; + +/* Smart Fifo possible scenario */ +enum iwl_sf_scenario { + SF_SCENARIO_SINGLE_UNICAST, + SF_SCENARIO_AGG_UNICAST, + SF_SCENARIO_MULTICAST, + SF_SCENARIO_BA_RESP, + SF_SCENARIO_TX_RESP, + SF_NUM_SCENARIO +}; + +#define SF_TRANSIENT_STATES_NUMBER 2 /* SF_LONG_DELAY_ON and SF_FULL_ON */ +#define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ + +/* smart FIFO default values */ +#define SF_W_MARK_SISO 6144 +#define SF_W_MARK_MIMO2 8192 +#define SF_W_MARK_MIMO3 6144 +#define SF_W_MARK_LEGACY 4096 +#define SF_W_MARK_SCAN 4096 + +/* SF Scenarios timers for default configuration (aligned to 32 uSec) */ +#define SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */ +#define SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ +#define SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ +#define SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ + +/* SF Scenarios timers for BSS MAC configuration (aligned to 32 uSec) */ +#define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ +#define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ +#define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ +#define SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */ +#define SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */ +#define SF_MCAST_AGING_TIMER 10016 /* 10 mSec */ +#define SF_BA_IDLE_TIMER 320 /* 300 uSec */ +#define SF_BA_AGING_TIMER 2016 /* 2 mSec */ +#define SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */ +#define SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */ + +#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ + +#define SF_CFG_DUMMY_NOTIF_OFF BIT(16) + +/** + * struct iwl_sf_cfg_cmd - Smart Fifo configuration command. + * @state: smart fifo state, types listed in &enum iwl_sf_state. + * @watermark: Minimum allowed available free space in RXF for transient state. + * @long_delay_timeouts: aging and idle timer values for each scenario + * in long delay state. + * @full_on_timeouts: timer values for each scenario in full on state. + */ +struct iwl_sf_cfg_cmd { + __le32 state; + __le32 watermark[SF_TRANSIENT_STATES_NUMBER]; + __le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; + __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; +} __packed; /* SF_CFG_API_S_VER_2 */ + +#endif /* __iwl_fw_api_sf_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index 81f0a3463bac..af369eba3795 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -64,8 +59,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __fw_api_sta_h__ -#define __fw_api_sta_h__ +#ifndef __iwl_fw_api_sta_h__ +#define __iwl_fw_api_sta_h__ /** * enum iwl_sta_flags - flags for the ADD_STA host command @@ -291,7 +286,7 @@ struct iwl_mvm_keyinfo { * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to, - * see &enum iwl_mvm_id_and_color + * see &enum iwl_ctxt_id_and_color * @addr: station's MAC address * @reserved2: reserved * @sta_id: index of station in uCode's station table @@ -372,7 +367,7 @@ enum iwl_sta_type { * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable * AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field. * @mac_id_n_color: the Mac context this station belongs to, - * see &enum iwl_mvm_id_and_color + * see &enum iwl_ctxt_id_and_color * @addr: station's MAC address * @reserved2: reserved * @sta_id: index of station in uCode's station table @@ -575,4 +570,4 @@ struct iwl_mvm_eosp_notification { __le32 sta_id; } __packed; /* UAPSD_EOSP_NTFY_API_S_VER_1 */ -#endif /* __fw_api_sta_h__ */ +#endif /* __iwl_fw_api_sta_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h index c7531da508fd..53cb622aa9ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h @@ -18,11 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -64,9 +59,9 @@ * *****************************************************************************/ -#ifndef __fw_api_stats_h__ -#define __fw_api_stats_h__ -#include "fw-api-mac.h" +#ifndef __iwl_fw_api_stats_h__ +#define __iwl_fw_api_stats_h__ +#include "mac.h" struct mvm_statistics_dbg { __le32 burst_check; @@ -476,4 +471,4 @@ struct iwl_statistics_cmd { __le32 flags; } __packed; /* STATISTICS_CMD_API_S_VER_1 */ -#endif /* __fw_api_stats_h__ */ +#endif /* __iwl_fw_api_stats_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h new file mode 100644 index 000000000000..7c6c2462d0e8 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h @@ -0,0 +1,208 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_tdls_h__ +#define __iwl_fw_api_tdls_h__ + +#include "fw/api/tx.h" +#include "fw/api/phy-ctxt.h" + +#define IWL_MVM_TDLS_STA_COUNT 4 + +/* Type of TDLS request */ +enum iwl_tdls_channel_switch_type { + TDLS_SEND_CHAN_SW_REQ = 0, + TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH, + TDLS_MOVE_CH, +}; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */ + +/** + * struct iwl_tdls_channel_switch_timing - Switch timing in TDLS channel-switch + * @frame_timestamp: GP2 timestamp of channel-switch request/response packet + * received from peer + * @max_offchan_duration: What amount of microseconds out of a DTIM is given + * to the TDLS off-channel communication. For instance if the DTIM is + * 200TU and the TDLS peer is to be given 25% of the time, the value + * given will be 50TU, or 50 * 1024 if translated into microseconds. + * @switch_time: switch time the peer sent in its channel switch timing IE + * @switch_timeout: switch timeout the peer sent in its channel switch timing IE + */ +struct iwl_tdls_channel_switch_timing { + __le32 frame_timestamp; /* GP2 time of peer packet Rx */ + __le32 max_offchan_duration; /* given in micro-seconds */ + __le32 switch_time; /* given in micro-seconds */ + __le32 switch_timeout; /* given in micro-seconds */ +} __packed; /* TDLS_STA_CHANNEL_SWITCH_TIMING_DATA_API_S_VER_1 */ + +#define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200 + +/** + * struct iwl_tdls_channel_switch_frame - TDLS channel switch frame template + * + * A template representing a TDLS channel-switch request or response frame + * + * @switch_time_offset: offset to the channel switch timing IE in the template + * @tx_cmd: Tx parameters for the frame + * @data: frame data + */ +struct iwl_tdls_channel_switch_frame { + __le32 switch_time_offset; + struct iwl_tx_cmd tx_cmd; + u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE]; +} __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ + +/** + * struct iwl_tdls_channel_switch_cmd - TDLS channel switch command + * + * The command is sent to initiate a channel switch and also in response to + * incoming TDLS channel-switch request/response packets from remote peers. + * + * @switch_type: see &enum iwl_tdls_channel_switch_type + * @peer_sta_id: station id of TDLS peer + * @ci: channel we switch to + * @timing: timing related data for command + * @frame: channel-switch request/response template, depending to switch_type + */ +struct iwl_tdls_channel_switch_cmd { + u8 switch_type; + __le32 peer_sta_id; + struct iwl_fw_channel_info ci; + struct iwl_tdls_channel_switch_timing timing; + struct iwl_tdls_channel_switch_frame frame; +} __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ + +/** + * struct iwl_tdls_channel_switch_notif - TDLS channel switch start notification + * + * @status: non-zero on success + * @offchannel_duration: duration given in microseconds + * @sta_id: peer currently performing the channel-switch with + */ +struct iwl_tdls_channel_switch_notif { + __le32 status; + __le32 offchannel_duration; + __le32 sta_id; +} __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */ + +/** + * struct iwl_tdls_sta_info - TDLS station info + * + * @sta_id: station id of the TDLS peer + * @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx + * @tx_to_peer_ssn: initial SSN the FW should use for Tx on its TID vs the peer + * @is_initiator: 1 if the peer is the TDLS link initiator, 0 otherwise + */ +struct iwl_tdls_sta_info { + u8 sta_id; + u8 tx_to_peer_tid; + __le16 tx_to_peer_ssn; + __le32 is_initiator; +} __packed; /* TDLS_STA_INFO_VER_1 */ + +/** + * struct iwl_tdls_config_cmd - TDLS basic config command + * + * @id_and_color: MAC id and color being configured + * @tdls_peer_count: amount of currently connected TDLS peers + * @tx_to_ap_tid: TID reverved vs. the AP for FW based Tx + * @tx_to_ap_ssn: initial SSN the FW should use for Tx on its TID vs. the AP + * @sta_info: per-station info. Only the first tdls_peer_count entries are set + * @pti_req_data_offset: offset of network-level data for the PTI template + * @pti_req_tx_cmd: Tx parameters for PTI request template + * @pti_req_template: PTI request template data + */ +struct iwl_tdls_config_cmd { + __le32 id_and_color; /* mac id and color */ + u8 tdls_peer_count; + u8 tx_to_ap_tid; + __le16 tx_to_ap_ssn; + struct iwl_tdls_sta_info sta_info[IWL_MVM_TDLS_STA_COUNT]; + + __le32 pti_req_data_offset; + struct iwl_tx_cmd pti_req_tx_cmd; + u8 pti_req_template[0]; +} __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ + +/** + * struct iwl_tdls_config_sta_info_res - TDLS per-station config information + * + * @sta_id: station id of the TDLS peer + * @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to + * the peer + */ +struct iwl_tdls_config_sta_info_res { + __le16 sta_id; + __le16 tx_to_peer_last_seq; +} __packed; /* TDLS_STA_INFO_RSP_VER_1 */ + +/** + * struct iwl_tdls_config_res - TDLS config information from FW + * + * @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP + * @sta_info: per-station TDLS config information + */ +struct iwl_tdls_config_res { + __le32 tx_to_ap_last_seq; + struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT]; +} __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */ + +#endif /* __iwl_fw_api_tdls_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h new file mode 100644 index 000000000000..3721a3ed358b --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -0,0 +1,386 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +#ifndef __iwl_fw_api_time_event_h__ +#define __iwl_fw_api_time_event_h__ + +#include "fw/api/phy-ctxt.h" + +/* Time Event types, according to MAC type */ +enum iwl_time_event_type { + /* BSS Station Events */ + TE_BSS_STA_AGGRESSIVE_ASSOC, + TE_BSS_STA_ASSOC, + TE_BSS_EAP_DHCP_PROT, + TE_BSS_QUIET_PERIOD, + + /* P2P Device Events */ + TE_P2P_DEVICE_DISCOVERABLE, + TE_P2P_DEVICE_LISTEN, + TE_P2P_DEVICE_ACTION_SCAN, + TE_P2P_DEVICE_FULL_SCAN, + + /* P2P Client Events */ + TE_P2P_CLIENT_AGGRESSIVE_ASSOC, + TE_P2P_CLIENT_ASSOC, + TE_P2P_CLIENT_QUIET_PERIOD, + + /* P2P GO Events */ + TE_P2P_GO_ASSOC_PROT, + TE_P2P_GO_REPETITIVET_NOA, + TE_P2P_GO_CT_WINDOW, + + /* WiDi Sync Events */ + TE_WIDI_TX_SYNC, + + /* Channel Switch NoA */ + TE_CHANNEL_SWITCH_PERIOD, + + TE_MAX +}; /* MAC_EVENT_TYPE_API_E_VER_1 */ + +/* Time event - defines for command API v1 */ + +/* + * @TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. + * @TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only + * the first fragment is scheduled. + * @TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only + * the first 2 fragments are scheduled. + * @TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any + * number of fragments are valid. + * + * Other than the constant defined above, specifying a fragmentation value 'x' + * means that the event can be fragmented but only the first 'x' will be + * scheduled. + */ +enum { + TE_V1_FRAG_NONE = 0, + TE_V1_FRAG_SINGLE = 1, + TE_V1_FRAG_DUAL = 2, + TE_V1_FRAG_ENDLESS = 0xffffffff +}; + +/* If a Time Event can be fragmented, this is the max number of fragments */ +#define TE_V1_FRAG_MAX_MSK 0x0fffffff +/* Repeat the time event endlessly (until removed) */ +#define TE_V1_REPEAT_ENDLESS 0xffffffff +/* If a Time Event has bounded repetitions, this is the maximal value */ +#define TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff + +/* Time Event dependencies: none, on another TE, or in a specific time */ +enum { + TE_V1_INDEPENDENT = 0, + TE_V1_DEP_OTHER = BIT(0), + TE_V1_DEP_TSF = BIT(1), + TE_V1_EVENT_SOCIOPATHIC = BIT(2), +}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ + +/* + * @TE_V1_NOTIF_NONE: no notifications + * @TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start + * @TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end + * @TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use + * @TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. + * @TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start + * @TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end + * @TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. + * @TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. + * + * Supported Time event notifications configuration. + * A notification (both event and fragment) includes a status indicating weather + * the FW was able to schedule the event or not. For fragment start/end + * notification the status is always success. There is no start/end fragment + * notification for monolithic events. + */ +enum { + TE_V1_NOTIF_NONE = 0, + TE_V1_NOTIF_HOST_EVENT_START = BIT(0), + TE_V1_NOTIF_HOST_EVENT_END = BIT(1), + TE_V1_NOTIF_INTERNAL_EVENT_START = BIT(2), + TE_V1_NOTIF_INTERNAL_EVENT_END = BIT(3), + TE_V1_NOTIF_HOST_FRAG_START = BIT(4), + TE_V1_NOTIF_HOST_FRAG_END = BIT(5), + TE_V1_NOTIF_INTERNAL_FRAG_START = BIT(6), + TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7), +}; /* MAC_EVENT_ACTION_API_E_VER_2 */ + +/* Time event - defines for command API */ + +/* + * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. + * @TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only + * the first fragment is scheduled. + * @TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only + * the first 2 fragments are scheduled. + * @TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any + * number of fragments are valid. + * + * Other than the constant defined above, specifying a fragmentation value 'x' + * means that the event can be fragmented but only the first 'x' will be + * scheduled. + */ +enum { + TE_V2_FRAG_NONE = 0, + TE_V2_FRAG_SINGLE = 1, + TE_V2_FRAG_DUAL = 2, + TE_V2_FRAG_MAX = 0xfe, + TE_V2_FRAG_ENDLESS = 0xff +}; + +/* Repeat the time event endlessly (until removed) */ +#define TE_V2_REPEAT_ENDLESS 0xff +/* If a Time Event has bounded repetitions, this is the maximal value */ +#define TE_V2_REPEAT_MAX 0xfe + +#define TE_V2_PLACEMENT_POS 12 +#define TE_V2_ABSENCE_POS 15 + +/** + * enum iwl_time_event_policy - Time event policy values + * A notification (both event and fragment) includes a status indicating weather + * the FW was able to schedule the event or not. For fragment start/end + * notification the status is always success. There is no start/end fragment + * notification for monolithic events. + * + * @TE_V2_DEFAULT_POLICY: independent, social, present, unoticable + * @TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start + * @TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end + * @TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use + * @TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. + * @TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start + * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end + * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. + * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. + * @T2_V2_START_IMMEDIATELY: start time event immediately + * @TE_V2_DEP_OTHER: depends on another time event + * @TE_V2_DEP_TSF: depends on a specific time + * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC + * @TE_V2_ABSENCE: are we present or absent during the Time Event. + */ +enum iwl_time_event_policy { + TE_V2_DEFAULT_POLICY = 0x0, + + /* notifications (event start/stop, fragment start/stop) */ + TE_V2_NOTIF_HOST_EVENT_START = BIT(0), + TE_V2_NOTIF_HOST_EVENT_END = BIT(1), + TE_V2_NOTIF_INTERNAL_EVENT_START = BIT(2), + TE_V2_NOTIF_INTERNAL_EVENT_END = BIT(3), + + TE_V2_NOTIF_HOST_FRAG_START = BIT(4), + TE_V2_NOTIF_HOST_FRAG_END = BIT(5), + TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), + TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), + T2_V2_START_IMMEDIATELY = BIT(11), + + /* placement characteristics */ + TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), + TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), + TE_V2_EVENT_SOCIOPATHIC = BIT(TE_V2_PLACEMENT_POS + 2), + + /* are we present or absent during the Time Event. */ + TE_V2_ABSENCE = BIT(TE_V2_ABSENCE_POS), +}; + +/** + * struct iwl_time_event_cmd - configuring Time Events + * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also + * with version 1. determined by IWL_UCODE_TLV_FLAGS) + * ( TIME_EVENT_CMD = 0x29 ) + * @id_and_color: ID and color of the relevant MAC, + * &enum iwl_ctxt_id_and_color + * @action: action to perform, one of &enum iwl_ctxt_action + * @id: this field has two meanings, depending on the action: + * If the action is ADD, then it means the type of event to add. + * For all other actions it is the unique event ID assigned when the + * event was added by the FW. + * @apply_time: When to start the Time Event (in GP2) + * @max_delay: maximum delay to event's start (apply time), in TU + * @depends_on: the unique ID of the event we depend on (if any) + * @interval: interval between repetitions, in TU + * @duration: duration of event in TU + * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS + * @max_frags: maximal number of fragments the Time Event can be divided to + * @policy: defines whether uCode shall notify the host or other uCode modules + * on event and/or fragment start and/or end + * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF + * TE_EVENT_SOCIOPATHIC + * using TE_ABSENCE and using TE_NOTIF_*, + * &enum iwl_time_event_policy + */ +struct iwl_time_event_cmd { + /* COMMON_INDEX_HDR_API_S_VER_1 */ + __le32 id_and_color; + __le32 action; + __le32 id; + /* MAC_TIME_EVENT_DATA_API_S_VER_2 */ + __le32 apply_time; + __le32 max_delay; + __le32 depends_on; + __le32 interval; + __le32 duration; + u8 repeat; + u8 max_frags; + __le16 policy; +} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_2 */ + +/** + * struct iwl_time_event_resp - response structure to iwl_time_event_cmd + * @status: bit 0 indicates success, all others specify errors + * @id: the Time Event type + * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE + * @id_and_color: ID and color of the relevant MAC, + * &enum iwl_ctxt_id_and_color + */ +struct iwl_time_event_resp { + __le32 status; + __le32 id; + __le32 unique_id; + __le32 id_and_color; +} __packed; /* MAC_TIME_EVENT_RSP_API_S_VER_1 */ + +/** + * struct iwl_time_event_notif - notifications of time event start/stop + * ( TIME_EVENT_NOTIFICATION = 0x2a ) + * @timestamp: action timestamp in GP2 + * @session_id: session's unique id + * @unique_id: unique id of the Time Event itself + * @id_and_color: ID and color of the relevant MAC + * @action: &enum iwl_time_event_policy + * @status: true if scheduled, false otherwise (not executed) + */ +struct iwl_time_event_notif { + __le32 timestamp; + __le32 session_id; + __le32 unique_id; + __le32 id_and_color; + __le32 action; + __le32 status; +} __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */ + +/* + * Aux ROC command + * + * Command requests the firmware to create a time event for a certain duration + * and remain on the given channel. This is done by using the Aux framework in + * the FW. + * The command was first used for Hot Spot issues - but can be used regardless + * to Hot Spot. + * + * ( HOT_SPOT_CMD 0x53 ) + * + * @id_and_color: ID and color of the MAC + * @action: action to perform, one of FW_CTXT_ACTION_* + * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the + * event_unique_id should be the id of the time event assigned by ucode. + * Otherwise ignore the event_unique_id. + * @sta_id_and_color: station id and color, resumed during "Remain On Channel" + * activity. + * @channel_info: channel info + * @node_addr: Our MAC Address + * @reserved: reserved for alignment + * @apply_time: GP2 value to start (should always be the current GP2 value) + * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max + * time by which start of the event is allowed to be postponed. + * @duration: event duration in TU To calculate event duration: + * timeEventDuration = min(duration, remainingQuota) + */ +struct iwl_hs20_roc_req { + /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ + __le32 id_and_color; + __le32 action; + __le32 event_unique_id; + __le32 sta_id_and_color; + struct iwl_fw_channel_info channel_info; + u8 node_addr[ETH_ALEN]; + __le16 reserved; + __le32 apply_time; + __le32 apply_time_max_delay; + __le32 duration; +} __packed; /* HOT_SPOT_CMD_API_S_VER_1 */ + +/* + * values for AUX ROC result values + */ +enum iwl_mvm_hot_spot { + HOT_SPOT_RSP_STATUS_OK, + HOT_SPOT_RSP_STATUS_TOO_MANY_EVENTS, + HOT_SPOT_MAX_NUM_OF_SESSIONS, +}; + +/* + * Aux ROC command response + * + * In response to iwl_hs20_roc_req the FW sends this command to notify the + * driver the uid of the timevent. + * + * ( HOT_SPOT_CMD 0x53 ) + * + * @event_unique_id: Unique ID of time event assigned by ucode + * @status: Return status 0 is success, all the rest used for specific errors + */ +struct iwl_hs20_roc_res { + __le32 event_unique_id; + __le32 status; +} __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ + +#endif /* __iwl_fw_api_time_event_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tof.h index 8658a983c463..7328a1606146 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tof.h @@ -16,11 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -60,8 +55,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#ifndef __fw_api_tof_h__ -#define __fw_api_tof_h__ +#ifndef __iwl_fw_api_tof_h__ +#define __iwl_fw_api_tof_h__ /* ToF sub-group command IDs */ enum iwl_mvm_tof_sub_grp_ids { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 97d7eed32622..14ad9fb895f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -17,11 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -62,8 +57,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __fw_api_tx_h__ -#define __fw_api_tx_h__ +#ifndef __iwl_fw_api_tx_h__ +#define __iwl_fw_api_tx_h__ /** * enum iwl_tx_flags - bitmasks for tx_flags in TX command @@ -414,7 +409,8 @@ enum iwl_tx_status { * @AGG_TX_STATE_BT_PRIO: * @AGG_TX_STATE_FEW_BYTES: * @AGG_TX_STATE_ABORT: - * @AGG_TX_STATE_LAST_SENT_TTL: + * @AGG_TX_STATE_TX_ON_AIR_DROP: TX_ON_AIR signal drop without underrun or + * BT detection * @AGG_TX_STATE_LAST_SENT_TRY_CNT: * @AGG_TX_STATE_LAST_SENT_BT_KILL: * @AGG_TX_STATE_SCD_QUERY: @@ -426,7 +422,7 @@ enum iwl_tx_status { * occur if tx failed for this frame when it was a member of a previous * aggregation block). If rate scaling is used, retry count indicates the * rate table entry used for all frames in the new agg. - *@ AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for + * @AGG_TX_STATE_SEQ_NUM_MSK: Command ID and sequence number of Tx command for * this frame * * TODO: complete documentation @@ -438,7 +434,7 @@ enum iwl_tx_agg_status { AGG_TX_STATE_BT_PRIO = 0x002, AGG_TX_STATE_FEW_BYTES = 0x004, AGG_TX_STATE_ABORT = 0x008, - AGG_TX_STATE_LAST_SENT_TTL = 0x010, + AGG_TX_STATE_TX_ON_AIR_DROP = 0x010, AGG_TX_STATE_LAST_SENT_TRY_CNT = 0x020, AGG_TX_STATE_LAST_SENT_BT_KILL = 0x040, AGG_TX_STATE_SCD_QUERY = 0x080, @@ -450,10 +446,6 @@ enum iwl_tx_agg_status { AGG_TX_STATE_TRY_CNT_MSK = 0xf << AGG_TX_STATE_TRY_CNT_POS, }; -#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL| \ - AGG_TX_STATE_LAST_SENT_TRY_CNT| \ - AGG_TX_STATE_LAST_SENT_BT_KILL) - /* * The mask below describes a status where we are absolutely sure that the MPDU * wasn't sent. For BA/Underrun we cannot be that sure. All we know that we've @@ -771,7 +763,8 @@ struct iwl_mac_beacon_cmd_v6 { } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_6 */ /** - * struct iwl_mac_beacon_cmd_data - data of beacon template with offloaded CSA + * struct iwl_mac_beacon_cmd_v7 - beacon template command with offloaded CSA + * @tx: the tx commands associated with the beacon frame * @template_id: currently equal to the mac context id of the coresponding * mac. * @tim_idx: the offset of the tim IE in the beacon @@ -780,38 +773,47 @@ struct iwl_mac_beacon_cmd_v6 { * @csa_offset: offset to the CSA IE if present * @frame: the template of the beacon frame */ -struct iwl_mac_beacon_cmd_data { +struct iwl_mac_beacon_cmd_v7 { + struct iwl_tx_cmd tx; __le32 template_id; __le32 tim_idx; __le32 tim_size; __le32 ecsa_offset; __le32 csa_offset; struct ieee80211_hdr frame[0]; -}; - -/** - * struct iwl_mac_beacon_cmd_v7 - beacon template command with offloaded CSA - * @tx: the tx commands associated with the beacon frame - * @data: see &iwl_mac_beacon_cmd_data - */ -struct iwl_mac_beacon_cmd_v7 { - struct iwl_tx_cmd tx; - struct iwl_mac_beacon_cmd_data data; } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_7 */ +enum iwl_mac_beacon_flags { + IWL_MAC_BEACON_CCK = BIT(8), + IWL_MAC_BEACON_ANT_A = BIT(9), + IWL_MAC_BEACON_ANT_B = BIT(10), + IWL_MAC_BEACON_ANT_C = BIT(11), +}; + /** * struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA - * @byte_cnt: byte count of the beacon frame - * @flags: for future use + * @byte_cnt: byte count of the beacon frame. + * @flags: least significant byte for rate code. The most significant byte + * is &enum iwl_mac_beacon_flags. * @reserved: reserved - * @data: see &iwl_mac_beacon_cmd_data + * @template_id: currently equal to the mac context id of the coresponding mac. + * @tim_idx: the offset of the tim IE in the beacon + * @tim_size: the length of the tim IE + * @ecsa_offset: offset to the ECSA IE if present + * @csa_offset: offset to the CSA IE if present + * @frame: the template of the beacon frame */ struct iwl_mac_beacon_cmd { __le16 byte_cnt; __le16 flags; __le64 reserved; - struct iwl_mac_beacon_cmd_data data; -} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_8 */ + __le32 template_id; + __le32 tim_idx; + __le32 tim_size; + __le32 ecsa_offset; + __le32 csa_offset; + struct ieee80211_hdr frame[0]; +} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_9 */ struct iwl_beacon_notif { struct iwl_mvm_tx_resp beacon_notify_hdr; @@ -914,4 +916,4 @@ struct iwl_scd_txq_cfg_rsp { u8 scd_queue; } __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */ -#endif /* __fw_api_tx_h__ */ +#endif /* __iwl_fw_api_tx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h new file mode 100644 index 000000000000..87b4434224a1 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_api_txq_h__ +#define __iwl_fw_api_txq_h__ + +/* + * DQA queue numbers + * + * @IWL_MVM_DQA_CMD_QUEUE: a queue reserved for sending HCMDs to the FW + * @IWL_MVM_DQA_AUX_QUEUE: a queue reserved for aux frames + * @IWL_MVM_DQA_P2P_DEVICE_QUEUE: a queue reserved for P2P device frames + * @IWL_MVM_DQA_GCAST_QUEUE: a queue reserved for P2P GO/SoftAP GCAST frames + * @IWL_MVM_DQA_BSS_CLIENT_QUEUE: a queue reserved for BSS activity, to ensure + * that we are never left without the possibility to connect to an AP. + * @IWL_MVM_DQA_MIN_MGMT_QUEUE: first TXQ in pool for MGMT and non-QOS frames. + * Each MGMT queue is mapped to a single STA + * MGMT frames are frames that return true on ieee80211_is_mgmt() + * @IWL_MVM_DQA_MAX_MGMT_QUEUE: last TXQ in pool for MGMT frames + * @IWL_MVM_DQA_AP_PROBE_RESP_QUEUE: a queue reserved for P2P GO/SoftAP probe + * responses + * @IWL_MVM_DQA_MIN_DATA_QUEUE: first TXQ in pool for DATA frames. + * DATA frames are intended for !ieee80211_is_mgmt() frames, but if + * the MGMT TXQ pool is exhausted, mgmt frames can be sent on DATA queues + * as well + * @IWL_MVM_DQA_MAX_DATA_QUEUE: last TXQ in pool for DATA frames + */ +enum iwl_mvm_dqa_txq { + IWL_MVM_DQA_CMD_QUEUE = 0, + IWL_MVM_DQA_AUX_QUEUE = 1, + IWL_MVM_DQA_P2P_DEVICE_QUEUE = 2, + IWL_MVM_DQA_GCAST_QUEUE = 3, + IWL_MVM_DQA_BSS_CLIENT_QUEUE = 4, + IWL_MVM_DQA_MIN_MGMT_QUEUE = 5, + IWL_MVM_DQA_MAX_MGMT_QUEUE = 8, + IWL_MVM_DQA_AP_PROBE_RESP_QUEUE = 9, + IWL_MVM_DQA_MIN_DATA_QUEUE = 10, + IWL_MVM_DQA_MAX_DATA_QUEUE = 31, +}; + +enum iwl_mvm_tx_fifo { + IWL_MVM_TX_FIFO_BK = 0, + IWL_MVM_TX_FIFO_BE, + IWL_MVM_TX_FIFO_VI, + IWL_MVM_TX_FIFO_VO, + IWL_MVM_TX_FIFO_MCAST = 5, + IWL_MVM_TX_FIFO_CMD = 7, +}; + +enum iwl_gen2_tx_fifo { + IWL_GEN2_TX_FIFO_CMD = 0, + IWL_GEN2_EDCA_TX_FIFO_BK, + IWL_GEN2_EDCA_TX_FIFO_BE, + IWL_GEN2_EDCA_TX_FIFO_VI, + IWL_GEN2_EDCA_TX_FIFO_VO, + IWL_GEN2_TRIG_TX_FIFO_BK, + IWL_GEN2_TRIG_TX_FIFO_BE, + IWL_GEN2_TRIG_TX_FIFO_VI, + IWL_GEN2_TRIG_TX_FIFO_VO, +}; + +/** + * enum iwl_tx_queue_cfg_actions - TXQ config options + * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue + * @TX_QUEUE_CFG_TFD_SHORT_FORMAT: use short TFD format + */ +enum iwl_tx_queue_cfg_actions { + TX_QUEUE_CFG_ENABLE_QUEUE = BIT(0), + TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), +}; + +/** + * struct iwl_tx_queue_cfg_cmd - txq hw scheduler config command + * @sta_id: station id + * @tid: tid of the queue + * @flags: see &enum iwl_tx_queue_cfg_actions + * @cb_size: size of TFD cyclic buffer. Value is exponent - 3. + * Minimum value 0 (8 TFDs), maximum value 5 (256 TFDs) + * @byte_cnt_addr: address of byte count table + * @tfdq_addr: address of TFD circular buffer + */ +struct iwl_tx_queue_cfg_cmd { + u8 sta_id; + u8 tid; + __le16 flags; + __le32 cb_size; + __le64 byte_cnt_addr; + __le64 tfdq_addr; +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_2 */ + +/** + * struct iwl_tx_queue_cfg_rsp - response to txq hw scheduler config + * @queue_number: queue number assigned to this RA -TID + * @flags: set on failure + * @write_pointer: initial value for write pointer + * @reserved: reserved + */ +struct iwl_tx_queue_cfg_rsp { + __le16 queue_number; + __le16 flags; + __le16 write_pointer; + __le16 reserved; +} __packed; /* TX_QUEUE_CFG_RSP_API_S_VER_2 */ + +#endif /* __iwl_fw_api_txq_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/common_rx.c b/drivers/net/wireless/intel/iwlwifi/fw/common_rx.c new file mode 100644 index 000000000000..6f75985eea66 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/common_rx.c @@ -0,0 +1,88 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "iwl-drv.h" +#include "runtime.h" +#include "fw/api/commands.h" +#include "fw/api/alive.h" + +static void iwl_fwrt_fseq_ver_mismatch(struct iwl_fw_runtime *fwrt, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_fseq_ver_mismatch_ntf *fseq = (void *)pkt->data; + + IWL_ERR(fwrt, "FSEQ version mismatch (aux: %d, wifi: %d)\n", + __le32_to_cpu(fseq->aux_read_fseq_ver), + __le32_to_cpu(fseq->wifi_fseq_ver)); +} + +void iwl_fwrt_handle_notification(struct iwl_fw_runtime *fwrt, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u32 cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); + + switch (cmd) { + case WIDE_ID(SYSTEM_GROUP, FSEQ_VER_MISMATCH_NTF): + iwl_fwrt_fseq_ver_mismatch(fwrt, rxb); + break; + default: + break; + } +} +IWL_EXPORT_SYMBOL(iwl_fwrt_handle_notification); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 1602b360353c..6afc7a799892 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -63,22 +63,37 @@ * *****************************************************************************/ #include <linux/devcoredump.h> - -#include "fw-dbg.h" +#include "iwl-drv.h" +#include "runtime.h" +#include "dbg.h" #include "iwl-io.h" -#include "mvm.h" #include "iwl-prph.h" #include "iwl-csr.h" +/** + * struct iwl_fw_dump_ptrs - set of pointers needed for the fw-error-dump + * + * @fwrt_ptr: pointer to the buffer coming from fwrt + * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the + * transport's data. + * @trans_len: length of the valid data in trans_ptr + * @fwrt_len: length of the valid data in fwrt_ptr + */ +struct iwl_fw_dump_ptrs { + struct iwl_trans_dump_data *trans_ptr; + void *fwrt_ptr; + u32 fwrt_len; +}; + #define RADIO_REG_MAX_READ 0x2ad -static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm, - struct iwl_fw_error_dump_data **dump_data) +static void iwl_read_radio_regs(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data) { u8 *pos = (void *)(*dump_data)->data; unsigned long flags; int i; - if (!iwl_trans_grab_nic_access(mvm->trans, &flags)) + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) return; (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RADIO_REG); @@ -88,20 +103,20 @@ static void iwl_mvm_read_radio_reg(struct iwl_mvm *mvm, u32 rd_cmd = RADIO_RSP_RD_CMD; rd_cmd |= i << RADIO_RSP_ADDR_POS; - iwl_write_prph_no_grab(mvm->trans, RSP_RADIO_CMD, rd_cmd); - *pos = (u8)iwl_read_prph_no_grab(mvm->trans, RSP_RADIO_RDDAT); + iwl_write_prph_no_grab(fwrt->trans, RSP_RADIO_CMD, rd_cmd); + *pos = (u8)iwl_read_prph_no_grab(fwrt->trans, RSP_RADIO_RDDAT); pos++; } *dump_data = iwl_fw_error_next_data(*dump_data); - iwl_trans_release_nic_access(mvm->trans, &flags); + iwl_trans_release_nic_access(fwrt->trans, &flags); } -static void iwl_mvm_dump_rxf(struct iwl_mvm *mvm, - struct iwl_fw_error_dump_data **dump_data, - int size, u32 offset, int fifo_num) +static void iwl_fwrt_dump_rxf(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data, + int size, u32 offset, int fifo_num) { struct iwl_fw_error_dump_fifo *fifo_hdr; u32 *fifo_data; @@ -122,41 +137,41 @@ static void iwl_mvm_dump_rxf(struct iwl_mvm *mvm, fifo_hdr->fifo_num = cpu_to_le32(fifo_num); fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, RXF_RD_D_SPACE + offset)); fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, RXF_RD_WR_PTR + offset)); fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, RXF_RD_RD_PTR + offset)); fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, RXF_RD_FENCE_PTR + offset)); fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, RXF_SET_FENCE_MODE + offset)); /* Lock fence */ - iwl_trans_write_prph(mvm->trans, RXF_SET_FENCE_MODE + offset, 0x1); + iwl_trans_write_prph(fwrt->trans, RXF_SET_FENCE_MODE + offset, 0x1); /* Set fence pointer to the same place like WR pointer */ - iwl_trans_write_prph(mvm->trans, RXF_LD_WR2FENCE + offset, 0x1); + iwl_trans_write_prph(fwrt->trans, RXF_LD_WR2FENCE + offset, 0x1); /* Set fence offset */ - iwl_trans_write_prph(mvm->trans, + iwl_trans_write_prph(fwrt->trans, RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (i = 0; i < fifo_len; i++) - fifo_data[i] = iwl_trans_read_prph(mvm->trans, + fifo_data[i] = iwl_trans_read_prph(fwrt->trans, RXF_FIFO_RD_FENCE_INC + offset); *dump_data = iwl_fw_error_next_data(*dump_data); } -static void iwl_mvm_dump_txf(struct iwl_mvm *mvm, - struct iwl_fw_error_dump_data **dump_data, - int size, u32 offset, int fifo_num) +static void iwl_fwrt_dump_txf(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data, + int size, u32 offset, int fifo_num) { struct iwl_fw_error_dump_fifo *fifo_hdr; u32 *fifo_data; @@ -177,91 +192,91 @@ static void iwl_mvm_dump_txf(struct iwl_mvm *mvm, fifo_hdr->fifo_num = cpu_to_le32(fifo_num); fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_FIFO_ITEM_CNT + offset)); fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_WR_PTR + offset)); fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_RD_PTR + offset)); fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_FENCE_PTR + offset)); fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_LOCK_FENCE + offset)); /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ - iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR + offset, + iwl_trans_write_prph(fwrt->trans, TXF_READ_MODIFY_ADDR + offset, TXF_WR_PTR + offset); /* Dummy-read to advance the read pointer to the head */ - iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA + offset); + iwl_trans_read_prph(fwrt->trans, TXF_READ_MODIFY_DATA + offset); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (i = 0; i < fifo_len; i++) - fifo_data[i] = iwl_trans_read_prph(mvm->trans, + fifo_data[i] = iwl_trans_read_prph(fwrt->trans, TXF_READ_MODIFY_DATA + offset); *dump_data = iwl_fw_error_next_data(*dump_data); } -static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, - struct iwl_fw_error_dump_data **dump_data) +static void iwl_fw_dump_fifos(struct iwl_fw_runtime *fwrt, + struct iwl_fw_error_dump_data **dump_data) { struct iwl_fw_error_dump_fifo *fifo_hdr; - struct iwl_mvm_shared_mem_cfg *cfg = &mvm->smem_cfg; + struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg; u32 *fifo_data; u32 fifo_len; unsigned long flags; int i, j; - if (!iwl_trans_grab_nic_access(mvm->trans, &flags)) + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) return; /* Pull RXF1 */ - iwl_mvm_dump_rxf(mvm, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0); + iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->lmac[0].rxfifo1_size, 0, 0); /* Pull RXF2 */ - iwl_mvm_dump_rxf(mvm, dump_data, cfg->rxfifo2_size, - RXF_DIFF_FROM_PREV, 1); + iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->rxfifo2_size, + RXF_DIFF_FROM_PREV, 1); /* Pull LMAC2 RXF1 */ - if (mvm->smem_cfg.num_lmacs > 1) - iwl_mvm_dump_rxf(mvm, dump_data, cfg->lmac[1].rxfifo1_size, - LMAC2_PRPH_OFFSET, 2); + if (fwrt->smem_cfg.num_lmacs > 1) + iwl_fwrt_dump_rxf(fwrt, dump_data, cfg->lmac[1].rxfifo1_size, + LMAC2_PRPH_OFFSET, 2); /* Pull TXF data from LMAC1 */ - for (i = 0; i < mvm->smem_cfg.num_txfifo_entries; i++) { + for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i); - iwl_mvm_dump_txf(mvm, dump_data, cfg->lmac[0].txfifo_size[i], - 0, i); + iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM, i); + iwl_fwrt_dump_txf(fwrt, dump_data, cfg->lmac[0].txfifo_size[i], + 0, i); } /* Pull TXF data from LMAC2 */ - if (mvm->smem_cfg.num_lmacs > 1) { - for (i = 0; i < mvm->smem_cfg.num_txfifo_entries; i++) { + if (fwrt->smem_cfg.num_lmacs > 1) { + for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(mvm->trans, + iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM + LMAC2_PRPH_OFFSET, i); - iwl_mvm_dump_txf(mvm, dump_data, - cfg->lmac[1].txfifo_size[i], - LMAC2_PRPH_OFFSET, - i + cfg->num_txfifo_entries); + iwl_fwrt_dump_txf(fwrt, dump_data, + cfg->lmac[1].txfifo_size[i], + LMAC2_PRPH_OFFSET, + i + cfg->num_txfifo_entries); } } - if (fw_has_capa(&mvm->fw->ucode_capa, + if (fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { /* Pull UMAC internal TXF data from all TXFs */ for (i = 0; - i < ARRAY_SIZE(mvm->smem_cfg.internal_txfifo_size); + i < ARRAY_SIZE(fwrt->smem_cfg.internal_txfifo_size); i++) { fifo_hdr = (void *)(*dump_data)->data; fifo_data = (void *)fifo_hdr->data; - fifo_len = mvm->smem_cfg.internal_txfifo_size[i]; + fifo_len = fwrt->smem_cfg.internal_txfifo_size[i]; /* No need to try to read the data if the length is 0 */ if (fifo_len == 0) @@ -276,52 +291,45 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm, fifo_hdr->fifo_num = cpu_to_le32(i); /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i + - mvm->smem_cfg.num_txfifo_entries); + iwl_trans_write_prph(fwrt->trans, TXF_CPU2_NUM, i + + fwrt->smem_cfg.num_txfifo_entries); fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_CPU2_FIFO_ITEM_CNT)); fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_CPU2_WR_PTR)); fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_CPU2_RD_PTR)); fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_CPU2_FENCE_PTR)); fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(mvm->trans, + cpu_to_le32(iwl_trans_read_prph(fwrt->trans, TXF_CPU2_LOCK_FENCE)); /* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */ - iwl_trans_write_prph(mvm->trans, + iwl_trans_write_prph(fwrt->trans, TXF_CPU2_READ_MODIFY_ADDR, TXF_CPU2_WR_PTR); /* Dummy-read to advance the read pointer to head */ - iwl_trans_read_prph(mvm->trans, + iwl_trans_read_prph(fwrt->trans, TXF_CPU2_READ_MODIFY_DATA); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (j = 0; j < fifo_len; j++) fifo_data[j] = - iwl_trans_read_prph(mvm->trans, + iwl_trans_read_prph(fwrt->trans, TXF_CPU2_READ_MODIFY_DATA); *dump_data = iwl_fw_error_next_data(*dump_data); } } - iwl_trans_release_nic_access(mvm->trans, &flags); -} - -void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm) -{ - if (mvm->fw_dump_desc != &iwl_mvm_dump_desc_assert) - kfree(mvm->fw_dump_desc); - mvm->fw_dump_desc = NULL; + iwl_trans_release_nic_access(fwrt->trans, &flags); } #define IWL8260_ICCM_OFFSET 0x44000 /* Only for B-step */ @@ -531,37 +539,34 @@ static struct scatterlist *alloc_sgtable(int size) return table; } -void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) +void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt) { struct iwl_fw_error_dump_file *dump_file; struct iwl_fw_error_dump_data *dump_data; struct iwl_fw_error_dump_info *dump_info; struct iwl_fw_error_dump_mem *dump_mem; + struct iwl_fw_error_dump_smem_cfg *dump_smem_cfg; struct iwl_fw_error_dump_trigger_desc *dump_trig; - struct iwl_mvm_dump_ptrs *fw_error_dump; + struct iwl_fw_dump_ptrs *fw_error_dump; struct scatterlist *sg_dump_data; u32 sram_len, sram_ofs; - const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = mvm->fw->dbg_mem_tlv; + const struct iwl_fw_dbg_mem_seg_tlv *fw_dbg_mem = fwrt->fw->dbg_mem_tlv; + struct iwl_fwrt_shared_mem_cfg *mem_cfg = &fwrt->smem_cfg; u32 file_len, fifo_data_len = 0, prph_len = 0, radio_len = 0; - u32 smem_len = mvm->fw->n_dbg_mem_tlv ? 0 : mvm->cfg->smem_len; - u32 sram2_len = mvm->fw->n_dbg_mem_tlv ? 0 : mvm->cfg->dccm2_len; + u32 smem_len = fwrt->fw->n_dbg_mem_tlv ? 0 : fwrt->trans->cfg->smem_len; + u32 sram2_len = fwrt->fw->n_dbg_mem_tlv ? + 0 : fwrt->trans->cfg->dccm2_len; bool monitor_dump_only = false; int i; - if (!IWL_MVM_COLLECT_FW_ERR_DUMP && - !mvm->trans->dbg_dest_tlv) - return; - - lockdep_assert_held(&mvm->mutex); - /* there's no point in fw dump if the bus is dead */ - if (test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { - IWL_ERR(mvm, "Skip fw error dump since bus is dead\n"); + if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) { + IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n"); goto out; } - if (mvm->fw_dump_trig && - mvm->fw_dump_trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) + if (fwrt->dump.trig && + fwrt->dump.trig->mode & IWL_FW_DBG_TRIGGER_MONITOR_ONLY) monitor_dump_only = true; fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL); @@ -569,21 +574,19 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) goto out; /* SRAM - include stack CCM if driver knows the values for it */ - if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) { + if (!fwrt->trans->cfg->dccm_offset || !fwrt->trans->cfg->dccm_len) { const struct fw_img *img; - img = &mvm->fw->img[mvm->cur_ucode]; + img = &fwrt->fw->img[fwrt->cur_fw_img]; sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; } else { - sram_ofs = mvm->cfg->dccm_offset; - sram_len = mvm->cfg->dccm_len; + sram_ofs = fwrt->trans->cfg->dccm_offset; + sram_len = fwrt->trans->cfg->dccm_len; } /* reading RXF/TXF sizes */ - if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { - struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->smem_cfg; - + if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { fifo_data_len = 0; /* Count RXF2 size */ @@ -621,7 +624,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } } - if (fw_has_capa(&mvm->fw->ucode_capa, + if (fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { for (i = 0; i < ARRAY_SIZE(mem_cfg->internal_txfifo_size); @@ -638,7 +641,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } /* Make room for PRPH registers */ - if (!mvm->trans->cfg->gen2) { + if (!fwrt->trans->cfg->gen2) { for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_comm); i++) { /* The range includes both boundaries */ @@ -652,7 +655,8 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } } - if (!mvm->trans->cfg->gen2 && mvm->cfg->mq_rx_supported) { + if (!fwrt->trans->cfg->gen2 && + fwrt->trans->cfg->mq_rx_supported) { for (i = 0; i < ARRAY_SIZE(iwl_prph_dump_addr_9000); i++) { /* The range includes both boundaries */ @@ -666,12 +670,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } } - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) + if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) radio_len = sizeof(*dump_data) + RADIO_REG_MAX_READ; } file_len = sizeof(*dump_file) + - sizeof(*dump_data) * 2 + + sizeof(*dump_data) * 3 + + sizeof(*dump_smem_cfg) + fifo_data_len + prph_len + radio_len + @@ -686,31 +691,31 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len; /* Make room for MEM segments */ - for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) { + for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { file_len += sizeof(*dump_data) + sizeof(*dump_mem) + le32_to_cpu(fw_dbg_mem[i].len); } /* Make room for fw's virtual image pages, if it exists */ - if (!mvm->trans->cfg->gen2 && - mvm->fw->img[mvm->cur_ucode].paging_mem_size && - mvm->fw_paging_db[0].fw_paging_block) - file_len += mvm->num_of_paging_blk * + if (!fwrt->trans->cfg->gen2 && + fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && + fwrt->fw_paging_db[0].fw_paging_block) + file_len += fwrt->num_of_paging_blk * (sizeof(*dump_data) + sizeof(struct iwl_fw_error_dump_paging) + PAGING_BLOCK_SIZE); /* If we only want a monitor dump, reset the file length */ if (monitor_dump_only) { - file_len = sizeof(*dump_file) + sizeof(*dump_data) + - sizeof(*dump_info); + file_len = sizeof(*dump_file) + sizeof(*dump_data) * 2 + + sizeof(*dump_info) + sizeof(*dump_smem_cfg); } - if (mvm->fw_dump_desc) + if (fwrt->dump.desc) file_len += sizeof(*dump_data) + sizeof(*dump_trig) + - mvm->fw_dump_desc->len; + fwrt->dump.desc->len; - if (!mvm->fw->n_dbg_mem_tlv) + if (!fwrt->fw->n_dbg_mem_tlv) file_len += sram_len + sizeof(*dump_mem); dump_file = vzalloc(file_len); @@ -719,7 +724,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) goto out; } - fw_error_dump->op_mode_ptr = dump_file; + fw_error_dump->fwrt_ptr = dump_file; dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); dump_data = (void *)dump_file->data; @@ -728,32 +733,59 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data->len = cpu_to_le32(sizeof(*dump_info)); dump_info = (void *)dump_data->data; dump_info->device_family = - mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? + fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000 ? cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) : cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8); - dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(mvm->trans->hw_rev)); - memcpy(dump_info->fw_human_readable, mvm->fw->human_readable, + dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(fwrt->trans->hw_rev)); + memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable, sizeof(dump_info->fw_human_readable)); - strncpy(dump_info->dev_human_readable, mvm->cfg->name, + strncpy(dump_info->dev_human_readable, fwrt->trans->cfg->name, sizeof(dump_info->dev_human_readable)); - strncpy(dump_info->bus_human_readable, mvm->dev->bus->name, + strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name, sizeof(dump_info->bus_human_readable)); dump_data = iwl_fw_error_next_data(dump_data); + + /* Dump shared memory configuration */ + dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_CFG); + dump_data->len = cpu_to_le32(sizeof(*dump_smem_cfg)); + dump_smem_cfg = (void *)dump_data->data; + dump_smem_cfg->num_lmacs = cpu_to_le32(mem_cfg->num_lmacs); + dump_smem_cfg->num_txfifo_entries = + cpu_to_le32(mem_cfg->num_txfifo_entries); + for (i = 0; i < MAX_NUM_LMAC; i++) { + int j; + + for (j = 0; j < TX_FIFO_MAX_NUM; j++) + dump_smem_cfg->lmac[i].txfifo_size[j] = + cpu_to_le32(mem_cfg->lmac[i].txfifo_size[j]); + dump_smem_cfg->lmac[i].rxfifo1_size = + cpu_to_le32(mem_cfg->lmac[i].rxfifo1_size); + } + dump_smem_cfg->rxfifo2_size = cpu_to_le32(mem_cfg->rxfifo2_size); + dump_smem_cfg->internal_txfifo_addr = + cpu_to_le32(mem_cfg->internal_txfifo_addr); + for (i = 0; i < TX_FIFO_INTERNAL_MAX_NUM; i++) { + dump_smem_cfg->internal_txfifo_size[i] = + cpu_to_le32(mem_cfg->internal_txfifo_size[i]); + } + + dump_data = iwl_fw_error_next_data(dump_data); + /* We only dump the FIFOs if the FW is in error state */ - if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) { - iwl_mvm_dump_fifos(mvm, &dump_data); + if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { + iwl_fw_dump_fifos(fwrt, &dump_data); if (radio_len) - iwl_mvm_read_radio_reg(mvm, &dump_data); + iwl_read_radio_regs(fwrt, &dump_data); } - if (mvm->fw_dump_desc) { + if (fwrt->dump.desc) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_ERROR_INFO); dump_data->len = cpu_to_le32(sizeof(*dump_trig) + - mvm->fw_dump_desc->len); + fwrt->dump.desc->len); dump_trig = (void *)dump_data->data; - memcpy(dump_trig, &mvm->fw_dump_desc->trig_desc, - sizeof(*dump_trig) + mvm->fw_dump_desc->len); + memcpy(dump_trig, &fwrt->dump.desc->trig_desc, + sizeof(*dump_trig) + fwrt->dump.desc->len); dump_data = iwl_fw_error_next_data(dump_data); } @@ -762,18 +794,18 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) if (monitor_dump_only) goto dump_trans_data; - if (!mvm->fw->n_dbg_mem_tlv) { + if (!fwrt->fw->n_dbg_mem_tlv) { dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM); dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); dump_mem->offset = cpu_to_le32(sram_ofs); - iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data, + iwl_trans_read_mem_bytes(fwrt->trans, sram_ofs, dump_mem->data, sram_len); dump_data = iwl_fw_error_next_data(dump_data); } - for (i = 0; i < mvm->fw->n_dbg_mem_tlv; i++) { + for (i = 0; i < fwrt->fw->n_dbg_mem_tlv; i++) { u32 len = le32_to_cpu(fw_dbg_mem[i].len); u32 ofs = le32_to_cpu(fw_dbg_mem[i].ofs); bool success; @@ -786,13 +818,13 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) switch (dump_mem->type & cpu_to_le32(FW_DBG_MEM_TYPE_MASK)) { case cpu_to_le32(FW_DBG_MEM_TYPE_REGULAR): - iwl_trans_read_mem_bytes(mvm->trans, ofs, + iwl_trans_read_mem_bytes(fwrt->trans, ofs, dump_mem->data, len); success = true; break; case cpu_to_le32(FW_DBG_MEM_TYPE_PRPH): - success = iwl_read_prph_block(mvm->trans, ofs, len, + success = iwl_read_prph_block(fwrt->trans, ofs, len, (void *)dump_mem->data); break; default: @@ -813,8 +845,9 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM); - dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset); - iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset, + dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->smem_offset); + iwl_trans_read_mem_bytes(fwrt->trans, + fwrt->trans->cfg->smem_offset, dump_mem->data, smem_len); dump_data = iwl_fw_error_next_data(dump_data); } @@ -824,28 +857,29 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem)); dump_mem = (void *)dump_data->data; dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM); - dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset); - iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset, + dump_mem->offset = cpu_to_le32(fwrt->trans->cfg->dccm2_offset); + iwl_trans_read_mem_bytes(fwrt->trans, + fwrt->trans->cfg->dccm2_offset, dump_mem->data, sram2_len); dump_data = iwl_fw_error_next_data(dump_data); } /* Dump fw's virtual image */ - if (!mvm->trans->cfg->gen2 && - mvm->fw->img[mvm->cur_ucode].paging_mem_size && - mvm->fw_paging_db[0].fw_paging_block) { - for (i = 1; i < mvm->num_of_paging_blk + 1; i++) { + if (!fwrt->trans->cfg->gen2 && + fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size && + fwrt->fw_paging_db[0].fw_paging_block) { + for (i = 1; i < fwrt->num_of_paging_blk + 1; i++) { struct iwl_fw_error_dump_paging *paging; struct page *pages = - mvm->fw_paging_db[i].fw_paging_block; - dma_addr_t addr = mvm->fw_paging_db[i].fw_paging_phys; + fwrt->fw_paging_db[i].fw_paging_block; + dma_addr_t addr = fwrt->fw_paging_db[i].fw_paging_phys; dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING); dump_data->len = cpu_to_le32(sizeof(*paging) + PAGING_BLOCK_SIZE); paging = (void *)dump_data->data; paging->index = cpu_to_le32(i); - dma_sync_single_for_cpu(mvm->trans->dev, addr, + dma_sync_single_for_cpu(fwrt->trans->dev, addr, PAGING_BLOCK_SIZE, DMA_BIDIRECTIONAL); memcpy(paging->data, page_address(pages), @@ -855,20 +889,20 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) } if (prph_len) { - iwl_dump_prph(mvm->trans, &dump_data, + iwl_dump_prph(fwrt->trans, &dump_data, iwl_prph_dump_addr_comm, ARRAY_SIZE(iwl_prph_dump_addr_comm)); - if (mvm->cfg->mq_rx_supported) - iwl_dump_prph(mvm->trans, &dump_data, + if (fwrt->trans->cfg->mq_rx_supported) + iwl_dump_prph(fwrt->trans, &dump_data, iwl_prph_dump_addr_9000, ARRAY_SIZE(iwl_prph_dump_addr_9000)); } dump_trans_data: - fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans, - mvm->fw_dump_trig); - fw_error_dump->op_mode_len = file_len; + fw_error_dump->trans_ptr = iwl_trans_dump_data(fwrt->trans, + fwrt->dump.trig); + fw_error_dump->fwrt_len = file_len; if (fw_error_dump->trans_ptr) file_len += fw_error_dump->trans_ptr->len; dump_file->file_len = cpu_to_le32(file_len); @@ -877,68 +911,72 @@ dump_trans_data: if (sg_dump_data) { sg_pcopy_from_buffer(sg_dump_data, sg_nents(sg_dump_data), - fw_error_dump->op_mode_ptr, - fw_error_dump->op_mode_len, 0); + fw_error_dump->fwrt_ptr, + fw_error_dump->fwrt_len, 0); if (fw_error_dump->trans_ptr) sg_pcopy_from_buffer(sg_dump_data, sg_nents(sg_dump_data), fw_error_dump->trans_ptr->data, fw_error_dump->trans_ptr->len, - fw_error_dump->op_mode_len); - dev_coredumpsg(mvm->trans->dev, sg_dump_data, file_len, + fw_error_dump->fwrt_len); + dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len, GFP_KERNEL); } - vfree(fw_error_dump->op_mode_ptr); + vfree(fw_error_dump->fwrt_ptr); vfree(fw_error_dump->trans_ptr); kfree(fw_error_dump); out: - iwl_mvm_free_fw_dump_desc(mvm); - mvm->fw_dump_trig = NULL; - clear_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status); + iwl_fw_free_dump_desc(fwrt); + fwrt->dump.trig = NULL; + clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status); } +IWL_EXPORT_SYMBOL(iwl_fw_error_dump); -const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert = { +const struct iwl_fw_dump_desc iwl_dump_desc_assert = { .trig_desc = { .type = cpu_to_le32(FW_DBG_TRIGGER_FW_ASSERT), }, }; +IWL_EXPORT_SYMBOL(iwl_dump_desc_assert); -int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, - const struct iwl_mvm_dump_desc *desc, - const struct iwl_fw_dbg_trigger_tlv *trigger) +int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, + const struct iwl_fw_dump_desc *desc, + const struct iwl_fw_dbg_trigger_tlv *trigger) { unsigned int delay = 0; if (trigger) delay = msecs_to_jiffies(le32_to_cpu(trigger->stop_delay)); - if (WARN(mvm->trans->state == IWL_TRANS_NO_FW, + if (WARN(fwrt->trans->state == IWL_TRANS_NO_FW, "Can't collect dbg data when FW isn't alive\n")) return -EIO; - if (test_and_set_bit(IWL_MVM_STATUS_DUMPING_FW_LOG, &mvm->status)) + if (test_and_set_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status)) return -EBUSY; - if (WARN_ON(mvm->fw_dump_desc)) - iwl_mvm_free_fw_dump_desc(mvm); + if (WARN_ON(fwrt->dump.desc)) + iwl_fw_free_dump_desc(fwrt); - IWL_WARN(mvm, "Collecting data: trigger %d fired.\n", + IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", le32_to_cpu(desc->trig_desc.type)); - mvm->fw_dump_desc = desc; - mvm->fw_dump_trig = trigger; + fwrt->dump.desc = desc; + fwrt->dump.trig = trigger; - schedule_delayed_work(&mvm->fw_dump_wk, delay); + schedule_delayed_work(&fwrt->dump.wk, delay); return 0; } +IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc); -int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, - const struct iwl_fw_dbg_trigger_tlv *trigger) +int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, + enum iwl_fw_dbg_trigger trig, + const char *str, size_t len, + const struct iwl_fw_dbg_trigger_tlv *trigger) { - struct iwl_mvm_dump_desc *desc; + struct iwl_fw_dump_desc *desc; desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC); if (!desc) @@ -948,12 +986,13 @@ int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); - return iwl_mvm_fw_dbg_collect_desc(mvm, desc, trigger); + return iwl_fw_dbg_collect_desc(fwrt, desc, trigger); } +IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); -int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, - struct iwl_fw_dbg_trigger_tlv *trigger, - const char *fmt, ...) +int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, + struct iwl_fw_dbg_trigger_tlv *trigger, + const char *fmt, ...) { u16 occurrences = le16_to_cpu(trigger->occurrences); int ret, len = 0; @@ -978,8 +1017,8 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, len = strlen(buf) + 1; } - ret = iwl_mvm_fw_dbg_collect(mvm, le32_to_cpu(trigger->id), buf, len, - trigger); + ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len, + trigger); if (ret) return ret; @@ -987,37 +1026,42 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, trigger->occurrences = cpu_to_le16(occurrences - 1); return 0; } +IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig); -int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id) +int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) { u8 *ptr; int ret; int i; - if (WARN_ONCE(conf_id >= ARRAY_SIZE(mvm->fw->dbg_conf_tlv), + if (WARN_ONCE(conf_id >= ARRAY_SIZE(fwrt->fw->dbg_conf_tlv), "Invalid configuration %d\n", conf_id)) return -EINVAL; /* EARLY START - firmware's configuration is hard coded */ - if ((!mvm->fw->dbg_conf_tlv[conf_id] || - !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) && + if ((!fwrt->fw->dbg_conf_tlv[conf_id] || + !fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) && conf_id == FW_DBG_START_FROM_ALIVE) return 0; - if (!mvm->fw->dbg_conf_tlv[conf_id]) + if (!fwrt->fw->dbg_conf_tlv[conf_id]) return -EINVAL; - if (mvm->fw_dbg_conf != FW_DBG_INVALID) - IWL_WARN(mvm, "FW already configured (%d) - re-configuring\n", - mvm->fw_dbg_conf); + if (fwrt->dump.conf != FW_DBG_INVALID) + IWL_WARN(fwrt, "FW already configured (%d) - re-configuring\n", + fwrt->dump.conf); /* Send all HCMDs for configuring the FW debug */ - ptr = (void *)&mvm->fw->dbg_conf_tlv[conf_id]->hcmd; - for (i = 0; i < mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { + ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd; + for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr; + struct iwl_host_cmd hcmd = { + .id = cmd->id, + .len = { le16_to_cpu(cmd->len), }, + .data = { cmd->data, }, + }; - ret = iwl_mvm_send_cmd_pdu(mvm, cmd->id, 0, - le16_to_cpu(cmd->len), cmd->data); + ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); if (ret) return ret; @@ -1025,7 +1069,59 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id) ptr += le16_to_cpu(cmd->len); } - mvm->fw_dbg_conf = conf_id; + fwrt->dump.conf = conf_id; return 0; } +IWL_EXPORT_SYMBOL(iwl_fw_start_dbg_conf); + +void iwl_fw_error_dump_wk(struct work_struct *work) +{ + struct iwl_fw_runtime *fwrt = + container_of(work, struct iwl_fw_runtime, dump.wk.work); + + if (fwrt->ops && fwrt->ops->dump_start && + fwrt->ops->dump_start(fwrt->ops_ctx)) + return; + + if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + /* stop recording */ + iwl_set_bits_prph(fwrt->trans, MON_BUFF_SAMPLE_CTL, 0x100); + + iwl_fw_error_dump(fwrt); + + /* start recording again if the firmware is not crashed */ + if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) && + fwrt->fw->dbg_dest_tlv) { + iwl_clear_bits_prph(fwrt->trans, + MON_BUFF_SAMPLE_CTL, 0x100); + iwl_clear_bits_prph(fwrt->trans, + MON_BUFF_SAMPLE_CTL, 0x1); + iwl_set_bits_prph(fwrt->trans, + MON_BUFF_SAMPLE_CTL, 0x1); + } + } else { + u32 in_sample = iwl_read_prph(fwrt->trans, DBGC_IN_SAMPLE); + u32 out_ctrl = iwl_read_prph(fwrt->trans, DBGC_OUT_CTRL); + + /* stop recording */ + iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, 0); + udelay(100); + iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, 0); + /* wait before we collect the data till the DBGC stop */ + udelay(500); + + iwl_fw_error_dump(fwrt); + + /* start recording again if the firmware is not crashed */ + if (!test_bit(STATUS_FW_ERROR, &fwrt->trans->status) && + fwrt->fw->dbg_dest_tlv) { + iwl_write_prph(fwrt->trans, DBGC_IN_SAMPLE, in_sample); + iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl); + } + } + + if (fwrt->ops && fwrt->ops->dump_end) + fwrt->ops->dump_end(fwrt->ops_ctx); +} + diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index 4a5287a0c617..0f810ea89d31 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -7,7 +7,7 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,24 +63,46 @@ * *****************************************************************************/ -#ifndef __mvm_fw_dbg_h__ -#define __mvm_fw_dbg_h__ -#include "fw/file.h" -#include "fw/error-dump.h" -#include "mvm.h" - -void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm); -void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm); -int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, - const struct iwl_mvm_dump_desc *desc, - const struct iwl_fw_dbg_trigger_tlv *trigger); -int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig, - const char *str, size_t len, - const struct iwl_fw_dbg_trigger_tlv *trigger); -int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, - struct iwl_fw_dbg_trigger_tlv *trigger, - const char *fmt, ...) __printf(3, 4); -int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id); +#ifndef __iwl_fw_dbg_h__ +#define __iwl_fw_dbg_h__ +#include <linux/workqueue.h> +#include <net/cfg80211.h> +#include "runtime.h" +#include "file.h" +#include "error-dump.h" + +/** + * struct iwl_fw_dump_desc - describes the dump + * @len: length of trig_desc->data + * @trig_desc: the description of the dump + */ +struct iwl_fw_dump_desc { + size_t len; + /* must be last */ + struct iwl_fw_error_dump_trigger_desc trig_desc; +}; + +extern const struct iwl_fw_dump_desc iwl_dump_desc_assert; + +static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt) +{ + if (fwrt->dump.desc != &iwl_dump_desc_assert) + kfree(fwrt->dump.desc); + fwrt->dump.desc = NULL; +} + +void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt); +int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, + const struct iwl_fw_dump_desc *desc, + const struct iwl_fw_dbg_trigger_tlv *trigger); +int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, + enum iwl_fw_dbg_trigger trig, + const char *str, size_t len, + const struct iwl_fw_dbg_trigger_tlv *trigger); +int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, + struct iwl_fw_dbg_trigger_tlv *trigger, + const char *fmt, ...) __printf(3, 4); +int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id); #define iwl_fw_dbg_trigger_enabled(fw, id) ({ \ void *__dbg_trigger = (fw)->dbg_trigger_tlv[(id)]; \ @@ -101,25 +123,25 @@ _iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id) static inline bool iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig, - struct ieee80211_vif *vif) + struct wireless_dev *wdev) { u32 trig_vif = le32_to_cpu(trig->vif_type); return trig_vif == IWL_FW_DBG_CONF_VIF_ANY || - ieee80211_vif_type_p2p(vif) == trig_vif; + wdev->iftype == trig_vif; } static inline bool -iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm, +iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trig) { return ((trig->mode & IWL_FW_DBG_TRIGGER_STOP) && - (mvm->fw_dbg_conf == FW_DBG_INVALID || - (BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids)))); + (fwrt->dump.conf == FW_DBG_INVALID || + (BIT(fwrt->dump.conf) & le32_to_cpu(trig->stop_conf_ids)))); } static inline bool -iwl_fw_dbg_no_trig_window(struct iwl_mvm *mvm, +iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trig) { unsigned long wind_jiff = @@ -127,49 +149,66 @@ iwl_fw_dbg_no_trig_window(struct iwl_mvm *mvm, u32 id = le32_to_cpu(trig->id); /* If this is the first event checked, jump to update start ts */ - if (mvm->fw_dbg_non_collect_ts_start[id] && - (time_after(mvm->fw_dbg_non_collect_ts_start[id] + wind_jiff, + if (fwrt->dump.non_collect_ts_start[id] && + (time_after(fwrt->dump.non_collect_ts_start[id] + wind_jiff, jiffies))) return true; - mvm->fw_dbg_non_collect_ts_start[id] = jiffies; + fwrt->dump.non_collect_ts_start[id] = jiffies; return false; } static inline bool -iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, +iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt, + struct wireless_dev *wdev, struct iwl_fw_dbg_trigger_tlv *trig) { - if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif)) + if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev)) return false; - if (iwl_fw_dbg_no_trig_window(mvm, trig)) { - IWL_WARN(mvm, "Trigger %d occurred while no-collect window.\n", + if (iwl_fw_dbg_no_trig_window(fwrt, trig)) { + IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n", trig->id); return false; } - return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig); + return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig); } static inline void -_iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, +_iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, + struct wireless_dev *wdev, struct iwl_fw_dbg_trigger_tlv *trigger) { if (!trigger) return; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger)) + if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trigger)) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL); + iwl_fw_dbg_collect_trig(fwrt, trigger, NULL); } -#define iwl_fw_dbg_trigger_simple_stop(mvm, vif, trig) \ - _iwl_fw_dbg_trigger_simple_stop((mvm), (vif), \ - iwl_fw_dbg_get_trigger((mvm)->fw,\ +#define iwl_fw_dbg_trigger_simple_stop(fwrt, wdev, trig) \ + _iwl_fw_dbg_trigger_simple_stop((fwrt), (wdev), \ + iwl_fw_dbg_get_trigger((fwrt)->fw,\ (trig))) -#endif /* __mvm_fw_dbg_h__ */ +static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt) +{ + fwrt->dump.conf = FW_DBG_INVALID; +} + +void iwl_fw_error_dump_wk(struct work_struct *work); + +static inline void iwl_fw_flush_dump(struct iwl_fw_runtime *fwrt) +{ + flush_delayed_work(&fwrt->dump.wk); +} + +static inline void iwl_fw_cancel_dump(struct iwl_fw_runtime *fwrt) +{ + cancel_delayed_work_sync(&fwrt->dump.wk); +} + +#endif /* __iwl_fw_dbg_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index cfebde68a391..ed7beca8817e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -7,6 +7,7 @@ * * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2014 Intel Corporation. All rights reserved. * Copyright(c) 2014 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,6 +94,9 @@ * @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and * for that reason is not in use in any other place in the Linux Wi-Fi * stack. + * @IWL_FW_ERROR_DUMP_MEM_CFG: the addresses and sizes of fifos in the smem, + * which we get from the fw after ALIVE. The content is structured as + * &struct iwl_fw_error_dump_smem_cfg. */ enum iwl_fw_error_dump_type { /* 0 is deprecated */ @@ -110,6 +115,7 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_RADIO_REG = 13, IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14, IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ + IWL_FW_ERROR_DUMP_MEM_CFG = 16, IWL_FW_ERROR_DUMP_MAX, }; @@ -208,6 +214,30 @@ struct iwl_fw_error_dump_fw_mon { u8 data[]; } __packed; +#define MAX_NUM_LMAC 2 +#define TX_FIFO_INTERNAL_MAX_NUM 6 +#define TX_FIFO_MAX_NUM 15 +/** + * struct iwl_fw_error_dump_smem_cfg - Dump SMEM configuration + * This must follow &struct iwl_fwrt_shared_mem_cfg. + * @num_lmacs: number of lmacs + * @num_txfifo_entries: number of tx fifos + * @lmac: sizes of lmacs txfifos and rxfifo1 + * @rxfifo2_size: size of rxfifo2 + * @internal_txfifo_addr: address of internal tx fifo + * @internal_txfifo_size: size of internal tx fifo + */ +struct iwl_fw_error_dump_smem_cfg { + __le32 num_lmacs; + __le32 num_txfifo_entries; + struct { + __le32 txfifo_size[TX_FIFO_MAX_NUM]; + __le32 rxfifo1_size; + } lmac[MAX_NUM_LMAC]; + __le32 rxfifo2_size; + __le32 internal_txfifo_addr; + __le32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; +} __packed; /** * struct iwl_fw_error_dump_prph - periphery registers data * @prph_start: address of the first register in this chunk diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index c73a6438ce8f..887f6d8fc8a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -246,6 +246,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used + * @IWL_UCODE_TLV_API_ATS_COEX_EXTERNAL: the coex notification is enlared to + * include information about ACL time sharing. * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -260,7 +262,9 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_STA_TYPE = (__force iwl_ucode_tlv_api_t)30, IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, /* API Set 1 */ + IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34, IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35, + IWL_UCODE_TLV_API_COEX_ATS_EXTERNAL = (__force iwl_ucode_tlv_api_t)37, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c new file mode 100644 index 000000000000..bfe5316bbb6a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -0,0 +1,75 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "iwl-drv.h" +#include "runtime.h" +#include "dbg.h" + +void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, + const struct iwl_fw *fw, + const struct iwl_fw_runtime_ops *ops, void *ops_ctx) +{ + memset(fwrt, 0, sizeof(*fwrt)); + fwrt->trans = trans; + fwrt->fw = fw; + fwrt->dev = trans->dev; + fwrt->dump.conf = FW_DBG_INVALID; + fwrt->ops = ops; + fwrt->ops_ctx = ops_ctx; + INIT_DELAYED_WORK(&fwrt->dump.wk, iwl_fw_error_dump_wk); +} +IWL_EXPORT_SYMBOL(iwl_fw_runtime_init); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c index 29bb92e3df59..1096c945a68b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -161,6 +162,15 @@ iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, } IWL_EXPORT_SYMBOL(iwl_init_notification_wait); +void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait, + struct iwl_notification_wait *wait_entry) +{ + spin_lock_bh(¬if_wait->notif_wait_lock); + list_del(&wait_entry->list); + spin_unlock_bh(¬if_wait->notif_wait_lock); +} +IWL_EXPORT_SYMBOL(iwl_remove_notification); + int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait, struct iwl_notification_wait *wait_entry, unsigned long timeout) @@ -171,9 +181,7 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait, wait_entry->triggered || wait_entry->aborted, timeout); - spin_lock_bh(¬if_wait->notif_wait_lock); - list_del(&wait_entry->list); - spin_unlock_bh(¬if_wait->notif_wait_lock); + iwl_remove_notification(notif_wait, wait_entry); if (wait_entry->aborted) return -EIO; @@ -184,12 +192,3 @@ int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait, return 0; } IWL_EXPORT_SYMBOL(iwl_wait_notification); - -void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait, - struct iwl_notification_wait *wait_entry) -{ - spin_lock_bh(¬if_wait->notif_wait_lock); - list_del(&wait_entry->list); - spin_unlock_bh(¬if_wait->notif_wait_lock); -} -IWL_EXPORT_SYMBOL(iwl_remove_notification); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/nvm.c b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c new file mode 100644 index 000000000000..bd2e1fb43f5a --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/nvm.c @@ -0,0 +1,162 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "iwl-drv.h" +#include "runtime.h" +#include "fw/api/nvm-reg.h" +#include "fw/api/commands.h" +#include "iwl-nvm-parse.h" + +struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt) +{ + struct iwl_nvm_get_info cmd = {}; + struct iwl_nvm_get_info_rsp *rsp; + struct iwl_trans *trans = fwrt->trans; + struct iwl_nvm_data *nvm; + struct iwl_host_cmd hcmd = { + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &cmd, }, + .len = { sizeof(cmd) }, + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) + }; + int ret; + bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && + fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_LAR_SUPPORT); + + ret = iwl_trans_send_cmd(trans, &hcmd); + if (ret) + return ERR_PTR(ret); + + if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp), + "Invalid payload len in NVM response from FW %d", + iwl_rx_packet_payload_len(hcmd.resp_pkt))) { + ret = -EINVAL; + goto out; + } + + rsp = (void *)hcmd.resp_pkt->data; + if (le32_to_cpu(rsp->general.flags) & NVM_GENERAL_FLAGS_EMPTY_OTP) + IWL_INFO(fwrt, "OTP is empty\n"); + + nvm = kzalloc(sizeof(*nvm) + + sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, + GFP_KERNEL); + if (!nvm) { + ret = -ENOMEM; + goto out; + } + + iwl_set_hw_address_from_csr(trans, nvm); + /* TODO: if platform NVM has MAC address - override it here */ + + if (!is_valid_ether_addr(nvm->hw_addr)) { + IWL_ERR(fwrt, "no valid mac address was found\n"); + ret = -EINVAL; + goto err_free; + } + + IWL_INFO(trans, "base HW address: %pM\n", nvm->hw_addr); + + /* Initialize general data */ + nvm->nvm_version = le16_to_cpu(rsp->general.nvm_version); + + /* Initialize MAC sku data */ + nvm->sku_cap_11ac_enable = + le32_to_cpu(rsp->mac_sku.enable_11ac); + nvm->sku_cap_11n_enable = + le32_to_cpu(rsp->mac_sku.enable_11n); + nvm->sku_cap_band_24GHz_enable = + le32_to_cpu(rsp->mac_sku.enable_24g); + nvm->sku_cap_band_52GHz_enable = + le32_to_cpu(rsp->mac_sku.enable_5g); + nvm->sku_cap_mimo_disabled = + le32_to_cpu(rsp->mac_sku.mimo_disable); + + /* Initialize PHY sku data */ + nvm->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); + nvm->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); + + /* Initialize regulatory data */ + nvm->lar_enabled = + le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported; + + iwl_init_sbands(trans->dev, trans->cfg, nvm, + rsp->regulatory.channel_profile, + nvm->valid_tx_ant & fwrt->fw->valid_tx_ant, + nvm->valid_rx_ant & fwrt->fw->valid_rx_ant, + nvm->lar_enabled, false); + + iwl_free_resp(&hcmd); + return nvm; + +err_free: + kfree(nvm); +out: + iwl_free_resp(&hcmd); + return ERR_PTR(ret); +} +IWL_EXPORT_SYMBOL(iwl_fw_get_nvm); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/paging.c b/drivers/net/wireless/intel/iwlwifi/fw/paging.c new file mode 100644 index 000000000000..1610722b8099 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/paging.c @@ -0,0 +1,414 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "iwl-drv.h" +#include "runtime.h" +#include "fw/api/commands.h" + +void iwl_free_fw_paging(struct iwl_fw_runtime *fwrt) +{ + int i; + + if (!fwrt->fw_paging_db[0].fw_paging_block) + return; + + for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { + struct iwl_fw_paging *paging = &fwrt->fw_paging_db[i]; + + if (!paging->fw_paging_block) { + IWL_DEBUG_FW(fwrt, + "Paging: block %d already freed, continue to next page\n", + i); + + continue; + } + dma_unmap_page(fwrt->trans->dev, paging->fw_paging_phys, + paging->fw_paging_size, DMA_BIDIRECTIONAL); + + __free_pages(paging->fw_paging_block, + get_order(paging->fw_paging_size)); + paging->fw_paging_block = NULL; + } + kfree(fwrt->trans->paging_download_buf); + fwrt->trans->paging_download_buf = NULL; + fwrt->trans->paging_db = NULL; + + memset(fwrt->fw_paging_db, 0, sizeof(fwrt->fw_paging_db)); +} +IWL_EXPORT_SYMBOL(iwl_free_fw_paging); + +static int iwl_alloc_fw_paging_mem(struct iwl_fw_runtime *fwrt, + const struct fw_img *image) +{ + struct page *block; + dma_addr_t phys = 0; + int blk_idx, order, num_of_pages, size, dma_enabled; + + if (fwrt->fw_paging_db[0].fw_paging_block) + return 0; + + dma_enabled = is_device_dma_capable(fwrt->trans->dev); + + /* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */ + BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE); + + num_of_pages = image->paging_mem_size / FW_PAGING_SIZE; + fwrt->num_of_paging_blk = + DIV_ROUND_UP(num_of_pages, NUM_OF_PAGE_PER_GROUP); + fwrt->num_of_pages_in_last_blk = + num_of_pages - + NUM_OF_PAGE_PER_GROUP * (fwrt->num_of_paging_blk - 1); + + IWL_DEBUG_FW(fwrt, + "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n", + fwrt->num_of_paging_blk, + fwrt->num_of_pages_in_last_blk); + + /* + * Allocate CSS and paging blocks in dram. + */ + for (blk_idx = 0; blk_idx < fwrt->num_of_paging_blk + 1; blk_idx++) { + /* For CSS allocate 4KB, for others PAGING_BLOCK_SIZE (32K) */ + size = blk_idx ? PAGING_BLOCK_SIZE : FW_PAGING_SIZE; + order = get_order(size); + block = alloc_pages(GFP_KERNEL, order); + if (!block) { + /* free all the previous pages since we failed */ + iwl_free_fw_paging(fwrt); + return -ENOMEM; + } + + fwrt->fw_paging_db[blk_idx].fw_paging_block = block; + fwrt->fw_paging_db[blk_idx].fw_paging_size = size; + + if (dma_enabled) { + phys = dma_map_page(fwrt->trans->dev, block, 0, + PAGE_SIZE << order, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(fwrt->trans->dev, phys)) { + /* + * free the previous pages and the current one + * since we failed to map_page. + */ + iwl_free_fw_paging(fwrt); + return -ENOMEM; + } + fwrt->fw_paging_db[blk_idx].fw_paging_phys = phys; + } else { + fwrt->fw_paging_db[blk_idx].fw_paging_phys = + PAGING_ADDR_SIG | + blk_idx << BLOCK_2_EXP_SIZE; + } + + if (!blk_idx) + IWL_DEBUG_FW(fwrt, + "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n", + order); + else + IWL_DEBUG_FW(fwrt, + "Paging: allocated 32K bytes (order %d) for firmware paging.\n", + order); + } + + return 0; +} + +static int iwl_fill_paging_mem(struct iwl_fw_runtime *fwrt, + const struct fw_img *image) +{ + int sec_idx, idx; + u32 offset = 0; + + /* + * find where is the paging image start point: + * if CPU2 exist and it's in paging format, then the image looks like: + * CPU1 sections (2 or more) + * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 + * CPU2 sections (not paged) + * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 + * non paged to CPU2 paging sec + * CPU2 paging CSS + * CPU2 paging image (including instruction and data) + */ + for (sec_idx = 0; sec_idx < image->num_sec; sec_idx++) { + if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) { + sec_idx++; + break; + } + } + + /* + * If paging is enabled there should be at least 2 more sections left + * (one for CSS and one for Paging data) + */ + if (sec_idx >= image->num_sec - 1) { + IWL_ERR(fwrt, "Paging: Missing CSS and/or paging sections\n"); + iwl_free_fw_paging(fwrt); + return -EINVAL; + } + + /* copy the CSS block to the dram */ + IWL_DEBUG_FW(fwrt, "Paging: load paging CSS to FW, sec = %d\n", + sec_idx); + + memcpy(page_address(fwrt->fw_paging_db[0].fw_paging_block), + image->sec[sec_idx].data, + fwrt->fw_paging_db[0].fw_paging_size); + dma_sync_single_for_device(fwrt->trans->dev, + fwrt->fw_paging_db[0].fw_paging_phys, + fwrt->fw_paging_db[0].fw_paging_size, + DMA_BIDIRECTIONAL); + + IWL_DEBUG_FW(fwrt, + "Paging: copied %d CSS bytes to first block\n", + fwrt->fw_paging_db[0].fw_paging_size); + + sec_idx++; + + /* + * copy the paging blocks to the dram + * loop index start from 1 since that CSS block already copied to dram + * and CSS index is 0. + * loop stop at num_of_paging_blk since that last block is not full. + */ + for (idx = 1; idx < fwrt->num_of_paging_blk; idx++) { + struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; + + memcpy(page_address(block->fw_paging_block), + image->sec[sec_idx].data + offset, + block->fw_paging_size); + dma_sync_single_for_device(fwrt->trans->dev, + block->fw_paging_phys, + block->fw_paging_size, + DMA_BIDIRECTIONAL); + + IWL_DEBUG_FW(fwrt, + "Paging: copied %d paging bytes to block %d\n", + fwrt->fw_paging_db[idx].fw_paging_size, + idx); + + offset += fwrt->fw_paging_db[idx].fw_paging_size; + } + + /* copy the last paging block */ + if (fwrt->num_of_pages_in_last_blk > 0) { + struct iwl_fw_paging *block = &fwrt->fw_paging_db[idx]; + + memcpy(page_address(block->fw_paging_block), + image->sec[sec_idx].data + offset, + FW_PAGING_SIZE * fwrt->num_of_pages_in_last_blk); + dma_sync_single_for_device(fwrt->trans->dev, + block->fw_paging_phys, + block->fw_paging_size, + DMA_BIDIRECTIONAL); + + IWL_DEBUG_FW(fwrt, + "Paging: copied %d pages in the last block %d\n", + fwrt->num_of_pages_in_last_blk, idx); + } + + return 0; +} + +static int iwl_save_fw_paging(struct iwl_fw_runtime *fwrt, + const struct fw_img *fw) +{ + int ret; + + ret = iwl_alloc_fw_paging_mem(fwrt, fw); + if (ret) + return ret; + + return iwl_fill_paging_mem(fwrt, fw); +} + +/* send paging cmd to FW in case CPU2 has paging image */ +static int iwl_send_paging_cmd(struct iwl_fw_runtime *fwrt, + const struct fw_img *fw) +{ + struct iwl_fw_paging_cmd paging_cmd = { + .flags = cpu_to_le32(PAGING_CMD_IS_SECURED | + PAGING_CMD_IS_ENABLED | + (fwrt->num_of_pages_in_last_blk << + PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), + .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), + .block_num = cpu_to_le32(fwrt->num_of_paging_blk), + }; + struct iwl_host_cmd hcmd = { + .id = iwl_cmd_id(FW_PAGING_BLOCK_CMD, IWL_ALWAYS_LONG_GROUP, 0), + .len = { sizeof(paging_cmd), }, + .data = { &paging_cmd, }, + }; + int blk_idx; + + /* loop for for all paging blocks + CSS block */ + for (blk_idx = 0; blk_idx < fwrt->num_of_paging_blk + 1; blk_idx++) { + dma_addr_t addr = fwrt->fw_paging_db[blk_idx].fw_paging_phys; + __le32 phy_addr; + + addr = addr >> PAGE_2_EXP_SIZE; + phy_addr = cpu_to_le32(addr); + paging_cmd.device_phy_addr[blk_idx] = phy_addr; + } + + return iwl_trans_send_cmd(fwrt->trans, &hcmd); +} + +/* + * Send paging item cmd to FW in case CPU2 has paging image + */ +static int iwl_trans_get_paging_item(struct iwl_fw_runtime *fwrt) +{ + int ret; + struct iwl_fw_get_item_cmd fw_get_item_cmd = { + .item_id = cpu_to_le32(IWL_FW_ITEM_ID_PAGING), + }; + struct iwl_fw_get_item_resp *item_resp; + struct iwl_host_cmd cmd = { + .id = iwl_cmd_id(FW_GET_ITEM_CMD, IWL_ALWAYS_LONG_GROUP, 0), + .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, + .data = { &fw_get_item_cmd, }, + .len = { sizeof(fw_get_item_cmd), }, + }; + + ret = iwl_trans_send_cmd(fwrt->trans, &cmd); + if (ret) { + IWL_ERR(fwrt, + "Paging: Failed to send FW_GET_ITEM_CMD cmd (err = %d)\n", + ret); + return ret; + } + + item_resp = (void *)((struct iwl_rx_packet *)cmd.resp_pkt)->data; + if (item_resp->item_id != cpu_to_le32(IWL_FW_ITEM_ID_PAGING)) { + IWL_ERR(fwrt, + "Paging: got wrong item in FW_GET_ITEM_CMD resp (item_id = %u)\n", + le32_to_cpu(item_resp->item_id)); + ret = -EIO; + goto exit; + } + + /* Add an extra page for headers */ + fwrt->trans->paging_download_buf = kzalloc(PAGING_BLOCK_SIZE + + FW_PAGING_SIZE, + GFP_KERNEL); + if (!fwrt->trans->paging_download_buf) { + ret = -ENOMEM; + goto exit; + } + fwrt->trans->paging_req_addr = le32_to_cpu(item_resp->item_val); + fwrt->trans->paging_db = fwrt->fw_paging_db; + IWL_DEBUG_FW(fwrt, + "Paging: got paging request address (paging_req_addr 0x%08x)\n", + fwrt->trans->paging_req_addr); + +exit: + iwl_free_resp(&cmd); + + return ret; +} + +int iwl_init_paging(struct iwl_fw_runtime *fwrt, enum iwl_ucode_type type) +{ + const struct fw_img *fw = &fwrt->fw->img[type]; + int ret; + + if (fwrt->trans->cfg->gen2) + return 0; + + /* + * Configure and operate fw paging mechanism. + * The driver configures the paging flow only once. + * The CPU2 paging image is included in the IWL_UCODE_INIT image. + */ + if (!fw->paging_mem_size) + return 0; + + /* + * When dma is not enabled, the driver needs to copy / write + * the downloaded / uploaded page to / from the smem. + * This gets the location of the place were the pages are + * stored. + */ + if (!is_device_dma_capable(fwrt->trans->dev)) { + ret = iwl_trans_get_paging_item(fwrt); + if (ret) { + IWL_ERR(fwrt, "failed to get FW paging item\n"); + return ret; + } + } + + ret = iwl_save_fw_paging(fwrt, fw); + if (ret) { + IWL_ERR(fwrt, "failed to save the FW paging image\n"); + return ret; + } + + ret = iwl_send_paging_cmd(fwrt, fw); + if (ret) { + IWL_ERR(fwrt, "failed to send the paging cmd\n"); + iwl_free_fw_paging(fwrt); + return ret; + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_init_paging); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h new file mode 100644 index 000000000000..50cfb6d795a5 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -0,0 +1,158 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_fw_runtime_h__ +#define __iwl_fw_runtime_h__ + +#include "iwl-config.h" +#include "iwl-trans.h" +#include "img.h" +#include "fw/api/debug.h" +#include "fw/api/paging.h" +#include "iwl-eeprom-parse.h" + +struct iwl_fw_runtime_ops { + int (*dump_start)(void *ctx); + void (*dump_end)(void *ctx); +}; + +#define MAX_NUM_LMAC 2 +struct iwl_fwrt_shared_mem_cfg { + int num_lmacs; + int num_txfifo_entries; + struct { + u32 txfifo_size[TX_FIFO_MAX_NUM]; + u32 rxfifo1_size; + } lmac[MAX_NUM_LMAC]; + u32 rxfifo2_size; + u32 internal_txfifo_addr; + u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; +}; + +enum iwl_fw_runtime_status { + IWL_FWRT_STATUS_DUMPING = 0, +}; + +/** + * struct iwl_fw_runtime - runtime data for firmware + * @fw: firmware image + * @cfg: NIC configuration + * @dev: device pointer + * @ops: user ops + * @ops_ctx: user ops context + * @status: status flags + * @fw_paging_db: paging database + * @num_of_paging_blk: number of paging blocks + * @num_of_pages_in_last_blk: number of pages in the last block + * @smem_cfg: saved firmware SMEM configuration + * @cur_fw_img: current firmware image, must be maintained by + * the driver by calling &iwl_fw_set_current_image() + * @dump: debug dump data + */ +struct iwl_fw_runtime { + struct iwl_trans *trans; + const struct iwl_fw *fw; + struct device *dev; + + const struct iwl_fw_runtime_ops *ops; + void *ops_ctx; + + unsigned long status; + + /* Paging */ + struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS]; + u16 num_of_paging_blk; + u16 num_of_pages_in_last_blk; + + enum iwl_ucode_type cur_fw_img; + + /* memory configuration */ + struct iwl_fwrt_shared_mem_cfg smem_cfg; + + /* debug */ + struct { + const struct iwl_fw_dump_desc *desc; + const struct iwl_fw_dbg_trigger_tlv *trig; + struct delayed_work wk; + + u8 conf; + + /* ts of the beginning of a non-collect fw dbg data period */ + unsigned long non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1]; + } dump; +}; + +void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, + const struct iwl_fw *fw, + const struct iwl_fw_runtime_ops *ops, void *ops_ctx); + +static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt, + enum iwl_ucode_type cur_fw_img) +{ + fwrt->cur_fw_img = cur_fw_img; +} + +int iwl_init_paging(struct iwl_fw_runtime *fwrt, enum iwl_ucode_type type); +void iwl_free_fw_paging(struct iwl_fw_runtime *fwrt); + +void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt); + +void iwl_fwrt_handle_notification(struct iwl_fw_runtime *fwrt, + struct iwl_rx_cmd_buffer *rxb); +struct iwl_nvm_data *iwl_fw_get_nvm(struct iwl_fw_runtime *fwrt); + +#endif /* __iwl_fw_runtime_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c new file mode 100644 index 000000000000..76675736ba4f --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c @@ -0,0 +1,155 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The full GNU General Public License is included in this distribution + * in the file called COPYING. + * + * Contact Information: + * Intel Linux Wireless <linuxwifi@intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include "iwl-drv.h" +#include "runtime.h" +#include "fw/api/commands.h" + +static void iwl_parse_shared_mem_a000(struct iwl_fw_runtime *fwrt, + struct iwl_rx_packet *pkt) +{ + struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data; + int i, lmac; + int lmac_num = le32_to_cpu(mem_cfg->lmac_num); + + if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) + return; + + fwrt->smem_cfg.num_lmacs = lmac_num; + fwrt->smem_cfg.num_txfifo_entries = + ARRAY_SIZE(mem_cfg->lmac_smem[0].txfifo_size); + fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); + + for (lmac = 0; lmac < lmac_num; lmac++) { + struct iwl_shared_mem_lmac_cfg *lmac_cfg = + &mem_cfg->lmac_smem[lmac]; + + for (i = 0; i < ARRAY_SIZE(lmac_cfg->txfifo_size); i++) + fwrt->smem_cfg.lmac[lmac].txfifo_size[i] = + le32_to_cpu(lmac_cfg->txfifo_size[i]); + fwrt->smem_cfg.lmac[lmac].rxfifo1_size = + le32_to_cpu(lmac_cfg->rxfifo1_size); + } +} + +static void iwl_parse_shared_mem(struct iwl_fw_runtime *fwrt, + struct iwl_rx_packet *pkt) +{ + struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data; + int i; + + fwrt->smem_cfg.num_lmacs = 1; + + fwrt->smem_cfg.num_txfifo_entries = ARRAY_SIZE(mem_cfg->txfifo_size); + for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) + fwrt->smem_cfg.lmac[0].txfifo_size[i] = + le32_to_cpu(mem_cfg->txfifo_size[i]); + + fwrt->smem_cfg.lmac[0].rxfifo1_size = + le32_to_cpu(mem_cfg->rxfifo_size[0]); + fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo_size[1]); + + /* new API has more data, from rxfifo_addr field and on */ + if (fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { + BUILD_BUG_ON(sizeof(fwrt->smem_cfg.internal_txfifo_size) != + sizeof(mem_cfg->internal_txfifo_size)); + + fwrt->smem_cfg.internal_txfifo_addr = + le32_to_cpu(mem_cfg->internal_txfifo_addr); + + for (i = 0; + i < ARRAY_SIZE(fwrt->smem_cfg.internal_txfifo_size); + i++) + fwrt->smem_cfg.internal_txfifo_size[i] = + le32_to_cpu(mem_cfg->internal_txfifo_size[i]); + } +} + +void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt) +{ + struct iwl_host_cmd cmd = { + .flags = CMD_WANT_SKB, + .data = { NULL, }, + .len = { 0, }, + }; + struct iwl_rx_packet *pkt; + + if (fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) + cmd.id = iwl_cmd_id(SHARED_MEM_CFG_CMD, SYSTEM_GROUP, 0); + else + cmd.id = SHARED_MEM_CFG; + + if (WARN_ON(iwl_trans_send_cmd(fwrt->trans, &cmd))) + return; + + pkt = cmd.resp_pkt; + if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) + iwl_parse_shared_mem_a000(fwrt, pkt); + else + iwl_parse_shared_mem(fwrt, pkt); + + IWL_DEBUG_INFO(fwrt, "SHARED MEM CFG: got memory offsets/sizes\n"); + + iwl_free_resp(&cmd); +} +IWL_EXPORT_SYMBOL(iwl_get_shared_mem_conf); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index d19c74827fbb..3e057b539d5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -463,6 +463,9 @@ extern const struct iwl_cfg iwla000_2ac_cfg_hr; extern const struct iwl_cfg iwla000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwla000_2ac_cfg_jf; extern const struct iwl_cfg iwla000_2ax_cfg_hr; +extern const struct iwl_cfg iwla000_2ax_cfg_qnj_hr_f0; +extern const struct iwl_cfg iwla000_2ax_cfg_qnj_jf_b0; +extern const struct iwl_cfg iwla000_2ax_cfg_qnj_hr_a0; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index c6c1876c1ad4..b03e0f975b5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -169,7 +169,7 @@ /* * CSR Hardware Revision Workaround Register. Indicates hardware rev; - * "step" determines CCK backoff for txpower calculation. Used for 4965 only. + * "step" determines CCK backoff for txpower calculation. * See also CSR_HW_REV register. * Bit fields: * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step @@ -354,11 +354,16 @@ enum { #define CSR_HW_REV_TYPE_135 (0x0000120) #define CSR_HW_REV_TYPE_7265D (0x0000210) #define CSR_HW_REV_TYPE_NONE (0x00001F0) +#define CSR_HW_REV_TYPE_QNJ (0x0000360) +#define CSR_HW_REV_TYPE_HR_CDB (0x0000340) /* RF_ID value */ -#define CSR_HW_RF_ID_TYPE_JF (0x00105000) +#define CSR_HW_RF_ID_TYPE_JF (0x00105100) #define CSR_HW_RF_ID_TYPE_HR (0x0010A000) -#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109000) +#define CSR_HW_RF_ID_TYPE_HRCDB (0x00109F00) + +/* HW_RF CHIP ID */ +#define CSR_HW_RF_ID_TYPE_CHIP_ID(_val) (((_val) >> 12) & 0xFFF) /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 4e0f86fe0a6f..99676d6c4713 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -479,8 +479,8 @@ static int iwl_set_default_calib(struct iwl_drv *drv, const u8 *data) return 0; } -static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data, - struct iwl_ucode_capabilities *capa) +static void iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data, + struct iwl_ucode_capabilities *capa) { const struct iwl_ucode_api *ucode_api = (void *)data; u32 api_index = le32_to_cpu(ucode_api->api_index); @@ -488,23 +488,20 @@ static int iwl_set_ucode_api_flags(struct iwl_drv *drv, const u8 *data, int i; if (api_index >= DIV_ROUND_UP(NUM_IWL_UCODE_TLV_API, 32)) { - IWL_ERR(drv, - "api flags index %d larger than supported by driver\n", - api_index); - /* don't return an error so we can load FW that has more bits */ - return 0; + IWL_WARN(drv, + "api flags index %d larger than supported by driver\n", + api_index); + return; } for (i = 0; i < 32; i++) { if (api_flags & BIT(i)) __set_bit(i + 32 * api_index, capa->_api); } - - return 0; } -static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data, - struct iwl_ucode_capabilities *capa) +static void iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data, + struct iwl_ucode_capabilities *capa) { const struct iwl_ucode_capa *ucode_capa = (void *)data; u32 api_index = le32_to_cpu(ucode_capa->api_index); @@ -512,19 +509,16 @@ static int iwl_set_ucode_capabilities(struct iwl_drv *drv, const u8 *data, int i; if (api_index >= DIV_ROUND_UP(NUM_IWL_UCODE_TLV_CAPA, 32)) { - IWL_ERR(drv, - "capa flags index %d larger than supported by driver\n", - api_index); - /* don't return an error so we can load FW that has more bits */ - return 0; + IWL_WARN(drv, + "capa flags index %d larger than supported by driver\n", + api_index); + return; } for (i = 0; i < 32; i++) { if (api_flags & BIT(i)) __set_bit(i + 32 * api_index, capa->_capa); } - - return 0; } static int iwl_parse_v1_v2_firmware(struct iwl_drv *drv, @@ -766,14 +760,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, case IWL_UCODE_TLV_API_CHANGES_SET: if (tlv_len != sizeof(struct iwl_ucode_api)) goto invalid_tlv_len; - if (iwl_set_ucode_api_flags(drv, tlv_data, capa)) - goto tlv_error; + iwl_set_ucode_api_flags(drv, tlv_data, capa); break; case IWL_UCODE_TLV_ENABLED_CAPABILITIES: if (tlv_len != sizeof(struct iwl_ucode_capa)) goto invalid_tlv_len; - if (iwl_set_ucode_capabilities(drv, tlv_data, capa)) - goto tlv_error; + iwl_set_ucode_capabilities(drv, tlv_data, capa); break; case IWL_UCODE_TLV_INIT_EVTLOG_PTR: if (tlv_len != sizeof(u32)) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index c527b8c10370..efb1998dcabd 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -241,20 +241,12 @@ IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); void iwl_force_nmi(struct iwl_trans *trans) { - if (trans->cfg->device_family < IWL_DEVICE_FAMILY_8000) { + if (trans->cfg->device_family < IWL_DEVICE_FAMILY_9000) iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL_DRV); - iwl_write_prph(trans, DEVICE_SET_NMI_REG, - DEVICE_SET_NMI_VAL_HW); - } else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) { + else iwl_write_prph(trans, UREG_NIC_SET_NMI_DRIVER, - DEVICE_SET_NMI_8000_VAL); - } else { - iwl_write_prph(trans, DEVICE_SET_NMI_8000_REG, - DEVICE_SET_NMI_8000_VAL); - iwl_write_prph(trans, DEVICE_SET_NMI_REG, - DEVICE_SET_NMI_VAL_DRV); - } + UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER_MSK); } IWL_EXPORT_SYMBOL(iwl_force_nmi); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 3ee6767392b6..3014beef4873 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -79,6 +79,7 @@ /* NVM offsets (in words) definitions */ enum wkp_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ + SUBSYSTEM_ID = 0x0A, HW_ADDR = 0x15, /* NVM SW-Section offset (in words) definitions */ @@ -183,22 +184,26 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS * on same channel on 2.4 or same UNII band on 5.2 - * @NVM_CHANNEL_WIDE: 20 MHz channel okay (?) - * @NVM_CHANNEL_40MHZ: 40 MHz channel okay (?) - * @NVM_CHANNEL_80MHZ: 80 MHz channel okay (?) - * @NVM_CHANNEL_160MHZ: 160 MHz channel okay (?) + * @NVM_CHANNEL_UNIFORM: uniform spreading required + * @NVM_CHANNEL_20MHZ: 20 MHz channel okay + * @NVM_CHANNEL_40MHZ: 40 MHz channel okay + * @NVM_CHANNEL_80MHZ: 80 MHz channel okay + * @NVM_CHANNEL_160MHZ: 160 MHz channel okay + * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) */ enum iwl_nvm_channel_flags { - NVM_CHANNEL_VALID = BIT(0), - NVM_CHANNEL_IBSS = BIT(1), - NVM_CHANNEL_ACTIVE = BIT(3), - NVM_CHANNEL_RADAR = BIT(4), - NVM_CHANNEL_INDOOR_ONLY = BIT(5), - NVM_CHANNEL_GO_CONCURRENT = BIT(6), - NVM_CHANNEL_WIDE = BIT(8), - NVM_CHANNEL_40MHZ = BIT(9), - NVM_CHANNEL_80MHZ = BIT(10), - NVM_CHANNEL_160MHZ = BIT(11), + NVM_CHANNEL_VALID = BIT(0), + NVM_CHANNEL_IBSS = BIT(1), + NVM_CHANNEL_ACTIVE = BIT(3), + NVM_CHANNEL_RADAR = BIT(4), + NVM_CHANNEL_INDOOR_ONLY = BIT(5), + NVM_CHANNEL_GO_CONCURRENT = BIT(6), + NVM_CHANNEL_UNIFORM = BIT(7), + NVM_CHANNEL_20MHZ = BIT(8), + NVM_CHANNEL_40MHZ = BIT(9), + NVM_CHANNEL_80MHZ = BIT(10), + NVM_CHANNEL_160MHZ = BIT(11), + NVM_CHANNEL_DC_HIGH = BIT(12), }; #define CHECK_AND_PRINT_I(x) \ @@ -254,13 +259,12 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 * const nvm_ch_flags, - bool lar_supported) + bool lar_supported, bool no_wide_in_5ghz) { int ch_idx; int n_channels = 0; struct ieee80211_channel *channel; u16 ch_flags; - bool is_5ghz; int num_of_ch, num_2ghz_channels; const u8 *nvm_chan; @@ -275,12 +279,20 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { + bool is_5ghz = (ch_idx >= num_2ghz_channels); + ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx); - if (ch_idx >= num_2ghz_channels && - !data->sku_cap_band_52GHz_enable) + if (is_5ghz && !data->sku_cap_band_52GHz_enable) continue; + /* workaround to disable wide channels in 5GHz */ + if (no_wide_in_5ghz && is_5ghz) { + ch_flags &= ~(NVM_CHANNEL_40MHZ | + NVM_CHANNEL_80MHZ | + NVM_CHANNEL_160MHZ); + } + if (ch_flags & NVM_CHANNEL_160MHZ) data->vht160_supported = true; @@ -303,8 +315,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, n_channels++; channel->hw_value = nvm_chan[ch_idx]; - channel->band = (ch_idx < num_2ghz_channels) ? - NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; + channel->band = is_5ghz ? + NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; channel->center_freq = ieee80211_channel_to_frequency( channel->hw_value, channel->band); @@ -316,7 +328,6 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, * is not used in mvm, and is used for backwards compatibility */ channel->max_power = IWL_DEFAULT_MAX_TX_POWER; - is_5ghz = channel->band == NL80211_BAND_5GHZ; /* don't put limitations in case we're using LAR */ if (!lar_supported) @@ -327,7 +338,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, channel->flags = 0; IWL_DEBUG_EEPROM(dev, - "Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n", + "Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n", channel->hw_value, is_5ghz ? "5.2" : "2.4", ch_flags, @@ -337,10 +348,12 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, CHECK_AND_PRINT_I(RADAR), CHECK_AND_PRINT_I(INDOOR_ONLY), CHECK_AND_PRINT_I(GO_CONCURRENT), - CHECK_AND_PRINT_I(WIDE), + CHECK_AND_PRINT_I(UNIFORM), + CHECK_AND_PRINT_I(20MHZ), CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), + CHECK_AND_PRINT_I(DC_HIGH), channel->max_power, ((ch_flags & NVM_CHANNEL_IBSS) && !(ch_flags & NVM_CHANNEL_RADAR)) @@ -432,14 +445,15 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg, void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *nvm_ch_flags, - u8 tx_chains, u8 rx_chains, bool lar_supported) + u8 tx_chains, u8 rx_chains, bool lar_supported, + bool no_wide_in_5ghz) { int n_channels; int n_used = 0; struct ieee80211_supported_band *sband; n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags, - lar_supported); + lar_supported, no_wide_in_5ghz); sband = &data->bands[NL80211_BAND_2GHZ]; sband->band = NL80211_BAND_2GHZ; sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; @@ -568,7 +582,7 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *mac_override, - const __le16 *nvm_hw) + const __be16 *nvm_hw) { const u8 *hw_addr; @@ -615,7 +629,7 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, static int iwl_set_hw_address(struct iwl_trans *trans, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, const __le16 *nvm_hw, + struct iwl_nvm_data *data, const __be16 *nvm_hw, const __le16 *mac_override) { if (cfg->mac_addr_from_csr) { @@ -645,9 +659,41 @@ static int iwl_set_hw_address(struct iwl_trans *trans, return 0; } +static bool +iwl_nvm_no_wide_in_5ghz(struct device *dev, const struct iwl_cfg *cfg, + const __be16 *nvm_hw) +{ + /* + * Workaround a bug in Indonesia SKUs where the regulatory in + * some 7000-family OTPs erroneously allow wide channels in + * 5GHz. To check for Indonesia, we take the SKU value from + * bits 1-4 in the subsystem ID and check if it is either 5 or + * 9. In those cases, we need to force-disable wide channels + * in 5GHz otherwise the FW will throw a sysassert when we try + * to use them. + */ + if (cfg->device_family == IWL_DEVICE_FAMILY_7000) { + /* + * Unlike the other sections in the NVM, the hw + * section uses big-endian. + */ + u16 subsystem_id = be16_to_cpup(nvm_hw + SUBSYSTEM_ID); + u8 sku = (subsystem_id & 0x1e) >> 1; + + if (sku == 5 || sku == 9) { + IWL_DEBUG_EEPROM(dev, + "disabling wide channels in 5GHz (0x%0x %d)\n", + subsystem_id, sku); + return true; + } + } + + return false; +} + struct iwl_nvm_data * iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, - const __le16 *nvm_hw, const __le16 *nvm_sw, + const __be16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, bool lar_fw_supported) @@ -655,6 +701,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct device *dev = trans->dev; struct iwl_nvm_data *data; bool lar_enabled; + bool no_wide_in_5ghz = iwl_nvm_no_wide_in_5ghz(dev, cfg, nvm_hw); u32 sku, radio_cfg; u16 lar_config; const __le16 *ch_section; @@ -725,7 +772,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, } iwl_init_sbands(dev, cfg, data, ch_section, tx_chains, rx_chains, - lar_fw_supported && lar_enabled); + lar_fw_supported && lar_enabled, no_wide_in_5ghz); data->calib_version = 255; return data; @@ -868,19 +915,27 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, prev_reg_rule_flags = reg_rule_flags; IWL_DEBUG_DEV(dev, IWL_DL_LAR, - "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x) reg_flags 0x%x: %s\n", + "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s%s%s%s(0x%02x)\n", center_freq, band == NL80211_BAND_5GHZ ? "5.2" : "2.4", CHECK_AND_PRINT_I(VALID), + CHECK_AND_PRINT_I(IBSS), CHECK_AND_PRINT_I(ACTIVE), CHECK_AND_PRINT_I(RADAR), - CHECK_AND_PRINT_I(WIDE), + CHECK_AND_PRINT_I(INDOOR_ONLY), + CHECK_AND_PRINT_I(GO_CONCURRENT), + CHECK_AND_PRINT_I(UNIFORM), + CHECK_AND_PRINT_I(20MHZ), CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), - CHECK_AND_PRINT_I(INDOOR_ONLY), - CHECK_AND_PRINT_I(GO_CONCURRENT), - ch_flags, reg_rule_flags, + CHECK_AND_PRINT_I(DC_HIGH), + ch_flags); + IWL_DEBUG_DEV(dev, IWL_DL_LAR, + "Ch. %d [%sGHz] reg_flags 0x%x: %s\n", + center_freq, + band == NL80211_BAND_5GHZ ? "5.2" : "2.4", + reg_rule_flags, ((ch_flags & NVM_CHANNEL_ACTIVE) && !(ch_flags & NVM_CHANNEL_RADAR)) ? "Ad-Hoc" : ""); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 3fd6506a02ab..2d1a24dd8410 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -77,7 +77,7 @@ */ struct iwl_nvm_data * iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, - const __le16 *nvm_hw, const __le16 *nvm_sw, + const __be16 *nvm_hw, const __le16 *nvm_sw, const __le16 *nvm_calib, const __le16 *regulatory, const __le16 *mac_override, const __le16 *phy_sku, u8 tx_chains, u8 rx_chains, bool lar_fw_supported); @@ -93,7 +93,8 @@ void iwl_set_hw_address_from_csr(struct iwl_trans *trans, */ void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const __le16 *nvm_ch_flags, - u8 tx_chains, u8 rx_chains, bool lar_supported); + u8 tx_chains, u8 rx_chains, bool lar_supported, + bool no_wide_in_5ghz); /** * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 6772c59b7764..421a869633a3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -109,13 +109,12 @@ /* Device system time */ #define DEVICE_SYSTEM_TIME_REG 0xA0206C -/* Device NMI register */ +/* Device NMI register and value for 8000 family and lower hw's */ #define DEVICE_SET_NMI_REG 0x00a01c30 -#define DEVICE_SET_NMI_VAL_HW BIT(0) #define DEVICE_SET_NMI_VAL_DRV BIT(7) -#define DEVICE_SET_NMI_8000_REG 0x00a01c24 -#define DEVICE_SET_NMI_8000_VAL 0x1000000 +/* Device NMI register and value for 9000 family and above hw's */ #define UREG_NIC_SET_NMI_DRIVER 0x00a05c10 +#define UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER_MSK 0xff000000 /* Shared registers (0x0..0x3ff, via target indirect or periphery */ #define SHR_BASE 0x00a10000 @@ -404,6 +403,12 @@ enum aux_misc_master1_en { #define SB_CPU_2_STATUS 0xA01E34 #define UMAG_SB_CPU_1_STATUS 0xA038C0 #define UMAG_SB_CPU_2_STATUS 0xA038C4 +#define UMAG_GEN_HW_STATUS 0xA038C8 + +/* For UMAG_GEN_HW_STATUS reg check */ +enum { + UMAG_GEN_HW_IS_FPGA = BIT(1), +}; /* FW chicken bits */ #define LMPM_CHICK 0xA01FF8 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index eb6842abb4c7..e90abbfba718 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -76,7 +76,8 @@ #include "iwl-config.h" #include "fw/img.h" #include "iwl-op-mode.h" -#include "fw/api.h" +#include "fw/api/cmdhdr.h" +#include "fw/api/txq.h" /** * DOC: Transport layer - what is it ? diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 83ac807e547d..00e6737dda72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -6,7 +6,7 @@ iwlmvm-y += power.o coex.o iwlmvm-y += tt.o offloading.o tdls.o iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o -iwlmvm-y += tof.o fw-dbg.o +iwlmvm-y += tof.o iwlmvm-$(CONFIG_PM) += d3.o ccflags-y += -I$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 34dd5c40ce77..79c80f181f7d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -7,6 +7,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,7 +69,7 @@ #include <linux/etherdevice.h> #include <net/mac80211.h> -#include "fw-api-coex.h" +#include "fw/api/coex.h" #include "iwl-modparams.h" #include "mvm.h" #include "iwl-debug.h" @@ -148,215 +150,6 @@ static const __le64 iwl_ci_mask[][3] = { }, }; -struct corunning_block_luts { - u8 range; - __le32 lut20[BT_COEX_CORUN_LUT_SIZE]; -}; - -/* - * Ranges for the antenna coupling calibration / co-running block LUT: - * LUT0: [ 0, 12[ - * LUT1: [12, 20[ - * LUT2: [20, 21[ - * LUT3: [21, 23[ - * LUT4: [23, 27[ - * LUT5: [27, 30[ - * LUT6: [30, 32[ - * LUT7: [32, 33[ - * LUT8: [33, - [ - */ -static const struct corunning_block_luts antenna_coupling_ranges[] = { - { - .range = 0, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 12, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 20, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 21, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 23, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 27, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 30, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 32, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, - { - .range = 33, - .lut20 = { - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - cpu_to_le32(0x00000000), cpu_to_le32(0x00000000), - }, - }, -}; - static enum iwl_bt_coex_lut_type iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) { @@ -437,9 +230,6 @@ int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm) bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED); - if (iwl_mvm_bt_is_plcr_supported(mvm)) - bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED); - if (iwl_mvm_is_mplut_supported(mvm)) bt_cmd.enabled_modules |= cpu_to_le32(BT_COEX_MPLUT_ENABLED); @@ -560,8 +350,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, smps_mode = IEEE80211_SMPS_AUTOMATIC; if (mvmvif->phy_ctxt && - IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status, - mvmvif->phy_ctxt->id)) + (mvm->last_bt_notif.rrc_status & BIT(mvmvif->phy_ctxt->id))) smps_mode = IEEE80211_SMPS_AUTOMATIC; IWL_DEBUG_COEX(data->mvm, @@ -725,17 +514,36 @@ void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; + if (!iwl_mvm_has_new_ats_coex_api(mvm)) { + struct iwl_bt_coex_profile_notif_v4 *v4 = (void *)pkt->data; + + mvm->last_bt_notif.mbox_msg[0] = v4->mbox_msg[0]; + mvm->last_bt_notif.mbox_msg[1] = v4->mbox_msg[1]; + mvm->last_bt_notif.mbox_msg[2] = v4->mbox_msg[2]; + mvm->last_bt_notif.mbox_msg[3] = v4->mbox_msg[3]; + mvm->last_bt_notif.msg_idx = v4->msg_idx; + mvm->last_bt_notif.bt_ci_compliance = v4->bt_ci_compliance; + mvm->last_bt_notif.primary_ch_lut = v4->primary_ch_lut; + mvm->last_bt_notif.secondary_ch_lut = v4->secondary_ch_lut; + mvm->last_bt_notif.bt_activity_grading = + v4->bt_activity_grading; + mvm->last_bt_notif.ttc_status = v4->ttc_status; + mvm->last_bt_notif.rrc_status = v4->rrc_status; + } else { + /* save this notification for future use: rssi fluctuations */ + memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); + } + IWL_DEBUG_COEX(mvm, "BT Coex Notification received\n"); - IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", notif->bt_ci_compliance); + IWL_DEBUG_COEX(mvm, "\tBT ci compliance %d\n", + mvm->last_bt_notif.bt_ci_compliance); IWL_DEBUG_COEX(mvm, "\tBT primary_ch_lut %d\n", - le32_to_cpu(notif->primary_ch_lut)); + le32_to_cpu(mvm->last_bt_notif.primary_ch_lut)); IWL_DEBUG_COEX(mvm, "\tBT secondary_ch_lut %d\n", - le32_to_cpu(notif->secondary_ch_lut)); + le32_to_cpu(mvm->last_bt_notif.secondary_ch_lut)); IWL_DEBUG_COEX(mvm, "\tBT activity grading %d\n", - le32_to_cpu(notif->bt_activity_grading)); + le32_to_cpu(mvm->last_bt_notif.bt_activity_grading)); - /* remember this notification for future use: rssi fluctuations */ - memcpy(&mvm->last_bt_notif, notif, sizeof(mvm->last_bt_notif)); iwl_mvm_bt_coex_notif_handle(mvm); } @@ -792,7 +600,7 @@ u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; enum iwl_bt_coex_lut_type lut_type; - if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) + if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id)) return LINK_QUAL_AGG_TIME_LIMIT_DEF; if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < @@ -816,7 +624,7 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *phy_ctxt = mvmvif->phy_ctxt; enum iwl_bt_coex_lut_type lut_type; - if (IWL_COEX_IS_TTC_ON(mvm->last_bt_notif.ttc_rrc_status, phy_ctxt->id)) + if (mvm->last_bt_notif.ttc_status & BIT(phy_ctxt->id)) return true; if (le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < @@ -909,59 +717,3 @@ void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm) { iwl_mvm_bt_coex_notif_handle(mvm); } - -void iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_mvm_antenna_coupling_notif *notif = (void *)pkt->data; - u32 ant_isolation = le32_to_cpu(notif->isolation); - struct iwl_bt_coex_corun_lut_update_cmd cmd = {}; - u8 __maybe_unused lower_bound, upper_bound; - u8 lut; - - if (!iwl_mvm_bt_is_plcr_supported(mvm)) - return; - - lockdep_assert_held(&mvm->mutex); - - /* Ignore updates if we are in force mode */ - if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) - return; - - if (ant_isolation == mvm->last_ant_isol) - return; - - for (lut = 0; lut < ARRAY_SIZE(antenna_coupling_ranges) - 1; lut++) - if (ant_isolation < antenna_coupling_ranges[lut + 1].range) - break; - - lower_bound = antenna_coupling_ranges[lut].range; - - if (lut < ARRAY_SIZE(antenna_coupling_ranges) - 1) - upper_bound = antenna_coupling_ranges[lut + 1].range; - else - upper_bound = antenna_coupling_ranges[lut].range; - - IWL_DEBUG_COEX(mvm, "Antenna isolation=%d in range [%d,%d[, lut=%d\n", - ant_isolation, lower_bound, upper_bound, lut); - - mvm->last_ant_isol = ant_isolation; - - if (mvm->last_corun_lut == lut) - return; - - mvm->last_corun_lut = lut; - - /* For the moment, use the same LUT for 20GHz and 40GHz */ - memcpy(&cmd.corun_lut20, antenna_coupling_ranges[lut].lut20, - sizeof(cmd.corun_lut20)); - - memcpy(&cmd.corun_lut40, antenna_coupling_ranges[lut].lut20, - sizeof(cmd.corun_lut40)); - - if (iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_CORUN_LUT, 0, - sizeof(cmd), &cmd)) - IWL_ERR(mvm, - "failed to send BT_COEX_UPDATE_CORUN_LUT command\n"); -} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 6fda8627b726..976640fed334 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -95,7 +95,6 @@ #define IWL_MVM_BT_COEX_EN_RED_TXP_THRESH 62 #define IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH 65 #define IWL_MVM_BT_COEX_SYNC2SCO 1 -#define IWL_MVM_BT_COEX_CORUNNING 0 #define IWL_MVM_BT_COEX_MPLUT 1 #define IWL_MVM_BT_COEX_RRC 1 #define IWL_MVM_BT_COEX_TTC 1 @@ -111,7 +110,6 @@ #define IWL_MVM_SW_TX_CSUM_OFFLOAD 0 #define IWL_MVM_HW_CSUM_DISABLE 0 #define IWL_MVM_PARSE_NVM 0 -#define IWL_MVM_COLLECT_FW_ERR_DUMP 1 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 @@ -138,8 +136,10 @@ #define IWL_MVM_RS_SR_NO_DECREASE 85 /* percent */ #define IWL_MVM_RS_AGG_TIME_LIMIT 4000 /* 4 msecs. valid 100-8000 */ #define IWL_MVM_RS_AGG_DISABLE_START 3 +#define IWL_MVM_RS_AGG_START_THRESHOLD 10 /* num frames per second */ #define IWL_MVM_RS_TPC_SR_FORCE_INCREASE 75 /* percent */ #define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */ #define IWL_MVM_RS_TPC_TX_POWER_STEP 3 +#define IWL_MVM_ENABLE_EBS 1 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index a7ac281e5cde..71a01df96f8b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -65,7 +65,7 @@ * *****************************************************************************/ #include "mvm.h" -#include "fw-api-tof.h" +#include "fw/api/tof.h" #include "debugfs.h" static void iwl_dbgfs_update_pm(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index c1c9c489edc9..e97904c2c4d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -69,7 +69,6 @@ #include <linux/netdevice.h> #include "mvm.h" -#include "fw-dbg.h" #include "sta.h" #include "iwl-io.h" #include "debugfs.h" @@ -83,8 +82,11 @@ static ssize_t iwl_dbgfs_ctdp_budget_read(struct file *file, char buf[16]; int pos, budget; + if (!iwl_mvm_is_ctdp_supported(mvm)) + return -EOPNOTSUPP; + if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -104,8 +106,11 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, { int ret; + if (!iwl_mvm_is_ctdp_supported(mvm)) + return -EOPNOTSUPP; + if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; mutex_lock(&mvm->mutex); @@ -115,6 +120,18 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } +static ssize_t iwl_dbgfs_force_ctkill_write(struct iwl_mvm *mvm, char *buf, + size_t count, loff_t *ppos) +{ + if (!iwl_mvm_firmware_running(mvm) || + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) + return -EIO; + + iwl_mvm_enter_ctkill(mvm); + + return count; +} + static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { @@ -122,7 +139,7 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, u32 flush_arg; if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; if (kstrtou32(buf, 0, &flush_arg)) @@ -155,7 +172,7 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, int sta_id, drain, ret; if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) return -EIO; if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) @@ -192,7 +209,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, return -EINVAL; /* default is to dump the entire data segment */ - img = &mvm->fw->img[mvm->cur_ucode]; + img = &mvm->fw->img[mvm->fwrt.cur_fw_img]; ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; len = img->sec[IWL_UCODE_SECTION_DATA].len; @@ -224,7 +241,7 @@ static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, if (!iwl_mvm_firmware_running(mvm)) return -EINVAL; - img = &mvm->fw->img[mvm->cur_ucode]; + img = &mvm->fw->img[mvm->fwrt.cur_fw_img]; img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset; img_len = img->sec[IWL_UCODE_SECTION_DATA].len; @@ -452,20 +469,9 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } -#define BT_MBOX_MSG(_notif, _num, _field) \ - ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ - >> BT_MBOX##_num##_##_field##_POS) - - -#define BT_MBOX_PRINT(_num, _field, _end) \ - pos += scnprintf(buf + pos, bufsz - pos, \ - "\t%s: %d%s", \ - #_field, \ - BT_MBOX_MSG(notif, _num, _field), \ - true ? "\n" : ", "); - static -int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, +int iwl_mvm_coex_dump_mbox(struct iwl_mvm *mvm, + struct iwl_bt_coex_profile_notif *notif, char *buf, int pos, int bufsz) { pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); @@ -509,6 +515,7 @@ int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, BT_MBOX_PRINT(3, SCO_STATE, false); BT_MBOX_PRINT(3, SNIFF_STATE, false); BT_MBOX_PRINT(3, A2DP_STATE, false); + BT_MBOX_PRINT(3, A2DP_SRC, false); BT_MBOX_PRINT(3, ACL_STATE, false); BT_MBOX_PRINT(3, MSTR_STATE, false); BT_MBOX_PRINT(3, OBX_STATE, false); @@ -518,7 +525,12 @@ int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, BT_MBOX_PRINT(3, INBAND_P, false); BT_MBOX_PRINT(3, MSG_TYPE_2, false); BT_MBOX_PRINT(3, SSN_2, false); - BT_MBOX_PRINT(3, UPDATE_REQUEST, true); + BT_MBOX_PRINT(3, UPDATE_REQUEST, !iwl_mvm_has_new_ats_coex_api(mvm)); + + if (iwl_mvm_has_new_ats_coex_api(mvm)) { + BT_MBOX_PRINT(4, ATS_BT_INTERVAL, false); + BT_MBOX_PRINT(4, ATS_BT_ACTIVE_MAX_TH, true); + } return pos; } @@ -537,7 +549,7 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, mutex_lock(&mvm->mutex); - pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz); + pos += iwl_mvm_coex_dump_mbox(mvm, notif, buf, pos, bufsz); pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n", notif->bt_ci_compliance); @@ -548,20 +560,15 @@ static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, pos += scnprintf(buf + pos, bufsz - pos, "bt_activity_grading = %d\n", le32_to_cpu(notif->bt_activity_grading)); - pos += scnprintf(buf + pos, bufsz - pos, - "antenna isolation = %d CORUN LUT index = %d\n", - mvm->last_ant_isol, mvm->last_corun_lut); pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n", - (notif->ttc_rrc_status >> 4) & 0xF); + notif->rrc_status & 0xF); pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n", - notif->ttc_rrc_status & 0xF); + notif->ttc_status & 0xF); pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n", IWL_MVM_BT_COEX_SYNC2SCO); pos += scnprintf(buf + pos, bufsz - pos, "mplut = %d\n", IWL_MVM_BT_COEX_MPLUT); - pos += scnprintf(buf + pos, bufsz - pos, "corunning = %d\n", - IWL_MVM_BT_COEX_CORUNNING); mutex_unlock(&mvm->mutex); @@ -1123,7 +1130,7 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file, int pos = 0; mutex_lock(&mvm->mutex); - conf = mvm->fw_dbg_conf; + conf = mvm->fwrt.dump.conf; mutex_unlock(&mvm->mutex); pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf); @@ -1190,7 +1197,7 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, return -EINVAL; mutex_lock(&mvm->mutex); - ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id); + ret = iwl_fw_start_dbg_conf(&mvm->fwrt, conf_id); mutex_unlock(&mvm->mutex); return ret ?: count; @@ -1211,8 +1218,8 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, if (count == 0) return 0; - iwl_mvm_fw_dbg_collect(mvm, FW_DBG_TRIGGER_USER, buf, - (count - 1), NULL); + iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, + (count - 1), NULL); iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); @@ -1642,6 +1649,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget); MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8); +MVM_DEBUGFS_WRITE_FILE_OPS(force_ctkill, 8); MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); MVM_DEBUGFS_WRITE_FILE_OPS(sta_drain, 8); MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8); @@ -1829,6 +1837,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, S_IWUSR); MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h index aad265dcfaf5..e8e74dd558f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h @@ -68,2823 +68,33 @@ #ifndef __fw_api_h__ #define __fw_api_h__ -#include "fw-api-rs.h" -#include "fw-api-rx.h" -#include "fw-api-tx.h" -#include "fw-api-sta.h" -#include "fw-api-mac.h" -#include "fw-api-power.h" -#include "fw-api-d3.h" -#include "fw-api-coex.h" -#include "fw-api-scan.h" -#include "fw-api-stats.h" -#include "fw-api-tof.h" - -/* Tx queue numbers for non-DQA mode */ -enum { - IWL_MVM_OFFCHANNEL_QUEUE = 8, - IWL_MVM_CMD_QUEUE = 9, -}; - -/* - * DQA queue numbers - * - * @IWL_MVM_DQA_CMD_QUEUE: a queue reserved for sending HCMDs to the FW - * @IWL_MVM_DQA_AUX_QUEUE: a queue reserved for aux frames - * @IWL_MVM_DQA_P2P_DEVICE_QUEUE: a queue reserved for P2P device frames - * @IWL_MVM_DQA_GCAST_QUEUE: a queue reserved for P2P GO/SoftAP GCAST frames - * @IWL_MVM_DQA_BSS_CLIENT_QUEUE: a queue reserved for BSS activity, to ensure - * that we are never left without the possibility to connect to an AP. - * @IWL_MVM_DQA_MIN_MGMT_QUEUE: first TXQ in pool for MGMT and non-QOS frames. - * Each MGMT queue is mapped to a single STA - * MGMT frames are frames that return true on ieee80211_is_mgmt() - * @IWL_MVM_DQA_MAX_MGMT_QUEUE: last TXQ in pool for MGMT frames - * @IWL_MVM_DQA_AP_PROBE_RESP_QUEUE: a queue reserved for P2P GO/SoftAP probe - * responses - * @IWL_MVM_DQA_MIN_DATA_QUEUE: first TXQ in pool for DATA frames. - * DATA frames are intended for !ieee80211_is_mgmt() frames, but if - * the MGMT TXQ pool is exhausted, mgmt frames can be sent on DATA queues - * as well - * @IWL_MVM_DQA_MAX_DATA_QUEUE: last TXQ in pool for DATA frames - */ -enum iwl_mvm_dqa_txq { - IWL_MVM_DQA_CMD_QUEUE = 0, - IWL_MVM_DQA_AUX_QUEUE = 1, - IWL_MVM_DQA_P2P_DEVICE_QUEUE = 2, - IWL_MVM_DQA_GCAST_QUEUE = 3, - IWL_MVM_DQA_BSS_CLIENT_QUEUE = 4, - IWL_MVM_DQA_MIN_MGMT_QUEUE = 5, - IWL_MVM_DQA_MAX_MGMT_QUEUE = 8, - IWL_MVM_DQA_AP_PROBE_RESP_QUEUE = 9, - IWL_MVM_DQA_MIN_DATA_QUEUE = 10, - IWL_MVM_DQA_MAX_DATA_QUEUE = 31, -}; - -enum iwl_mvm_tx_fifo { - IWL_MVM_TX_FIFO_BK = 0, - IWL_MVM_TX_FIFO_BE, - IWL_MVM_TX_FIFO_VI, - IWL_MVM_TX_FIFO_VO, - IWL_MVM_TX_FIFO_MCAST = 5, - IWL_MVM_TX_FIFO_CMD = 7, -}; - - -/** - * enum iwl_legacy_cmds - legacy group command IDs - */ -enum iwl_legacy_cmds { - /** - * @MVM_ALIVE: - * Alive data from the firmware, as described in - * &struct mvm_alive_resp_v3 or &struct mvm_alive_resp. - */ - MVM_ALIVE = 0x1, - - /** - * @REPLY_ERROR: Cause an error in the firmware, for testing purposes. - */ - REPLY_ERROR = 0x2, - - /** - * @ECHO_CMD: Send data to the device to have it returned immediately. - */ - ECHO_CMD = 0x3, - - /** - * @INIT_COMPLETE_NOTIF: Notification that initialization is complete. - */ - INIT_COMPLETE_NOTIF = 0x4, - - /** - * @PHY_CONTEXT_CMD: - * Add/modify/remove a PHY context, using &struct iwl_phy_context_cmd. - */ - PHY_CONTEXT_CMD = 0x8, - - /** - * @DBG_CFG: Debug configuration command. - */ - DBG_CFG = 0x9, - - /** - * @ANTENNA_COUPLING_NOTIFICATION: - * Antenna coupling data, &struct iwl_mvm_antenna_coupling_notif - */ - ANTENNA_COUPLING_NOTIFICATION = 0xa, - - /** - * @SCAN_ITERATION_COMPLETE_UMAC: - * Firmware indicates a scan iteration completed, using - * &struct iwl_umac_scan_iter_complete_notif. - */ - SCAN_ITERATION_COMPLETE_UMAC = 0xb5, - - /** - * @SCAN_CFG_CMD: - * uses &struct iwl_scan_config_v1 or &struct iwl_scan_config - */ - SCAN_CFG_CMD = 0xc, - - /** - * @SCAN_REQ_UMAC: uses &struct iwl_scan_req_umac - */ - SCAN_REQ_UMAC = 0xd, - - /** - * @SCAN_ABORT_UMAC: uses &struct iwl_umac_scan_abort - */ - SCAN_ABORT_UMAC = 0xe, - - /** - * @SCAN_COMPLETE_UMAC: uses &struct iwl_umac_scan_complete - */ - SCAN_COMPLETE_UMAC = 0xf, - - /** - * @BA_WINDOW_STATUS_NOTIFICATION_ID: - * uses &struct iwl_ba_window_status_notif - */ - BA_WINDOW_STATUS_NOTIFICATION_ID = 0x13, - - /** - * @ADD_STA_KEY: - * &struct iwl_mvm_add_sta_key_cmd_v1 or - * &struct iwl_mvm_add_sta_key_cmd. - */ - ADD_STA_KEY = 0x17, - - /** - * @ADD_STA: - * &struct iwl_mvm_add_sta_cmd or &struct iwl_mvm_add_sta_cmd_v7. - */ - ADD_STA = 0x18, - - /** - * @REMOVE_STA: &struct iwl_mvm_rm_sta_cmd - */ - REMOVE_STA = 0x19, - - /** - * @FW_GET_ITEM_CMD: uses &struct iwl_fw_get_item_cmd - */ - FW_GET_ITEM_CMD = 0x1a, - - /** - * @TX_CMD: uses &struct iwl_tx_cmd or &struct iwl_tx_cmd_gen2, - * response in &struct iwl_mvm_tx_resp or - * &struct iwl_mvm_tx_resp_v3 - */ - TX_CMD = 0x1c, - - /** - * @TXPATH_FLUSH: &struct iwl_tx_path_flush_cmd - */ - TXPATH_FLUSH = 0x1e, - - /** - * @MGMT_MCAST_KEY: - * &struct iwl_mvm_mgmt_mcast_key_cmd or - * &struct iwl_mvm_mgmt_mcast_key_cmd_v1 - */ - MGMT_MCAST_KEY = 0x1f, - - /* scheduler config */ - /** - * @SCD_QUEUE_CFG: &struct iwl_scd_txq_cfg_cmd for older hardware, - * &struct iwl_tx_queue_cfg_cmd with &struct iwl_tx_queue_cfg_rsp - * for newer (A000) hardware. - */ - SCD_QUEUE_CFG = 0x1d, - - /** - * @WEP_KEY: uses &struct iwl_mvm_wep_key_cmd - */ - WEP_KEY = 0x20, - - /** - * @SHARED_MEM_CFG: - * retrieve shared memory configuration - response in - * &struct iwl_shared_mem_cfg - */ - SHARED_MEM_CFG = 0x25, - - /** - * @TDLS_CHANNEL_SWITCH_CMD: uses &struct iwl_tdls_channel_switch_cmd - */ - TDLS_CHANNEL_SWITCH_CMD = 0x27, - - /** - * @TDLS_CHANNEL_SWITCH_NOTIFICATION: - * uses &struct iwl_tdls_channel_switch_notif - */ - TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa, - - /** - * @TDLS_CONFIG_CMD: - * &struct iwl_tdls_config_cmd, response in &struct iwl_tdls_config_res - */ - TDLS_CONFIG_CMD = 0xa7, - - /** - * @MAC_CONTEXT_CMD: &struct iwl_mac_ctx_cmd - */ - MAC_CONTEXT_CMD = 0x28, - - /** - * @TIME_EVENT_CMD: - * &struct iwl_time_event_cmd, response in &struct iwl_time_event_resp - */ - TIME_EVENT_CMD = 0x29, /* both CMD and response */ - - /** - * @TIME_EVENT_NOTIFICATION: &struct iwl_time_event_notif - */ - TIME_EVENT_NOTIFICATION = 0x2a, - - /** - * @BINDING_CONTEXT_CMD: - * &struct iwl_binding_cmd or &struct iwl_binding_cmd_v1 - */ - BINDING_CONTEXT_CMD = 0x2b, - - /** - * @TIME_QUOTA_CMD: &struct iwl_time_quota_cmd - */ - TIME_QUOTA_CMD = 0x2c, - - /** - * @NON_QOS_TX_COUNTER_CMD: - * command is &struct iwl_nonqos_seq_query_cmd - */ - NON_QOS_TX_COUNTER_CMD = 0x2d, - - /** - * @LQ_CMD: using &struct iwl_lq_cmd - */ - LQ_CMD = 0x4e, - - /** - * @FW_PAGING_BLOCK_CMD: - * &struct iwl_fw_paging_cmd - */ - FW_PAGING_BLOCK_CMD = 0x4f, - - /** - * @SCAN_OFFLOAD_REQUEST_CMD: uses &struct iwl_scan_req_lmac - */ - SCAN_OFFLOAD_REQUEST_CMD = 0x51, - - /** - * @SCAN_OFFLOAD_ABORT_CMD: abort the scan - no further contents - */ - SCAN_OFFLOAD_ABORT_CMD = 0x52, - - /** - * @HOT_SPOT_CMD: uses &struct iwl_hs20_roc_req - */ - HOT_SPOT_CMD = 0x53, - - /** - * @SCAN_OFFLOAD_COMPLETE: - * notification, &struct iwl_periodic_scan_complete - */ - SCAN_OFFLOAD_COMPLETE = 0x6D, - - /** - * @SCAN_OFFLOAD_UPDATE_PROFILES_CMD: - * update scan offload (scheduled scan) profiles/blacklist/etc. - */ - SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, - - /** - * @MATCH_FOUND_NOTIFICATION: scan match found - */ - MATCH_FOUND_NOTIFICATION = 0xd9, - - /** - * @SCAN_ITERATION_COMPLETE: - * uses &struct iwl_lmac_scan_complete_notif - */ - SCAN_ITERATION_COMPLETE = 0xe7, - - /* Phy */ - /** - * @PHY_CONFIGURATION_CMD: &struct iwl_phy_cfg_cmd - */ - PHY_CONFIGURATION_CMD = 0x6a, - - /** - * @CALIB_RES_NOTIF_PHY_DB: &struct iwl_calib_res_notif_phy_db - */ - CALIB_RES_NOTIF_PHY_DB = 0x6b, - - /** - * @PHY_DB_CMD: &struct iwl_phy_db_cmd - */ - PHY_DB_CMD = 0x6c, - - /** - * @TOF_CMD: &struct iwl_tof_config_cmd - */ - TOF_CMD = 0x10, - - /** - * @TOF_NOTIFICATION: &struct iwl_tof_gen_resp_cmd - */ - TOF_NOTIFICATION = 0x11, - - /** - * @POWER_TABLE_CMD: &struct iwl_device_power_cmd - */ - POWER_TABLE_CMD = 0x77, - - /** - * @PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION: - * &struct iwl_uapsd_misbehaving_ap_notif - */ - PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION = 0x78, - - /** - * @LTR_CONFIG: &struct iwl_ltr_config_cmd - */ - LTR_CONFIG = 0xee, - - /** - * @REPLY_THERMAL_MNG_BACKOFF: - * Thermal throttling command - */ - REPLY_THERMAL_MNG_BACKOFF = 0x7e, - - /** - * @DC2DC_CONFIG_CMD: - * Set/Get DC2DC frequency tune - * Command is &struct iwl_dc2dc_config_cmd, - * response is &struct iwl_dc2dc_config_resp - */ - DC2DC_CONFIG_CMD = 0x83, - - /** - * @NVM_ACCESS_CMD: using &struct iwl_nvm_access_cmd - */ - NVM_ACCESS_CMD = 0x88, - - /** - * @BEACON_NOTIFICATION: &struct iwl_extended_beacon_notif - */ - BEACON_NOTIFICATION = 0x90, - - /** - * @BEACON_TEMPLATE_CMD: - * Uses one of &struct iwl_mac_beacon_cmd_v6, - * &struct iwl_mac_beacon_cmd_v7 or &struct iwl_mac_beacon_cmd - * depending on the device version. - */ - BEACON_TEMPLATE_CMD = 0x91, - /** - * @TX_ANT_CONFIGURATION_CMD: &struct iwl_tx_ant_cfg_cmd - */ - TX_ANT_CONFIGURATION_CMD = 0x98, - - /** - * @STATISTICS_CMD: - * one of &struct iwl_statistics_cmd, - * &struct iwl_notif_statistics_v11, - * &struct iwl_notif_statistics_v10, - * &struct iwl_notif_statistics_cdb - */ - STATISTICS_CMD = 0x9c, - - /** - * @STATISTICS_NOTIFICATION: - * one of &struct iwl_notif_statistics_v10, - * &struct iwl_notif_statistics_v11, - * &struct iwl_notif_statistics_cdb - */ - STATISTICS_NOTIFICATION = 0x9d, - - /** - * @EOSP_NOTIFICATION: - * Notify that a service period ended, - * &struct iwl_mvm_eosp_notification - */ - EOSP_NOTIFICATION = 0x9e, - - /** - * @REDUCE_TX_POWER_CMD: - * &struct iwl_dev_tx_power_cmd_v3 or &struct iwl_dev_tx_power_cmd - */ - REDUCE_TX_POWER_CMD = 0x9f, - - /** - * @CARD_STATE_NOTIFICATION: - * Card state (RF/CT kill) notification, - * uses &struct iwl_card_state_notif - */ - CARD_STATE_NOTIFICATION = 0xa1, - - /** - * @MISSED_BEACONS_NOTIFICATION: &struct iwl_missed_beacons_notif - */ - MISSED_BEACONS_NOTIFICATION = 0xa2, - - /** - * @MAC_PM_POWER_TABLE: using &struct iwl_mac_power_cmd - */ - MAC_PM_POWER_TABLE = 0xa9, - - /** - * @MFUART_LOAD_NOTIFICATION: &struct iwl_mfuart_load_notif - */ - MFUART_LOAD_NOTIFICATION = 0xb1, - - /** - * @RSS_CONFIG_CMD: &struct iwl_rss_config_cmd - */ - RSS_CONFIG_CMD = 0xb3, - - /** - * @REPLY_RX_PHY_CMD: &struct iwl_rx_phy_info - */ - REPLY_RX_PHY_CMD = 0xc0, - - /** - * @REPLY_RX_MPDU_CMD: - * &struct iwl_rx_mpdu_res_start or &struct iwl_rx_mpdu_desc - */ - REPLY_RX_MPDU_CMD = 0xc1, - - /** - * @FRAME_RELEASE: - * Frame release (reorder helper) notification, uses - * &struct iwl_frame_release - */ - FRAME_RELEASE = 0xc3, - - /** - * @BA_NOTIF: - * BlockAck notification, uses &struct iwl_mvm_compressed_ba_notif - * or &struct iwl_mvm_ba_notif depending on the HW - */ - BA_NOTIF = 0xc5, - - /* Location Aware Regulatory */ - /** - * @MCC_UPDATE_CMD: using &struct iwl_mcc_update_cmd - */ - MCC_UPDATE_CMD = 0xc8, - - /** - * @MCC_CHUB_UPDATE_CMD: using &struct iwl_mcc_chub_notif - */ - MCC_CHUB_UPDATE_CMD = 0xc9, - - /** - * @MARKER_CMD: trace marker command, uses &struct iwl_mvm_marker - */ - MARKER_CMD = 0xcb, - - /** - * @BT_PROFILE_NOTIFICATION: &struct iwl_bt_coex_profile_notif - */ - BT_PROFILE_NOTIFICATION = 0xce, - - /** - * @BT_CONFIG: &struct iwl_bt_coex_cmd - */ - BT_CONFIG = 0x9b, - - /** - * @BT_COEX_UPDATE_CORUN_LUT: - * &struct iwl_bt_coex_corun_lut_update_cmd - */ - BT_COEX_UPDATE_CORUN_LUT = 0x5b, - - /** - * @BT_COEX_UPDATE_REDUCED_TXP: - * &struct iwl_bt_coex_reduced_txp_update_cmd - */ - BT_COEX_UPDATE_REDUCED_TXP = 0x5c, - - /** - * @BT_COEX_CI: &struct iwl_bt_coex_ci_cmd - */ - BT_COEX_CI = 0x5d, - - /** - * @REPLY_SF_CFG_CMD: &struct iwl_sf_cfg_cmd - */ - REPLY_SF_CFG_CMD = 0xd1, - /** - * @REPLY_BEACON_FILTERING_CMD: &struct iwl_beacon_filter_cmd - */ - REPLY_BEACON_FILTERING_CMD = 0xd2, - - /** - * @DTS_MEASUREMENT_NOTIFICATION: - * &struct iwl_dts_measurement_notif_v1 or - * &struct iwl_dts_measurement_notif_v2 - */ - DTS_MEASUREMENT_NOTIFICATION = 0xdd, - - /** - * @LDBG_CONFIG_CMD: configure continuous trace recording - */ - LDBG_CONFIG_CMD = 0xf6, - - /** - * @DEBUG_LOG_MSG: Debugging log data from firmware - */ - DEBUG_LOG_MSG = 0xf7, - - /** - * @BCAST_FILTER_CMD: &struct iwl_bcast_filter_cmd - */ - BCAST_FILTER_CMD = 0xcf, - - /** - * @MCAST_FILTER_CMD: &struct iwl_mcast_filter_cmd - */ - MCAST_FILTER_CMD = 0xd0, - - /** - * @D3_CONFIG_CMD: &struct iwl_d3_manager_config - */ - D3_CONFIG_CMD = 0xd3, - - /** - * @PROT_OFFLOAD_CONFIG_CMD: Depending on firmware, uses one of - * &struct iwl_proto_offload_cmd_v1, &struct iwl_proto_offload_cmd_v2, - * &struct iwl_proto_offload_cmd_v3_small, - * &struct iwl_proto_offload_cmd_v3_large - */ - PROT_OFFLOAD_CONFIG_CMD = 0xd4, - - /** - * @OFFLOADS_QUERY_CMD: - * No data in command, response in &struct iwl_wowlan_status - */ - OFFLOADS_QUERY_CMD = 0xd5, - - /** - * @REMOTE_WAKE_CONFIG_CMD: &struct iwl_wowlan_remote_wake_config - */ - REMOTE_WAKE_CONFIG_CMD = 0xd6, - - /** - * @D0I3_END_CMD: End D0i3/D3 state, no command data - */ - D0I3_END_CMD = 0xed, - - /** - * @WOWLAN_PATTERNS: &struct iwl_wowlan_patterns_cmd - */ - WOWLAN_PATTERNS = 0xe0, - - /** - * @WOWLAN_CONFIGURATION: &struct iwl_wowlan_config_cmd - */ - WOWLAN_CONFIGURATION = 0xe1, - - /** - * @WOWLAN_TSC_RSC_PARAM: &struct iwl_wowlan_rsc_tsc_params_cmd - */ - WOWLAN_TSC_RSC_PARAM = 0xe2, - - /** - * @WOWLAN_TKIP_PARAM: &struct iwl_wowlan_tkip_params_cmd - */ - WOWLAN_TKIP_PARAM = 0xe3, - - /** - * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd - */ - WOWLAN_KEK_KCK_MATERIAL = 0xe4, - - /** - * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status - */ - WOWLAN_GET_STATUSES = 0xe5, - - /** - * @SCAN_OFFLOAD_PROFILES_QUERY_CMD: - * No command data, response is &struct iwl_scan_offload_profiles_query - */ - SCAN_OFFLOAD_PROFILES_QUERY_CMD = 0x56, -}; - -/* Please keep this enum *SORTED* by hex value. - * Needed for binary search, otherwise a warning will be triggered. - */ -enum iwl_mac_conf_subcmd_ids { - LINK_QUALITY_MEASUREMENT_CMD = 0x1, - LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE, - CHANNEL_SWITCH_NOA_NOTIF = 0xFF, -}; - -/** - * enum iwl_phy_ops_subcmd_ids - PHY group commands - */ -enum iwl_phy_ops_subcmd_ids { - /** - * @CMD_DTS_MEASUREMENT_TRIGGER_WIDE: - * Uses either &struct iwl_dts_measurement_cmd or - * &struct iwl_ext_dts_measurement_cmd - */ - CMD_DTS_MEASUREMENT_TRIGGER_WIDE = 0x0, - - /** - * @CTDP_CONFIG_CMD: &struct iwl_mvm_ctdp_cmd - */ - CTDP_CONFIG_CMD = 0x03, - - /** - * @TEMP_REPORTING_THRESHOLDS_CMD: &struct temp_report_ths_cmd - */ - TEMP_REPORTING_THRESHOLDS_CMD = 0x04, - - /** - * @GEO_TX_POWER_LIMIT: &struct iwl_geo_tx_power_profiles_cmd - */ - GEO_TX_POWER_LIMIT = 0x05, - - /** - * @CT_KILL_NOTIFICATION: &struct ct_kill_notif - */ - CT_KILL_NOTIFICATION = 0xFE, - - /** - * @DTS_MEASUREMENT_NOTIF_WIDE: - * &struct iwl_dts_measurement_notif_v1 or - * &struct iwl_dts_measurement_notif_v2 - */ - DTS_MEASUREMENT_NOTIF_WIDE = 0xFF, -}; - -/** - * enum iwl_system_subcmd_ids - system group command IDs - */ -enum iwl_system_subcmd_ids { - /** - * @SHARED_MEM_CFG_CMD: - * response in &struct iwl_shared_mem_cfg or - * &struct iwl_shared_mem_cfg_v2 - */ - SHARED_MEM_CFG_CMD = 0x0, - - /** - * @INIT_EXTENDED_CFG_CMD: &struct iwl_init_extended_cfg_cmd - */ - INIT_EXTENDED_CFG_CMD = 0x03, -}; - -/** - * enum iwl_data_path_subcmd_ids - data path group commands - */ -enum iwl_data_path_subcmd_ids { - /** - * @DQA_ENABLE_CMD: &struct iwl_dqa_enable_cmd - */ - DQA_ENABLE_CMD = 0x0, - - /** - * @UPDATE_MU_GROUPS_CMD: &struct iwl_mu_group_mgmt_cmd - */ - UPDATE_MU_GROUPS_CMD = 0x1, - - /** - * @TRIGGER_RX_QUEUES_NOTIF_CMD: &struct iwl_rxq_sync_cmd - */ - TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2, - - /** - * @STA_PM_NOTIF: &struct iwl_mvm_pm_state_notification - */ - STA_PM_NOTIF = 0xFD, - - /** - * @MU_GROUP_MGMT_NOTIF: &struct iwl_mu_group_mgmt_notif - */ - MU_GROUP_MGMT_NOTIF = 0xFE, - - /** - * @RX_QUEUES_NOTIFICATION: &struct iwl_rxq_sync_notification - */ - RX_QUEUES_NOTIFICATION = 0xFF, -}; - -/** - * enum iwl_prot_offload_subcmd_ids - protocol offload commands - */ -enum iwl_prot_offload_subcmd_ids { - /** - * @STORED_BEACON_NTF: &struct iwl_stored_beacon_notif - */ - STORED_BEACON_NTF = 0xFF, -}; - -/** - * enum iwl_regulatory_and_nvm_subcmd_ids - regulatory/NVM commands - */ -enum iwl_regulatory_and_nvm_subcmd_ids { - /** - * @NVM_ACCESS_COMPLETE: &struct iwl_nvm_access_complete_cmd - */ - NVM_ACCESS_COMPLETE = 0x0, - - /** - * @NVM_GET_INFO: - * Command is &struct iwl_nvm_get_info, - * response is &struct iwl_nvm_get_info_rsp - */ - NVM_GET_INFO = 0x2, -}; - -/** - * enum iwl_debug_cmds - debug commands - */ -enum iwl_debug_cmds { - /** - * @LMAC_RD_WR: - * LMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and - * &struct iwl_dbg_mem_access_rsp - */ - LMAC_RD_WR = 0x0, - /** - * @UMAC_RD_WR: - * UMAC memory read/write, using &struct iwl_dbg_mem_access_cmd and - * &struct iwl_dbg_mem_access_rsp - */ - UMAC_RD_WR = 0x1, - /** - * @MFU_ASSERT_DUMP_NTF: - * &struct iwl_mfu_assert_dump_notif - */ - MFU_ASSERT_DUMP_NTF = 0xFE, -}; - -/** - * enum iwl_mvm_command_groups - command groups for the firmware - * @LEGACY_GROUP: legacy group, uses command IDs from &enum iwl_legacy_cmds - * @LONG_GROUP: legacy group with long header, also uses command IDs - * from &enum iwl_legacy_cmds - * @SYSTEM_GROUP: system group, uses command IDs from - * &enum iwl_system_subcmd_ids - * @MAC_CONF_GROUP: MAC configuration group, uses command IDs from - * &enum iwl_mac_conf_subcmd_ids - * @PHY_OPS_GROUP: PHY operations group, uses command IDs from - * &enum iwl_phy_ops_subcmd_ids - * @DATA_PATH_GROUP: data path group, uses command IDs from - * &enum iwl_data_path_subcmd_ids - * @NAN_GROUP: NAN group, uses command IDs from &enum iwl_nan_subcmd_ids - * @TOF_GROUP: TOF group, uses command IDs from &enum iwl_tof_subcmd_ids - * @PROT_OFFLOAD_GROUP: protocol offload group, uses command IDs from - * &enum iwl_prot_offload_subcmd_ids - * @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from - * &enum iwl_regulatory_and_nvm_subcmd_ids - * @DEBUG_GROUP: Debug group, uses command IDs from &enum iwl_debug_cmds - */ -enum iwl_mvm_command_groups { - LEGACY_GROUP = 0x0, - LONG_GROUP = 0x1, - SYSTEM_GROUP = 0x2, - MAC_CONF_GROUP = 0x3, - PHY_OPS_GROUP = 0x4, - DATA_PATH_GROUP = 0x5, - PROT_OFFLOAD_GROUP = 0xb, - REGULATORY_AND_NVM_GROUP = 0xc, - DEBUG_GROUP = 0xf, -}; - -/** - * struct iwl_cmd_response - generic response struct for most commands - * @status: status of the command asked, changes for each one - */ -struct iwl_cmd_response { - __le32 status; -}; - -/* - * struct iwl_dqa_enable_cmd - * @cmd_queue: the TXQ number of the command queue - */ -struct iwl_dqa_enable_cmd { - __le32 cmd_queue; -} __packed; /* DQA_CONTROL_CMD_API_S_VER_1 */ - -/* - * struct iwl_tx_ant_cfg_cmd - * @valid: valid antenna configuration - */ -struct iwl_tx_ant_cfg_cmd { - __le32 valid; -} __packed; - -/** - * struct iwl_calib_ctrl - Calibration control struct. - * Sent as part of the phy configuration command. - * @flow_trigger: bitmap for which calibrations to perform according to - * flow triggers, using &enum iwl_calib_cfg - * @event_trigger: bitmap for which calibrations to perform according to - * event triggers, using &enum iwl_calib_cfg - */ -struct iwl_calib_ctrl { - __le32 flow_trigger; - __le32 event_trigger; -} __packed; - -/* This enum defines the bitmap of various calibrations to enable in both - * init ucode and runtime ucode through CALIBRATION_CFG_CMD. - */ -enum iwl_calib_cfg { - IWL_CALIB_CFG_XTAL_IDX = BIT(0), - IWL_CALIB_CFG_TEMPERATURE_IDX = BIT(1), - IWL_CALIB_CFG_VOLTAGE_READ_IDX = BIT(2), - IWL_CALIB_CFG_PAPD_IDX = BIT(3), - IWL_CALIB_CFG_TX_PWR_IDX = BIT(4), - IWL_CALIB_CFG_DC_IDX = BIT(5), - IWL_CALIB_CFG_BB_FILTER_IDX = BIT(6), - IWL_CALIB_CFG_LO_LEAKAGE_IDX = BIT(7), - IWL_CALIB_CFG_TX_IQ_IDX = BIT(8), - IWL_CALIB_CFG_TX_IQ_SKEW_IDX = BIT(9), - IWL_CALIB_CFG_RX_IQ_IDX = BIT(10), - IWL_CALIB_CFG_RX_IQ_SKEW_IDX = BIT(11), - IWL_CALIB_CFG_SENSITIVITY_IDX = BIT(12), - IWL_CALIB_CFG_CHAIN_NOISE_IDX = BIT(13), - IWL_CALIB_CFG_DISCONNECTED_ANT_IDX = BIT(14), - IWL_CALIB_CFG_ANT_COUPLING_IDX = BIT(15), - IWL_CALIB_CFG_DAC_IDX = BIT(16), - IWL_CALIB_CFG_ABS_IDX = BIT(17), - IWL_CALIB_CFG_AGC_IDX = BIT(18), -}; - -/** - * struct iwl_phy_cfg_cmd - Phy configuration command - * @phy_cfg: PHY configuration value, uses &enum iwl_fw_phy_cfg - * @calib_control: calibration control data - */ -struct iwl_phy_cfg_cmd { - __le32 phy_cfg; - struct iwl_calib_ctrl calib_control; -} __packed; - -#define PHY_CFG_RADIO_TYPE (BIT(0) | BIT(1)) -#define PHY_CFG_RADIO_STEP (BIT(2) | BIT(3)) -#define PHY_CFG_RADIO_DASH (BIT(4) | BIT(5)) -#define PHY_CFG_PRODUCT_NUMBER (BIT(6) | BIT(7)) -#define PHY_CFG_TX_CHAIN_A BIT(8) -#define PHY_CFG_TX_CHAIN_B BIT(9) -#define PHY_CFG_TX_CHAIN_C BIT(10) -#define PHY_CFG_RX_CHAIN_A BIT(12) -#define PHY_CFG_RX_CHAIN_B BIT(13) -#define PHY_CFG_RX_CHAIN_C BIT(14) - - -/** - * enum iwl_nvm_access_op - NVM access opcode - * @IWL_NVM_READ: read NVM - * @IWL_NVM_WRITE: write NVM - */ -enum iwl_nvm_access_op { - IWL_NVM_READ = 0, - IWL_NVM_WRITE = 1, -}; - -/** - * enum iwl_nvm_access_target - target of the NVM_ACCESS_CMD - * @NVM_ACCESS_TARGET_CACHE: access the cache - * @NVM_ACCESS_TARGET_OTP: access the OTP - * @NVM_ACCESS_TARGET_EEPROM: access the EEPROM - */ -enum iwl_nvm_access_target { - NVM_ACCESS_TARGET_CACHE = 0, - NVM_ACCESS_TARGET_OTP = 1, - NVM_ACCESS_TARGET_EEPROM = 2, -}; - -/** - * enum iwl_nvm_section_type - section types for NVM_ACCESS_CMD - * @NVM_SECTION_TYPE_SW: software section - * @NVM_SECTION_TYPE_REGULATORY: regulatory section - * @NVM_SECTION_TYPE_CALIBRATION: calibration section - * @NVM_SECTION_TYPE_PRODUCTION: production section - * @NVM_SECTION_TYPE_MAC_OVERRIDE: MAC override section - * @NVM_SECTION_TYPE_PHY_SKU: PHY SKU section - * @NVM_MAX_NUM_SECTIONS: number of sections - */ -enum iwl_nvm_section_type { - NVM_SECTION_TYPE_SW = 1, - NVM_SECTION_TYPE_REGULATORY = 3, - NVM_SECTION_TYPE_CALIBRATION = 4, - NVM_SECTION_TYPE_PRODUCTION = 5, - NVM_SECTION_TYPE_MAC_OVERRIDE = 11, - NVM_SECTION_TYPE_PHY_SKU = 12, - NVM_MAX_NUM_SECTIONS = 13, -}; - -/** - * struct iwl_nvm_access_cmd - Request the device to send an NVM section - * @op_code: &enum iwl_nvm_access_op - * @target: &enum iwl_nvm_access_target - * @type: &enum iwl_nvm_section_type - * @offset: offset in bytes into the section - * @length: in bytes, to read/write - * @data: if write operation, the data to write. On read its empty - */ -struct iwl_nvm_access_cmd { - u8 op_code; - u8 target; - __le16 type; - __le16 offset; - __le16 length; - u8 data[]; -} __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ - -#define NUM_OF_FW_PAGING_BLOCKS 33 /* 32 for data and 1 block for CSS */ - -/** - * struct iwl_fw_paging_cmd - paging layout - * - * (FW_PAGING_BLOCK_CMD = 0x4f) - * - * Send to FW the paging layout in the driver. - * - * @flags: various flags for the command - * @block_size: the block size in powers of 2 - * @block_num: number of blocks specified in the command. - * @device_phy_addr: virtual addresses from device side - */ -struct iwl_fw_paging_cmd { - __le32 flags; - __le32 block_size; - __le32 block_num; - __le32 device_phy_addr[NUM_OF_FW_PAGING_BLOCKS]; -} __packed; /* FW_PAGING_BLOCK_CMD_API_S_VER_1 */ - -/* - * Fw items ID's - * - * @IWL_FW_ITEM_ID_PAGING: Address of the pages that the FW will upload - * download - */ -enum iwl_fw_item_id { - IWL_FW_ITEM_ID_PAGING = 3, -}; - -/* - * struct iwl_fw_get_item_cmd - get an item from the fw - */ -struct iwl_fw_get_item_cmd { - __le32 item_id; -} __packed; /* FW_GET_ITEM_CMD_API_S_VER_1 */ - -#define CONT_REC_COMMAND_SIZE 80 -#define ENABLE_CONT_RECORDING 0x15 -#define DISABLE_CONT_RECORDING 0x16 - -/* - * struct iwl_continuous_record_mode - recording mode - */ -struct iwl_continuous_record_mode { - __le16 enable_recording; -} __packed; - -/* - * struct iwl_continuous_record_cmd - enable/disable continuous recording - */ -struct iwl_continuous_record_cmd { - struct iwl_continuous_record_mode record_mode; - u8 pad[CONT_REC_COMMAND_SIZE - - sizeof(struct iwl_continuous_record_mode)]; -} __packed; - -struct iwl_fw_get_item_resp { - __le32 item_id; - __le32 item_byte_cnt; - __le32 item_val; -} __packed; /* FW_GET_ITEM_RSP_S_VER_1 */ - -/** - * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD - * @offset: offset in bytes into the section - * @length: in bytes, either how much was written or read - * @type: NVM_SECTION_TYPE_* - * @status: 0 for success, fail otherwise - * @data: if read operation, the data returned. Empty on write. - */ -struct iwl_nvm_access_resp { - __le16 offset; - __le16 length; - __le16 type; - __le16 status; - u8 data[]; -} __packed; /* NVM_ACCESS_CMD_RESP_API_S_VER_2 */ - -/* MVM_ALIVE 0x1 */ - -/* alive response is_valid values */ -#define ALIVE_RESP_UCODE_OK BIT(0) -#define ALIVE_RESP_RFKILL BIT(1) - -/* alive response ver_type values */ -enum { - FW_TYPE_HW = 0, - FW_TYPE_PROT = 1, - FW_TYPE_AP = 2, - FW_TYPE_WOWLAN = 3, - FW_TYPE_TIMING = 4, - FW_TYPE_WIPAN = 5 -}; - -/* alive response ver_subtype values */ -enum { - FW_SUBTYPE_FULL_FEATURE = 0, - FW_SUBTYPE_BOOTSRAP = 1, /* Not valid */ - FW_SUBTYPE_REDUCED = 2, - FW_SUBTYPE_ALIVE_ONLY = 3, - FW_SUBTYPE_WOWLAN = 4, - FW_SUBTYPE_AP_SUBTYPE = 5, - FW_SUBTYPE_WIPAN = 6, - FW_SUBTYPE_INITIALIZE = 9 -}; - -#define IWL_ALIVE_STATUS_ERR 0xDEAD -#define IWL_ALIVE_STATUS_OK 0xCAFE - -#define IWL_ALIVE_FLG_RFKILL BIT(0) - -struct iwl_lmac_alive { - __le32 ucode_minor; - __le32 ucode_major; - u8 ver_subtype; - u8 ver_type; - u8 mac; - u8 opt; - __le32 timestamp; - __le32 error_event_table_ptr; /* SRAM address for error log */ - __le32 log_event_table_ptr; /* SRAM address for LMAC event log */ - __le32 cpu_register_ptr; - __le32 dbgm_config_ptr; - __le32 alive_counter_ptr; - __le32 scd_base_ptr; /* SRAM address for SCD */ - __le32 st_fwrd_addr; /* pointer to Store and forward */ - __le32 st_fwrd_size; -} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_3 */ - -struct iwl_umac_alive { - __le32 umac_minor; /* UMAC version: minor */ - __le32 umac_major; /* UMAC version: major */ - __le32 error_info_addr; /* SRAM address for UMAC error log */ - __le32 dbg_print_buff_addr; -} __packed; /* UMAC_ALIVE_DATA_API_S_VER_2 */ - -struct mvm_alive_resp_v3 { - __le16 status; - __le16 flags; - struct iwl_lmac_alive lmac_data; - struct iwl_umac_alive umac_data; -} __packed; /* ALIVE_RES_API_S_VER_3 */ - -struct mvm_alive_resp { - __le16 status; - __le16 flags; - struct iwl_lmac_alive lmac_data[2]; - struct iwl_umac_alive umac_data; -} __packed; /* ALIVE_RES_API_S_VER_4 */ - -/* Error response/notification */ -enum { - FW_ERR_UNKNOWN_CMD = 0x0, - FW_ERR_INVALID_CMD_PARAM = 0x1, - FW_ERR_SERVICE = 0x2, - FW_ERR_ARC_MEMORY = 0x3, - FW_ERR_ARC_CODE = 0x4, - FW_ERR_WATCH_DOG = 0x5, - FW_ERR_WEP_GRP_KEY_INDX = 0x10, - FW_ERR_WEP_KEY_SIZE = 0x11, - FW_ERR_OBSOLETE_FUNC = 0x12, - FW_ERR_UNEXPECTED = 0xFE, - FW_ERR_FATAL = 0xFF -}; - -/** - * struct iwl_error_resp - FW error indication - * ( REPLY_ERROR = 0x2 ) - * @error_type: one of FW_ERR_* - * @cmd_id: the command ID for which the error occured - * @reserved1: reserved - * @bad_cmd_seq_num: sequence number of the erroneous command - * @error_service: which service created the error, applicable only if - * error_type = 2, otherwise 0 - * @timestamp: TSF in usecs. - */ -struct iwl_error_resp { - __le32 error_type; - u8 cmd_id; - u8 reserved1; - __le16 bad_cmd_seq_num; - __le32 error_service; - __le64 timestamp; -} __packed; - - -/* Common PHY, MAC and Bindings definitions */ -#define MAX_MACS_IN_BINDING (3) -#define MAX_BINDINGS (4) - -/** - * enum iwl_mvm_id_and_color - ID and color fields in context dword - * @FW_CTXT_ID_POS: position of the ID - * @FW_CTXT_ID_MSK: mask of the ID - * @FW_CTXT_COLOR_POS: position of the color - * @FW_CTXT_COLOR_MSK: mask of the color - * @FW_CTXT_INVALID: value used to indicate unused/invalid - */ -enum iwl_mvm_id_and_color { - FW_CTXT_ID_POS = 0, - FW_CTXT_ID_MSK = 0xff << FW_CTXT_ID_POS, - FW_CTXT_COLOR_POS = 8, - FW_CTXT_COLOR_MSK = 0xff << FW_CTXT_COLOR_POS, - FW_CTXT_INVALID = 0xffffffff, -}; - -#define FW_CMD_ID_AND_COLOR(_id, _color) ((_id << FW_CTXT_ID_POS) |\ - (_color << FW_CTXT_COLOR_POS)) - -/* Possible actions on PHYs, MACs and Bindings */ -enum iwl_phy_ctxt_action { - FW_CTXT_ACTION_STUB = 0, - FW_CTXT_ACTION_ADD, - FW_CTXT_ACTION_MODIFY, - FW_CTXT_ACTION_REMOVE, - FW_CTXT_ACTION_NUM -}; /* COMMON_CONTEXT_ACTION_API_E_VER_1 */ - -/* Time Events */ - -/* Time Event types, according to MAC type */ -enum iwl_time_event_type { - /* BSS Station Events */ - TE_BSS_STA_AGGRESSIVE_ASSOC, - TE_BSS_STA_ASSOC, - TE_BSS_EAP_DHCP_PROT, - TE_BSS_QUIET_PERIOD, - - /* P2P Device Events */ - TE_P2P_DEVICE_DISCOVERABLE, - TE_P2P_DEVICE_LISTEN, - TE_P2P_DEVICE_ACTION_SCAN, - TE_P2P_DEVICE_FULL_SCAN, - - /* P2P Client Events */ - TE_P2P_CLIENT_AGGRESSIVE_ASSOC, - TE_P2P_CLIENT_ASSOC, - TE_P2P_CLIENT_QUIET_PERIOD, - - /* P2P GO Events */ - TE_P2P_GO_ASSOC_PROT, - TE_P2P_GO_REPETITIVET_NOA, - TE_P2P_GO_CT_WINDOW, - - /* WiDi Sync Events */ - TE_WIDI_TX_SYNC, - - /* Channel Switch NoA */ - TE_CHANNEL_SWITCH_PERIOD, - - TE_MAX -}; /* MAC_EVENT_TYPE_API_E_VER_1 */ - - - -/* Time event - defines for command API v1 */ - -/* - * @TE_V1_FRAG_NONE: fragmentation of the time event is NOT allowed. - * @TE_V1_FRAG_SINGLE: fragmentation of the time event is allowed, but only - * the first fragment is scheduled. - * @TE_V1_FRAG_DUAL: fragmentation of the time event is allowed, but only - * the first 2 fragments are scheduled. - * @TE_V1_FRAG_ENDLESS: fragmentation of the time event is allowed, and any - * number of fragments are valid. - * - * Other than the constant defined above, specifying a fragmentation value 'x' - * means that the event can be fragmented but only the first 'x' will be - * scheduled. - */ -enum { - TE_V1_FRAG_NONE = 0, - TE_V1_FRAG_SINGLE = 1, - TE_V1_FRAG_DUAL = 2, - TE_V1_FRAG_ENDLESS = 0xffffffff -}; - -/* If a Time Event can be fragmented, this is the max number of fragments */ -#define TE_V1_FRAG_MAX_MSK 0x0fffffff -/* Repeat the time event endlessly (until removed) */ -#define TE_V1_REPEAT_ENDLESS 0xffffffff -/* If a Time Event has bounded repetitions, this is the maximal value */ -#define TE_V1_REPEAT_MAX_MSK_V1 0x0fffffff - -/* Time Event dependencies: none, on another TE, or in a specific time */ -enum { - TE_V1_INDEPENDENT = 0, - TE_V1_DEP_OTHER = BIT(0), - TE_V1_DEP_TSF = BIT(1), - TE_V1_EVENT_SOCIOPATHIC = BIT(2), -}; /* MAC_EVENT_DEPENDENCY_POLICY_API_E_VER_2 */ - -/* - * @TE_V1_NOTIF_NONE: no notifications - * @TE_V1_NOTIF_HOST_EVENT_START: request/receive notification on event start - * @TE_V1_NOTIF_HOST_EVENT_END:request/receive notification on event end - * @TE_V1_NOTIF_INTERNAL_EVENT_START: internal FW use - * @TE_V1_NOTIF_INTERNAL_EVENT_END: internal FW use. - * @TE_V1_NOTIF_HOST_FRAG_START: request/receive notification on frag start - * @TE_V1_NOTIF_HOST_FRAG_END:request/receive notification on frag end - * @TE_V1_NOTIF_INTERNAL_FRAG_START: internal FW use. - * @TE_V1_NOTIF_INTERNAL_FRAG_END: internal FW use. - * - * Supported Time event notifications configuration. - * A notification (both event and fragment) includes a status indicating weather - * the FW was able to schedule the event or not. For fragment start/end - * notification the status is always success. There is no start/end fragment - * notification for monolithic events. - */ -enum { - TE_V1_NOTIF_NONE = 0, - TE_V1_NOTIF_HOST_EVENT_START = BIT(0), - TE_V1_NOTIF_HOST_EVENT_END = BIT(1), - TE_V1_NOTIF_INTERNAL_EVENT_START = BIT(2), - TE_V1_NOTIF_INTERNAL_EVENT_END = BIT(3), - TE_V1_NOTIF_HOST_FRAG_START = BIT(4), - TE_V1_NOTIF_HOST_FRAG_END = BIT(5), - TE_V1_NOTIF_INTERNAL_FRAG_START = BIT(6), - TE_V1_NOTIF_INTERNAL_FRAG_END = BIT(7), -}; /* MAC_EVENT_ACTION_API_E_VER_2 */ - -/* Time event - defines for command API */ - -/* - * @TE_V2_FRAG_NONE: fragmentation of the time event is NOT allowed. - * @TE_V2_FRAG_SINGLE: fragmentation of the time event is allowed, but only - * the first fragment is scheduled. - * @TE_V2_FRAG_DUAL: fragmentation of the time event is allowed, but only - * the first 2 fragments are scheduled. - * @TE_V2_FRAG_ENDLESS: fragmentation of the time event is allowed, and any - * number of fragments are valid. - * - * Other than the constant defined above, specifying a fragmentation value 'x' - * means that the event can be fragmented but only the first 'x' will be - * scheduled. - */ -enum { - TE_V2_FRAG_NONE = 0, - TE_V2_FRAG_SINGLE = 1, - TE_V2_FRAG_DUAL = 2, - TE_V2_FRAG_MAX = 0xfe, - TE_V2_FRAG_ENDLESS = 0xff -}; - -/* Repeat the time event endlessly (until removed) */ -#define TE_V2_REPEAT_ENDLESS 0xff -/* If a Time Event has bounded repetitions, this is the maximal value */ -#define TE_V2_REPEAT_MAX 0xfe - -#define TE_V2_PLACEMENT_POS 12 -#define TE_V2_ABSENCE_POS 15 - -/** - * enum iwl_time_event_policy - Time event policy values - * A notification (both event and fragment) includes a status indicating weather - * the FW was able to schedule the event or not. For fragment start/end - * notification the status is always success. There is no start/end fragment - * notification for monolithic events. - * - * @TE_V2_DEFAULT_POLICY: independent, social, present, unoticable - * @TE_V2_NOTIF_HOST_EVENT_START: request/receive notification on event start - * @TE_V2_NOTIF_HOST_EVENT_END:request/receive notification on event end - * @TE_V2_NOTIF_INTERNAL_EVENT_START: internal FW use - * @TE_V2_NOTIF_INTERNAL_EVENT_END: internal FW use. - * @TE_V2_NOTIF_HOST_FRAG_START: request/receive notification on frag start - * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end - * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use. - * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use. - * @T2_V2_START_IMMEDIATELY: start time event immediately - * @TE_V2_DEP_OTHER: depends on another time event - * @TE_V2_DEP_TSF: depends on a specific time - * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC - * @TE_V2_ABSENCE: are we present or absent during the Time Event. - */ -enum iwl_time_event_policy { - TE_V2_DEFAULT_POLICY = 0x0, - - /* notifications (event start/stop, fragment start/stop) */ - TE_V2_NOTIF_HOST_EVENT_START = BIT(0), - TE_V2_NOTIF_HOST_EVENT_END = BIT(1), - TE_V2_NOTIF_INTERNAL_EVENT_START = BIT(2), - TE_V2_NOTIF_INTERNAL_EVENT_END = BIT(3), - - TE_V2_NOTIF_HOST_FRAG_START = BIT(4), - TE_V2_NOTIF_HOST_FRAG_END = BIT(5), - TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6), - TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7), - T2_V2_START_IMMEDIATELY = BIT(11), - - /* placement characteristics */ - TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS), - TE_V2_DEP_TSF = BIT(TE_V2_PLACEMENT_POS + 1), - TE_V2_EVENT_SOCIOPATHIC = BIT(TE_V2_PLACEMENT_POS + 2), - - /* are we present or absent during the Time Event. */ - TE_V2_ABSENCE = BIT(TE_V2_ABSENCE_POS), -}; - -/** - * struct iwl_time_event_cmd - configuring Time Events - * with struct MAC_TIME_EVENT_DATA_API_S_VER_2 (see also - * with version 1. determined by IWL_UCODE_TLV_FLAGS) - * ( TIME_EVENT_CMD = 0x29 ) - * @id_and_color: ID and color of the relevant MAC, - * &enum iwl_mvm_id_and_color - * @action: action to perform, one of &enum iwl_phy_ctxt_action - * @id: this field has two meanings, depending on the action: - * If the action is ADD, then it means the type of event to add. - * For all other actions it is the unique event ID assigned when the - * event was added by the FW. - * @apply_time: When to start the Time Event (in GP2) - * @max_delay: maximum delay to event's start (apply time), in TU - * @depends_on: the unique ID of the event we depend on (if any) - * @interval: interval between repetitions, in TU - * @duration: duration of event in TU - * @repeat: how many repetitions to do, can be TE_REPEAT_ENDLESS - * @max_frags: maximal number of fragments the Time Event can be divided to - * @policy: defines whether uCode shall notify the host or other uCode modules - * on event and/or fragment start and/or end - * using one of TE_INDEPENDENT, TE_DEP_OTHER, TE_DEP_TSF - * TE_EVENT_SOCIOPATHIC - * using TE_ABSENCE and using TE_NOTIF_*, - * &enum iwl_time_event_policy - */ -struct iwl_time_event_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - __le32 id; - /* MAC_TIME_EVENT_DATA_API_S_VER_2 */ - __le32 apply_time; - __le32 max_delay; - __le32 depends_on; - __le32 interval; - __le32 duration; - u8 repeat; - u8 max_frags; - __le16 policy; -} __packed; /* MAC_TIME_EVENT_CMD_API_S_VER_2 */ - -/** - * struct iwl_time_event_resp - response structure to iwl_time_event_cmd - * @status: bit 0 indicates success, all others specify errors - * @id: the Time Event type - * @unique_id: the unique ID assigned (in ADD) or given (others) to the TE - * @id_and_color: ID and color of the relevant MAC, - * &enum iwl_mvm_id_and_color - */ -struct iwl_time_event_resp { - __le32 status; - __le32 id; - __le32 unique_id; - __le32 id_and_color; -} __packed; /* MAC_TIME_EVENT_RSP_API_S_VER_1 */ - -/** - * struct iwl_time_event_notif - notifications of time event start/stop - * ( TIME_EVENT_NOTIFICATION = 0x2a ) - * @timestamp: action timestamp in GP2 - * @session_id: session's unique id - * @unique_id: unique id of the Time Event itself - * @id_and_color: ID and color of the relevant MAC - * @action: &enum iwl_time_event_policy - * @status: true if scheduled, false otherwise (not executed) - */ -struct iwl_time_event_notif { - __le32 timestamp; - __le32 session_id; - __le32 unique_id; - __le32 id_and_color; - __le32 action; - __le32 status; -} __packed; /* MAC_TIME_EVENT_NTFY_API_S_VER_1 */ - - -/* Bindings and Time Quota */ - -/** - * struct iwl_binding_cmd_v1 - configuring bindings - * ( BINDING_CONTEXT_CMD = 0x2b ) - * @id_and_color: ID and color of the relevant Binding, - * &enum iwl_mvm_id_and_color - * @action: action to perform, one of FW_CTXT_ACTION_* - * @macs: array of MAC id and colors which belong to the binding, - * &enum iwl_mvm_id_and_color - * @phy: PHY id and color which belongs to the binding, - * &enum iwl_mvm_id_and_color - */ -struct iwl_binding_cmd_v1 { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - /* BINDING_DATA_API_S_VER_1 */ - __le32 macs[MAX_MACS_IN_BINDING]; - __le32 phy; -} __packed; /* BINDING_CMD_API_S_VER_1 */ - -/** - * struct iwl_binding_cmd - configuring bindings - * ( BINDING_CONTEXT_CMD = 0x2b ) - * @id_and_color: ID and color of the relevant Binding, - * &enum iwl_mvm_id_and_color - * @action: action to perform, one of FW_CTXT_ACTION_* - * @macs: array of MAC id and colors which belong to the binding - * &enum iwl_mvm_id_and_color - * @phy: PHY id and color which belongs to the binding - * &enum iwl_mvm_id_and_color - * @lmac_id: the lmac id the binding belongs to - */ -struct iwl_binding_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - /* BINDING_DATA_API_S_VER_1 */ - __le32 macs[MAX_MACS_IN_BINDING]; - __le32 phy; - __le32 lmac_id; -} __packed; /* BINDING_CMD_API_S_VER_2 */ - -#define IWL_BINDING_CMD_SIZE_V1 sizeof(struct iwl_binding_cmd_v1) -#define IWL_LMAC_24G_INDEX 0 -#define IWL_LMAC_5G_INDEX 1 - -/* The maximal number of fragments in the FW's schedule session */ -#define IWL_MVM_MAX_QUOTA 128 - -/** - * struct iwl_time_quota_data - configuration of time quota per binding - * @id_and_color: ID and color of the relevant Binding, - * &enum iwl_mvm_id_and_color - * @quota: absolute time quota in TU. The scheduler will try to divide the - * remainig quota (after Time Events) according to this quota. - * @max_duration: max uninterrupted context duration in TU - */ -struct iwl_time_quota_data { - __le32 id_and_color; - __le32 quota; - __le32 max_duration; -} __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */ - -/** - * struct iwl_time_quota_cmd - configuration of time quota between bindings - * ( TIME_QUOTA_CMD = 0x2c ) - * @quotas: allocations per binding - * Note: on non-CDB the fourth one is the auxilary mac and is - * essentially zero. - * On CDB the fourth one is a regular binding. - */ -struct iwl_time_quota_cmd { - struct iwl_time_quota_data quotas[MAX_BINDINGS]; -} __packed; /* TIME_QUOTA_ALLOCATION_CMD_API_S_VER_1 */ - - -/* PHY context */ - -/* Supported bands */ -#define PHY_BAND_5 (0) -#define PHY_BAND_24 (1) - -/* Supported channel width, vary if there is VHT support */ -#define PHY_VHT_CHANNEL_MODE20 (0x0) -#define PHY_VHT_CHANNEL_MODE40 (0x1) -#define PHY_VHT_CHANNEL_MODE80 (0x2) -#define PHY_VHT_CHANNEL_MODE160 (0x3) - -/* - * Control channel position: - * For legacy set bit means upper channel, otherwise lower. - * For VHT - bit-2 marks if the control is lower/upper relative to center-freq - * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. - * center_freq - * | - * 40Mhz |_______|_______| - * 80Mhz |_______|_______|_______|_______| - * 160Mhz |_______|_______|_______|_______|_______|_______|_______|_______| - * code 011 010 001 000 | 100 101 110 111 - */ -#define PHY_VHT_CTRL_POS_1_BELOW (0x0) -#define PHY_VHT_CTRL_POS_2_BELOW (0x1) -#define PHY_VHT_CTRL_POS_3_BELOW (0x2) -#define PHY_VHT_CTRL_POS_4_BELOW (0x3) -#define PHY_VHT_CTRL_POS_1_ABOVE (0x4) -#define PHY_VHT_CTRL_POS_2_ABOVE (0x5) -#define PHY_VHT_CTRL_POS_3_ABOVE (0x6) -#define PHY_VHT_CTRL_POS_4_ABOVE (0x7) - -/* - * @band: PHY_BAND_* - * @channel: channel number - * @width: PHY_[VHT|LEGACY]_CHANNEL_* - * @ctrl channel: PHY_[VHT|LEGACY]_CTRL_* - */ -struct iwl_fw_channel_info { - u8 band; - u8 channel; - u8 width; - u8 ctrl_pos; -} __packed; - -#define PHY_RX_CHAIN_DRIVER_FORCE_POS (0) -#define PHY_RX_CHAIN_DRIVER_FORCE_MSK \ - (0x1 << PHY_RX_CHAIN_DRIVER_FORCE_POS) -#define PHY_RX_CHAIN_VALID_POS (1) -#define PHY_RX_CHAIN_VALID_MSK \ - (0x7 << PHY_RX_CHAIN_VALID_POS) -#define PHY_RX_CHAIN_FORCE_SEL_POS (4) -#define PHY_RX_CHAIN_FORCE_SEL_MSK \ - (0x7 << PHY_RX_CHAIN_FORCE_SEL_POS) -#define PHY_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define PHY_RX_CHAIN_FORCE_MIMO_SEL_MSK \ - (0x7 << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS) -#define PHY_RX_CHAIN_CNT_POS (10) -#define PHY_RX_CHAIN_CNT_MSK \ - (0x3 << PHY_RX_CHAIN_CNT_POS) -#define PHY_RX_CHAIN_MIMO_CNT_POS (12) -#define PHY_RX_CHAIN_MIMO_CNT_MSK \ - (0x3 << PHY_RX_CHAIN_MIMO_CNT_POS) -#define PHY_RX_CHAIN_MIMO_FORCE_POS (14) -#define PHY_RX_CHAIN_MIMO_FORCE_MSK \ - (0x1 << PHY_RX_CHAIN_MIMO_FORCE_POS) - -/* TODO: fix the value, make it depend on firmware at runtime? */ -#define NUM_PHY_CTX 3 - -/* TODO: complete missing documentation */ -/** - * struct iwl_phy_context_cmd - config of the PHY context - * ( PHY_CONTEXT_CMD = 0x8 ) - * @id_and_color: ID and color of the relevant Binding - * @action: action to perform, one of FW_CTXT_ACTION_* - * @apply_time: 0 means immediate apply and context switch. - * other value means apply new params after X usecs - * @tx_param_color: ??? - * @ci: channel info - * @txchain_info: ??? - * @rxchain_info: ??? - * @acquisition_data: ??? - * @dsp_cfg_flags: set to 0 - */ -struct iwl_phy_context_cmd { - /* COMMON_INDEX_HDR_API_S_VER_1 */ - __le32 id_and_color; - __le32 action; - /* PHY_CONTEXT_DATA_API_S_VER_1 */ - __le32 apply_time; - __le32 tx_param_color; - struct iwl_fw_channel_info ci; - __le32 txchain_info; - __le32 rxchain_info; - __le32 acquisition_data; - __le32 dsp_cfg_flags; -} __packed; /* PHY_CONTEXT_CMD_API_VER_1 */ - -/* - * Aux ROC command - * - * Command requests the firmware to create a time event for a certain duration - * and remain on the given channel. This is done by using the Aux framework in - * the FW. - * The command was first used for Hot Spot issues - but can be used regardless - * to Hot Spot. - * - * ( HOT_SPOT_CMD 0x53 ) - * - * @id_and_color: ID and color of the MAC - * @action: action to perform, one of FW_CTXT_ACTION_* - * @event_unique_id: If the action FW_CTXT_ACTION_REMOVE then the - * event_unique_id should be the id of the time event assigned by ucode. - * Otherwise ignore the event_unique_id. - * @sta_id_and_color: station id and color, resumed during "Remain On Channel" - * activity. - * @channel_info: channel info - * @node_addr: Our MAC Address - * @reserved: reserved for alignment - * @apply_time: GP2 value to start (should always be the current GP2 value) - * @apply_time_max_delay: Maximum apply time delay value in TU. Defines max - * time by which start of the event is allowed to be postponed. - * @duration: event duration in TU To calculate event duration: - * timeEventDuration = min(duration, remainingQuota) - */ -struct iwl_hs20_roc_req { - /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ - __le32 id_and_color; - __le32 action; - __le32 event_unique_id; - __le32 sta_id_and_color; - struct iwl_fw_channel_info channel_info; - u8 node_addr[ETH_ALEN]; - __le16 reserved; - __le32 apply_time; - __le32 apply_time_max_delay; - __le32 duration; -} __packed; /* HOT_SPOT_CMD_API_S_VER_1 */ - -/* - * values for AUX ROC result values - */ -enum iwl_mvm_hot_spot { - HOT_SPOT_RSP_STATUS_OK, - HOT_SPOT_RSP_STATUS_TOO_MANY_EVENTS, - HOT_SPOT_MAX_NUM_OF_SESSIONS, -}; - -/* - * Aux ROC command response - * - * In response to iwl_hs20_roc_req the FW sends this command to notify the - * driver the uid of the timevent. - * - * ( HOT_SPOT_CMD 0x53 ) - * - * @event_unique_id: Unique ID of time event assigned by ucode - * @status: Return status 0 is success, all the rest used for specific errors - */ -struct iwl_hs20_roc_res { - __le32 event_unique_id; - __le32 status; -} __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ - -/** - * struct iwl_radio_version_notif - information on the radio version - * ( RADIO_VERSION_NOTIFICATION = 0x68 ) - * @radio_flavor: radio flavor - * @radio_step: radio version step - * @radio_dash: radio version dash - */ -struct iwl_radio_version_notif { - __le32 radio_flavor; - __le32 radio_step; - __le32 radio_dash; -} __packed; /* RADIO_VERSION_NOTOFICATION_S_VER_1 */ - -enum iwl_card_state_flags { - CARD_ENABLED = 0x00, - HW_CARD_DISABLED = 0x01, - SW_CARD_DISABLED = 0x02, - CT_KILL_CARD_DISABLED = 0x04, - HALT_CARD_DISABLED = 0x08, - CARD_DISABLED_MSK = 0x0f, - CARD_IS_RX_ON = 0x10, -}; - -/** - * struct iwl_radio_version_notif - information on the radio version - * ( CARD_STATE_NOTIFICATION = 0xa1 ) - * @flags: %iwl_card_state_flags - */ -struct iwl_card_state_notif { - __le32 flags; -} __packed; /* CARD_STATE_NTFY_API_S_VER_1 */ - -/** - * struct iwl_missed_beacons_notif - information on missed beacons - * ( MISSED_BEACONS_NOTIFICATION = 0xa2 ) - * @mac_id: interface ID - * @consec_missed_beacons_since_last_rx: number of consecutive missed - * beacons since last RX. - * @consec_missed_beacons: number of consecutive missed beacons - * @num_expected_beacons: number of expected beacons - * @num_recvd_beacons: number of received beacons - */ -struct iwl_missed_beacons_notif { - __le32 mac_id; - __le32 consec_missed_beacons_since_last_rx; - __le32 consec_missed_beacons; - __le32 num_expected_beacons; - __le32 num_recvd_beacons; -} __packed; /* MISSED_BEACON_NTFY_API_S_VER_3 */ - -/** - * struct iwl_mfuart_load_notif - mfuart image version & status - * ( MFUART_LOAD_NOTIFICATION = 0xb1 ) - * @installed_ver: installed image version - * @external_ver: external image version - * @status: MFUART loading status - * @duration: MFUART loading time - * @image_size: MFUART image size in bytes -*/ -struct iwl_mfuart_load_notif { - __le32 installed_ver; - __le32 external_ver; - __le32 status; - __le32 duration; - /* image size valid only in v2 of the command */ - __le32 image_size; -} __packed; /*MFU_LOADER_NTFY_API_S_VER_2*/ - -/** - * struct iwl_mfu_assert_dump_notif - mfuart dump logs - * ( MFU_ASSERT_DUMP_NTF = 0xfe ) - * @assert_id: mfuart assert id that cause the notif - * @curr_reset_num: number of asserts since uptime - * @index_num: current chunk id - * @parts_num: total number of chunks - * @data_size: number of data bytes sent - * @data: data buffer - */ -struct iwl_mfu_assert_dump_notif { - __le32 assert_id; - __le32 curr_reset_num; - __le16 index_num; - __le16 parts_num; - __le32 data_size; - __le32 data[0]; -} __packed; /*MFU_DUMP_ASSERT_API_S_VER_1*/ - -#define MAX_PORT_ID_NUM 2 -#define MAX_MCAST_FILTERING_ADDRESSES 256 - -/** - * struct iwl_mcast_filter_cmd - configure multicast filter. - * @filter_own: Set 1 to filter out multicast packets sent by station itself - * @port_id: Multicast MAC addresses array specifier. This is a strange way - * to identify network interface adopted in host-device IF. - * It is used by FW as index in array of addresses. This array has - * MAX_PORT_ID_NUM members. - * @count: Number of MAC addresses in the array - * @pass_all: Set 1 to pass all multicast packets. - * @bssid: current association BSSID. - * @reserved: reserved - * @addr_list: Place holder for array of MAC addresses. - * IMPORTANT: add padding if necessary to ensure DWORD alignment. - */ -struct iwl_mcast_filter_cmd { - u8 filter_own; - u8 port_id; - u8 count; - u8 pass_all; - u8 bssid[6]; - u8 reserved[2]; - u8 addr_list[0]; -} __packed; /* MCAST_FILTERING_CMD_API_S_VER_1 */ - -#define MAX_BCAST_FILTERS 8 -#define MAX_BCAST_FILTER_ATTRS 2 - -/** - * enum iwl_mvm_bcast_filter_attr_offset - written by fw for each Rx packet - * @BCAST_FILTER_OFFSET_PAYLOAD_START: offset is from payload start. - * @BCAST_FILTER_OFFSET_IP_END: offset is from ip header end (i.e. - * start of ip payload). - */ -enum iwl_mvm_bcast_filter_attr_offset { - BCAST_FILTER_OFFSET_PAYLOAD_START = 0, - BCAST_FILTER_OFFSET_IP_END = 1, -}; - -/** - * struct iwl_fw_bcast_filter_attr - broadcast filter attribute - * @offset_type: &enum iwl_mvm_bcast_filter_attr_offset. - * @offset: starting offset of this pattern. - * @reserved1: reserved - * @val: value to match - big endian (MSB is the first - * byte to match from offset pos). - * @mask: mask to match (big endian). - */ -struct iwl_fw_bcast_filter_attr { - u8 offset_type; - u8 offset; - __le16 reserved1; - __be32 val; - __be32 mask; -} __packed; /* BCAST_FILTER_ATT_S_VER_1 */ - -/** - * enum iwl_mvm_bcast_filter_frame_type - filter frame type - * @BCAST_FILTER_FRAME_TYPE_ALL: consider all frames. - * @BCAST_FILTER_FRAME_TYPE_IPV4: consider only ipv4 frames - */ -enum iwl_mvm_bcast_filter_frame_type { - BCAST_FILTER_FRAME_TYPE_ALL = 0, - BCAST_FILTER_FRAME_TYPE_IPV4 = 1, -}; - -/** - * struct iwl_fw_bcast_filter - broadcast filter - * @discard: discard frame (1) or let it pass (0). - * @frame_type: &enum iwl_mvm_bcast_filter_frame_type. - * @reserved1: reserved - * @num_attrs: number of valid attributes in this filter. - * @attrs: attributes of this filter. a filter is considered matched - * only when all its attributes are matched (i.e. AND relationship) - */ -struct iwl_fw_bcast_filter { - u8 discard; - u8 frame_type; - u8 num_attrs; - u8 reserved1; - struct iwl_fw_bcast_filter_attr attrs[MAX_BCAST_FILTER_ATTRS]; -} __packed; /* BCAST_FILTER_S_VER_1 */ - -#define BA_WINDOW_STREAMS_MAX 16 -#define BA_WINDOW_STATUS_TID_MSK 0x000F -#define BA_WINDOW_STATUS_STA_ID_POS 4 -#define BA_WINDOW_STATUS_STA_ID_MSK 0x01F0 -#define BA_WINDOW_STATUS_VALID_MSK BIT(9) - -/** - * struct iwl_ba_window_status_notif - reordering window's status notification - * @bitmap: bitmap of received frames [start_seq_num + 0]..[start_seq_num + 63] - * @ra_tid: bit 3:0 - TID, bit 8:4 - STA_ID, bit 9 - valid - * @start_seq_num: the start sequence number of the bitmap - * @mpdu_rx_count: the number of received MPDUs since entering D0i3 - */ -struct iwl_ba_window_status_notif { - __le64 bitmap[BA_WINDOW_STREAMS_MAX]; - __le16 ra_tid[BA_WINDOW_STREAMS_MAX]; - __le32 start_seq_num[BA_WINDOW_STREAMS_MAX]; - __le16 mpdu_rx_count[BA_WINDOW_STREAMS_MAX]; -} __packed; /* BA_WINDOW_STATUS_NTFY_API_S_VER_1 */ - -/** - * struct iwl_fw_bcast_mac - per-mac broadcast filtering configuration. - * @default_discard: default action for this mac (discard (1) / pass (0)). - * @reserved1: reserved - * @attached_filters: bitmap of relevant filters for this mac. - */ -struct iwl_fw_bcast_mac { - u8 default_discard; - u8 reserved1; - __le16 attached_filters; -} __packed; /* BCAST_MAC_CONTEXT_S_VER_1 */ - -/** - * struct iwl_bcast_filter_cmd - broadcast filtering configuration - * @disable: enable (0) / disable (1) - * @max_bcast_filters: max number of filters (MAX_BCAST_FILTERS) - * @max_macs: max number of macs (NUM_MAC_INDEX_DRIVER) - * @reserved1: reserved - * @filters: broadcast filters - * @macs: broadcast filtering configuration per-mac - */ -struct iwl_bcast_filter_cmd { - u8 disable; - u8 max_bcast_filters; - u8 max_macs; - u8 reserved1; - struct iwl_fw_bcast_filter filters[MAX_BCAST_FILTERS]; - struct iwl_fw_bcast_mac macs[NUM_MAC_INDEX_DRIVER]; -} __packed; /* BCAST_FILTERING_HCMD_API_S_VER_1 */ - -/* - * enum iwl_mvm_marker_id - maker ids - * - * The ids for different type of markers to insert into the usniffer logs - */ -enum iwl_mvm_marker_id { - MARKER_ID_TX_FRAME_LATENCY = 1, -}; /* MARKER_ID_API_E_VER_1 */ - -/** - * struct iwl_mvm_marker - mark info into the usniffer logs - * - * (MARKER_CMD = 0xcb) - * - * Mark the UTC time stamp into the usniffer logs together with additional - * metadata, so the usniffer output can be parsed. - * In the command response the ucode will return the GP2 time. - * - * @dw_len: The amount of dwords following this byte including this byte. - * @marker_id: A unique marker id (iwl_mvm_marker_id). - * @reserved: reserved. - * @timestamp: in milliseconds since 1970-01-01 00:00:00 UTC - * @metadata: additional meta data that will be written to the unsiffer log - */ -struct iwl_mvm_marker { - u8 dw_len; - u8 marker_id; - __le16 reserved; - __le64 timestamp; - __le32 metadata[0]; -} __packed; /* MARKER_API_S_VER_1 */ - -/* - * enum iwl_dc2dc_config_id - flag ids - * - * Ids of dc2dc configuration flags - */ -enum iwl_dc2dc_config_id { - DCDC_LOW_POWER_MODE_MSK_SET = 0x1, /* not used */ - DCDC_FREQ_TUNE_SET = 0x2, -}; /* MARKER_ID_API_E_VER_1 */ - -/** - * struct iwl_dc2dc_config_cmd - configure dc2dc values - * - * (DC2DC_CONFIG_CMD = 0x83) - * - * Set/Get & configure dc2dc values. - * The command always returns the current dc2dc values. - * - * @flags: set/get dc2dc - * @enable_low_power_mode: not used. - * @dc2dc_freq_tune0: frequency divider - digital domain - * @dc2dc_freq_tune1: frequency divider - analog domain - */ -struct iwl_dc2dc_config_cmd { - __le32 flags; - __le32 enable_low_power_mode; /* not used */ - __le32 dc2dc_freq_tune0; - __le32 dc2dc_freq_tune1; -} __packed; /* DC2DC_CONFIG_CMD_API_S_VER_1 */ - -/** - * struct iwl_dc2dc_config_resp - response for iwl_dc2dc_config_cmd - * - * Current dc2dc values returned by the FW. - * - * @dc2dc_freq_tune0: frequency divider - digital domain - * @dc2dc_freq_tune1: frequency divider - analog domain - */ -struct iwl_dc2dc_config_resp { - __le32 dc2dc_freq_tune0; - __le32 dc2dc_freq_tune1; -} __packed; /* DC2DC_CONFIG_RESP_API_S_VER_1 */ - -/*********************************** - * Smart Fifo API - ***********************************/ -/* Smart Fifo state */ -enum iwl_sf_state { - SF_LONG_DELAY_ON = 0, /* should never be called by driver */ - SF_FULL_ON, - SF_UNINIT, - SF_INIT_OFF, - SF_HW_NUM_STATES -}; - -/* Smart Fifo possible scenario */ -enum iwl_sf_scenario { - SF_SCENARIO_SINGLE_UNICAST, - SF_SCENARIO_AGG_UNICAST, - SF_SCENARIO_MULTICAST, - SF_SCENARIO_BA_RESP, - SF_SCENARIO_TX_RESP, - SF_NUM_SCENARIO -}; - -#define SF_TRANSIENT_STATES_NUMBER 2 /* SF_LONG_DELAY_ON and SF_FULL_ON */ -#define SF_NUM_TIMEOUT_TYPES 2 /* Aging timer and Idle timer */ - -/* smart FIFO default values */ -#define SF_W_MARK_SISO 6144 -#define SF_W_MARK_MIMO2 8192 -#define SF_W_MARK_MIMO3 6144 -#define SF_W_MARK_LEGACY 4096 -#define SF_W_MARK_SCAN 4096 - -/* SF Scenarios timers for default configuration (aligned to 32 uSec) */ -#define SF_SINGLE_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ -#define SF_SINGLE_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ -#define SF_AGG_UNICAST_IDLE_TIMER_DEF 160 /* 150 uSec */ -#define SF_AGG_UNICAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ -#define SF_MCAST_IDLE_TIMER_DEF 160 /* 150 mSec */ -#define SF_MCAST_AGING_TIMER_DEF 400 /* 0.4 mSec */ -#define SF_BA_IDLE_TIMER_DEF 160 /* 150 uSec */ -#define SF_BA_AGING_TIMER_DEF 400 /* 0.4 mSec */ -#define SF_TX_RE_IDLE_TIMER_DEF 160 /* 150 uSec */ -#define SF_TX_RE_AGING_TIMER_DEF 400 /* 0.4 mSec */ - -/* SF Scenarios timers for BSS MAC configuration (aligned to 32 uSec) */ -#define SF_SINGLE_UNICAST_IDLE_TIMER 320 /* 300 uSec */ -#define SF_SINGLE_UNICAST_AGING_TIMER 2016 /* 2 mSec */ -#define SF_AGG_UNICAST_IDLE_TIMER 320 /* 300 uSec */ -#define SF_AGG_UNICAST_AGING_TIMER 2016 /* 2 mSec */ -#define SF_MCAST_IDLE_TIMER 2016 /* 2 mSec */ -#define SF_MCAST_AGING_TIMER 10016 /* 10 mSec */ -#define SF_BA_IDLE_TIMER 320 /* 300 uSec */ -#define SF_BA_AGING_TIMER 2016 /* 2 mSec */ -#define SF_TX_RE_IDLE_TIMER 320 /* 300 uSec */ -#define SF_TX_RE_AGING_TIMER 2016 /* 2 mSec */ - -#define SF_LONG_DELAY_AGING_TIMER 1000000 /* 1 Sec */ - -#define SF_CFG_DUMMY_NOTIF_OFF BIT(16) - -/** - * struct iwl_sf_cfg_cmd - Smart Fifo configuration command. - * @state: smart fifo state, types listed in &enum iwl_sf_state. - * @watermark: Minimum allowed availabe free space in RXF for transient state. - * @long_delay_timeouts: aging and idle timer values for each scenario - * in long delay state. - * @full_on_timeouts: timer values for each scenario in full on state. - */ -struct iwl_sf_cfg_cmd { - __le32 state; - __le32 watermark[SF_TRANSIENT_STATES_NUMBER]; - __le32 long_delay_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; - __le32 full_on_timeouts[SF_NUM_SCENARIO][SF_NUM_TIMEOUT_TYPES]; -} __packed; /* SF_CFG_API_S_VER_2 */ - -/*********************************** - * Location Aware Regulatory (LAR) API - MCC updates - ***********************************/ - -/** - * struct iwl_mcc_update_cmd_v1 - Request the device to update geographic - * regulatory profile according to the given MCC (Mobile Country Code). - * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. - * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the - * MCC in the cmd response will be the relevant MCC in the NVM. - * @mcc: given mobile country code - * @source_id: the source from where we got the MCC, see iwl_mcc_source - * @reserved: reserved for alignment - */ -struct iwl_mcc_update_cmd_v1 { - __le16 mcc; - u8 source_id; - u8 reserved; -} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_1 */ - -/** - * struct iwl_mcc_update_cmd - Request the device to update geographic - * regulatory profile according to the given MCC (Mobile Country Code). - * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. - * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the - * MCC in the cmd response will be the relevant MCC in the NVM. - * @mcc: given mobile country code - * @source_id: the source from where we got the MCC, see iwl_mcc_source - * @reserved: reserved for alignment - * @key: integrity key for MCC API OEM testing - * @reserved2: reserved - */ -struct iwl_mcc_update_cmd { - __le16 mcc; - u8 source_id; - u8 reserved; - __le32 key; - u8 reserved2[20]; -} __packed; /* LAR_UPDATE_MCC_CMD_API_S_VER_2 */ - -/** - * struct iwl_mcc_update_resp_v1 - response to MCC_UPDATE_CMD. - * Contains the new channel control profile map, if changed, and the new MCC - * (mobile country code). - * The new MCC may be different than what was requested in MCC_UPDATE_CMD. - * @status: see &enum iwl_mcc_update_status - * @mcc: the new applied MCC - * @cap: capabilities for all channels which matches the MCC - * @source_id: the MCC source, see iwl_mcc_source - * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 - * channels, depending on platform) - * @channels: channel control data map, DWORD for each channel. Only the first - * 16bits are used. - */ -struct iwl_mcc_update_resp_v1 { - __le32 status; - __le16 mcc; - u8 cap; - u8 source_id; - __le32 n_channels; - __le32 channels[0]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ - -/** - * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. - * Contains the new channel control profile map, if changed, and the new MCC - * (mobile country code). - * The new MCC may be different than what was requested in MCC_UPDATE_CMD. - * @status: see &enum iwl_mcc_update_status - * @mcc: the new applied MCC - * @cap: capabilities for all channels which matches the MCC - * @source_id: the MCC source, see iwl_mcc_source - * @time: time elapsed from the MCC test start (in 30 seconds TU) - * @reserved: reserved. - * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 - * channels, depending on platform) - * @channels: channel control data map, DWORD for each channel. Only the first - * 16bits are used. - */ -struct iwl_mcc_update_resp { - __le32 status; - __le16 mcc; - u8 cap; - u8 source_id; - __le16 time; - __le16 reserved; - __le32 n_channels; - __le32 channels[0]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */ - -/** - * struct iwl_mcc_chub_notif - chub notifies of mcc change - * (MCC_CHUB_UPDATE_CMD = 0xc9) - * The Chub (Communication Hub, CommsHUB) is a HW component that connects to - * the cellular and connectivity cores that gets updates of the mcc, and - * notifies the ucode directly of any mcc change. - * The ucode requests the driver to request the device to update geographic - * regulatory profile according to the given MCC (Mobile Country Code). - * The MCC is two letter-code, ascii upper case[A-Z] or '00' for world domain. - * 'ZZ' MCC will be used to switch to NVM default profile; in this case, the - * MCC in the cmd response will be the relevant MCC in the NVM. - * @mcc: given mobile country code - * @source_id: identity of the change originator, see iwl_mcc_source - * @reserved1: reserved for alignment - */ -struct iwl_mcc_chub_notif { - __le16 mcc; - u8 source_id; - u8 reserved1; -} __packed; /* LAR_MCC_NOTIFY_S */ - -enum iwl_mcc_update_status { - MCC_RESP_NEW_CHAN_PROFILE, - MCC_RESP_SAME_CHAN_PROFILE, - MCC_RESP_INVALID, - MCC_RESP_NVM_DISABLED, - MCC_RESP_ILLEGAL, - MCC_RESP_LOW_PRIORITY, - MCC_RESP_TEST_MODE_ACTIVE, - MCC_RESP_TEST_MODE_NOT_ACTIVE, - MCC_RESP_TEST_MODE_DENIAL_OF_SERVICE, -}; - -enum iwl_mcc_source { - MCC_SOURCE_OLD_FW = 0, - MCC_SOURCE_ME = 1, - MCC_SOURCE_BIOS = 2, - MCC_SOURCE_3G_LTE_HOST = 3, - MCC_SOURCE_3G_LTE_DEVICE = 4, - MCC_SOURCE_WIFI = 5, - MCC_SOURCE_RESERVED = 6, - MCC_SOURCE_DEFAULT = 7, - MCC_SOURCE_UNINITIALIZED = 8, - MCC_SOURCE_MCC_API = 9, - MCC_SOURCE_GET_CURRENT = 0x10, - MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11, -}; - -/* DTS measurements */ - -enum iwl_dts_measurement_flags { - DTS_TRIGGER_CMD_FLAGS_TEMP = BIT(0), - DTS_TRIGGER_CMD_FLAGS_VOLT = BIT(1), -}; - -/** - * struct iwl_dts_measurement_cmd - request DTS temp and/or voltage measurements - * - * @flags: indicates which measurements we want as specified in - * &enum iwl_dts_measurement_flags - */ -struct iwl_dts_measurement_cmd { - __le32 flags; -} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_CMD_S */ - -/** -* enum iwl_dts_control_measurement_mode - DTS measurement type -* @DTS_AUTOMATIC: Automatic mode (full SW control). Provide temperature read -* back (latest value. Not waiting for new value). Use automatic -* SW DTS configuration. -* @DTS_REQUEST_READ: Request DTS read. Configure DTS with manual settings, -* trigger DTS reading and provide read back temperature read -* when available. -* @DTS_OVER_WRITE: over-write the DTS temperatures in the SW until next read -* @DTS_DIRECT_WITHOUT_MEASURE: DTS returns its latest temperature result, -* without measurement trigger. -*/ -enum iwl_dts_control_measurement_mode { - DTS_AUTOMATIC = 0, - DTS_REQUEST_READ = 1, - DTS_OVER_WRITE = 2, - DTS_DIRECT_WITHOUT_MEASURE = 3, -}; - -/** -* enum iwl_dts_used - DTS to use or used for measurement in the DTS request -* @DTS_USE_TOP: Top -* @DTS_USE_CHAIN_A: chain A -* @DTS_USE_CHAIN_B: chain B -* @DTS_USE_CHAIN_C: chain C -* @XTAL_TEMPERATURE: read temperature from xtal -*/ -enum iwl_dts_used { - DTS_USE_TOP = 0, - DTS_USE_CHAIN_A = 1, - DTS_USE_CHAIN_B = 2, - DTS_USE_CHAIN_C = 3, - XTAL_TEMPERATURE = 4, -}; - -/** -* enum iwl_dts_bit_mode - bit-mode to use in DTS request read mode -* @DTS_BIT6_MODE: bit 6 mode -* @DTS_BIT8_MODE: bit 8 mode -*/ -enum iwl_dts_bit_mode { - DTS_BIT6_MODE = 0, - DTS_BIT8_MODE = 1, -}; - -/** - * struct iwl_ext_dts_measurement_cmd - request extended DTS temp measurements - * @control_mode: see &enum iwl_dts_control_measurement_mode - * @temperature: used when over write DTS mode is selected - * @sensor: set temperature sensor to use. See &enum iwl_dts_used - * @avg_factor: average factor to DTS in request DTS read mode - * @bit_mode: value defines the DTS bit mode to use. See &enum iwl_dts_bit_mode - * @step_duration: step duration for the DTS - */ -struct iwl_ext_dts_measurement_cmd { - __le32 control_mode; - __le32 temperature; - __le32 sensor; - __le32 avg_factor; - __le32 bit_mode; - __le32 step_duration; -} __packed; /* XVT_FW_DTS_CONTROL_MEASUREMENT_REQUEST_API_S */ - -/** - * struct iwl_dts_measurement_notif_v1 - measurements notification - * - * @temp: the measured temperature - * @voltage: the measured voltage - */ -struct iwl_dts_measurement_notif_v1 { - __le32 temp; - __le32 voltage; -} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_1*/ - -/** - * struct iwl_dts_measurement_notif_v2 - measurements notification - * - * @temp: the measured temperature - * @voltage: the measured voltage - * @threshold_idx: the trip index that was crossed - */ -struct iwl_dts_measurement_notif_v2 { - __le32 temp; - __le32 voltage; - __le32 threshold_idx; -} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S_VER_2 */ - -/** - * struct ct_kill_notif - CT-kill entry notification - * - * @temperature: the current temperature in celsius - * @reserved: reserved - */ -struct ct_kill_notif { - __le16 temperature; - __le16 reserved; -} __packed; /* GRP_PHY_CT_KILL_NTF */ - -/** -* enum ctdp_cmd_operation - CTDP command operations -* @CTDP_CMD_OPERATION_START: update the current budget -* @CTDP_CMD_OPERATION_STOP: stop ctdp -* @CTDP_CMD_OPERATION_REPORT: get the average budget -*/ -enum iwl_mvm_ctdp_cmd_operation { - CTDP_CMD_OPERATION_START = 0x1, - CTDP_CMD_OPERATION_STOP = 0x2, - CTDP_CMD_OPERATION_REPORT = 0x4, -};/* CTDP_CMD_OPERATION_TYPE_E */ - -/** - * struct iwl_mvm_ctdp_cmd - track and manage the FW power consumption budget - * - * @operation: see &enum iwl_mvm_ctdp_cmd_operation - * @budget: the budget in milliwatt - * @window_size: defined in API but not used - */ -struct iwl_mvm_ctdp_cmd { - __le32 operation; - __le32 budget; - __le32 window_size; -} __packed; - -#define IWL_MAX_DTS_TRIPS 8 - -/** - * struct temp_report_ths_cmd - set temperature thresholds - * - * @num_temps: number of temperature thresholds passed - * @thresholds: array with the thresholds to be configured - */ -struct temp_report_ths_cmd { - __le32 num_temps; - __le16 thresholds[IWL_MAX_DTS_TRIPS]; -} __packed; /* GRP_PHY_TEMP_REPORTING_THRESHOLDS_CMD */ - -/*********************************** - * TDLS API - ***********************************/ - -/* Type of TDLS request */ -enum iwl_tdls_channel_switch_type { - TDLS_SEND_CHAN_SW_REQ = 0, - TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH, - TDLS_MOVE_CH, -}; /* TDLS_STA_CHANNEL_SWITCH_CMD_TYPE_API_E_VER_1 */ - -/** - * struct iwl_tdls_channel_switch_timing - Switch timing in TDLS channel-switch - * @frame_timestamp: GP2 timestamp of channel-switch request/response packet - * received from peer - * @max_offchan_duration: What amount of microseconds out of a DTIM is given - * to the TDLS off-channel communication. For instance if the DTIM is - * 200TU and the TDLS peer is to be given 25% of the time, the value - * given will be 50TU, or 50 * 1024 if translated into microseconds. - * @switch_time: switch time the peer sent in its channel switch timing IE - * @switch_timeout: switch timeout the peer sent in its channel switch timing IE - */ -struct iwl_tdls_channel_switch_timing { - __le32 frame_timestamp; /* GP2 time of peer packet Rx */ - __le32 max_offchan_duration; /* given in micro-seconds */ - __le32 switch_time; /* given in micro-seconds */ - __le32 switch_timeout; /* given in micro-seconds */ -} __packed; /* TDLS_STA_CHANNEL_SWITCH_TIMING_DATA_API_S_VER_1 */ - -#define IWL_TDLS_CH_SW_FRAME_MAX_SIZE 200 - -/** - * struct iwl_tdls_channel_switch_frame - TDLS channel switch frame template - * - * A template representing a TDLS channel-switch request or response frame - * - * @switch_time_offset: offset to the channel switch timing IE in the template - * @tx_cmd: Tx parameters for the frame - * @data: frame data - */ -struct iwl_tdls_channel_switch_frame { - __le32 switch_time_offset; - struct iwl_tx_cmd tx_cmd; - u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE]; -} __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ - -/** - * struct iwl_tdls_channel_switch_cmd - TDLS channel switch command - * - * The command is sent to initiate a channel switch and also in response to - * incoming TDLS channel-switch request/response packets from remote peers. - * - * @switch_type: see &enum iwl_tdls_channel_switch_type - * @peer_sta_id: station id of TDLS peer - * @ci: channel we switch to - * @timing: timing related data for command - * @frame: channel-switch request/response template, depending to switch_type - */ -struct iwl_tdls_channel_switch_cmd { - u8 switch_type; - __le32 peer_sta_id; - struct iwl_fw_channel_info ci; - struct iwl_tdls_channel_switch_timing timing; - struct iwl_tdls_channel_switch_frame frame; -} __packed; /* TDLS_STA_CHANNEL_SWITCH_CMD_API_S_VER_1 */ - -/** - * struct iwl_tdls_channel_switch_notif - TDLS channel switch start notification - * - * @status: non-zero on success - * @offchannel_duration: duration given in microseconds - * @sta_id: peer currently performing the channel-switch with - */ -struct iwl_tdls_channel_switch_notif { - __le32 status; - __le32 offchannel_duration; - __le32 sta_id; -} __packed; /* TDLS_STA_CHANNEL_SWITCH_NTFY_API_S_VER_1 */ - -/** - * struct iwl_tdls_sta_info - TDLS station info - * - * @sta_id: station id of the TDLS peer - * @tx_to_peer_tid: TID reserved vs. the peer for FW based Tx - * @tx_to_peer_ssn: initial SSN the FW should use for Tx on its TID vs the peer - * @is_initiator: 1 if the peer is the TDLS link initiator, 0 otherwise - */ -struct iwl_tdls_sta_info { - u8 sta_id; - u8 tx_to_peer_tid; - __le16 tx_to_peer_ssn; - __le32 is_initiator; -} __packed; /* TDLS_STA_INFO_VER_1 */ - -/** - * struct iwl_tdls_config_cmd - TDLS basic config command - * - * @id_and_color: MAC id and color being configured - * @tdls_peer_count: amount of currently connected TDLS peers - * @tx_to_ap_tid: TID reverved vs. the AP for FW based Tx - * @tx_to_ap_ssn: initial SSN the FW should use for Tx on its TID vs. the AP - * @sta_info: per-station info. Only the first tdls_peer_count entries are set - * @pti_req_data_offset: offset of network-level data for the PTI template - * @pti_req_tx_cmd: Tx parameters for PTI request template - * @pti_req_template: PTI request template data - */ -struct iwl_tdls_config_cmd { - __le32 id_and_color; /* mac id and color */ - u8 tdls_peer_count; - u8 tx_to_ap_tid; - __le16 tx_to_ap_ssn; - struct iwl_tdls_sta_info sta_info[IWL_MVM_TDLS_STA_COUNT]; - - __le32 pti_req_data_offset; - struct iwl_tx_cmd pti_req_tx_cmd; - u8 pti_req_template[0]; -} __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ - -/** - * struct iwl_tdls_config_sta_info_res - TDLS per-station config information - * - * @sta_id: station id of the TDLS peer - * @tx_to_peer_last_seq: last sequence number used by FW during FW-based Tx to - * the peer - */ -struct iwl_tdls_config_sta_info_res { - __le16 sta_id; - __le16 tx_to_peer_last_seq; -} __packed; /* TDLS_STA_INFO_RSP_VER_1 */ - -/** - * struct iwl_tdls_config_res - TDLS config information from FW - * - * @tx_to_ap_last_seq: last sequence number used by FW during FW-based Tx to AP - * @sta_info: per-station TDLS config information - */ -struct iwl_tdls_config_res { - __le32 tx_to_ap_last_seq; - struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT]; -} __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */ - -#define TX_FIFO_MAX_NUM_9000 8 -#define TX_FIFO_MAX_NUM 15 -#define RX_FIFO_MAX_NUM 2 -#define TX_FIFO_INTERNAL_MAX_NUM 6 - -/** - * struct iwl_shared_mem_cfg_v2 - Shared memory configuration information - * - * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not - * accessible) - * @shared_mem_size: shared memory size - * @sample_buff_addr: internal sample (mon/adc) buff addr (pre 8000 HW set to - * 0x0 as accessible only via DBGM RDAT) - * @sample_buff_size: internal sample buff size - * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB), (pre - * 8000 HW set to 0x0 as not accessible) - * @txfifo_size: size of TXF0 ... TXF7 - * @rxfifo_size: RXF1, RXF2 sizes. If there is no RXF2, it'll have a value of 0 - * @page_buff_addr: used by UMAC and performance debug (page miss analysis), - * when paging is not supported this should be 0 - * @page_buff_size: size of %page_buff_addr - * @rxfifo_addr: Start address of rxFifo - * @internal_txfifo_addr: start address of internalFifo - * @internal_txfifo_size: internal fifos' size - * - * NOTE: on firmware that don't have IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG - * set, the last 3 members don't exist. - */ -struct iwl_shared_mem_cfg_v2 { - __le32 shared_mem_addr; - __le32 shared_mem_size; - __le32 sample_buff_addr; - __le32 sample_buff_size; - __le32 txfifo_addr; - __le32 txfifo_size[TX_FIFO_MAX_NUM_9000]; - __le32 rxfifo_size[RX_FIFO_MAX_NUM]; - __le32 page_buff_addr; - __le32 page_buff_size; - __le32 rxfifo_addr; - __le32 internal_txfifo_addr; - __le32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; -} __packed; /* SHARED_MEM_ALLOC_API_S_VER_2 */ - -/** - * struct iwl_shared_mem_lmac_cfg - LMAC shared memory configuration - * - * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB) - * @txfifo_size: size of TX FIFOs - * @rxfifo1_addr: RXF1 addr - * @rxfifo1_size: RXF1 size - */ -struct iwl_shared_mem_lmac_cfg { - __le32 txfifo_addr; - __le32 txfifo_size[TX_FIFO_MAX_NUM]; - __le32 rxfifo1_addr; - __le32 rxfifo1_size; - -} __packed; /* SHARED_MEM_ALLOC_LMAC_API_S_VER_1 */ - -/** - * struct iwl_shared_mem_cfg - Shared memory configuration information - * - * @shared_mem_addr: shared memory address - * @shared_mem_size: shared memory size - * @sample_buff_addr: internal sample (mon/adc) buff addr - * @sample_buff_size: internal sample buff size - * @rxfifo2_addr: start addr of RXF2 - * @rxfifo2_size: size of RXF2 - * @page_buff_addr: used by UMAC and performance debug (page miss analysis), - * when paging is not supported this should be 0 - * @page_buff_size: size of %page_buff_addr - * @lmac_num: number of LMACs (1 or 2) - * @lmac_smem: per - LMAC smem data - */ -struct iwl_shared_mem_cfg { - __le32 shared_mem_addr; - __le32 shared_mem_size; - __le32 sample_buff_addr; - __le32 sample_buff_size; - __le32 rxfifo2_addr; - __le32 rxfifo2_size; - __le32 page_buff_addr; - __le32 page_buff_size; - __le32 lmac_num; - struct iwl_shared_mem_lmac_cfg lmac_smem[2]; -} __packed; /* SHARED_MEM_ALLOC_API_S_VER_3 */ - -/** - * struct iwl_mu_group_mgmt_cmd - VHT MU-MIMO group configuration - * - * @reserved: reserved - * @membership_status: a bitmap of MU groups - * @user_position:the position of station in a group. If the station is in the - * group then bits (group * 2) is the position -1 - */ -struct iwl_mu_group_mgmt_cmd { - __le32 reserved; - __le32 membership_status[2]; - __le32 user_position[4]; -} __packed; /* MU_GROUP_ID_MNG_TABLE_API_S_VER_1 */ - -/** - * struct iwl_mu_group_mgmt_notif - VHT MU-MIMO group id notification - * - * @membership_status: a bitmap of MU groups - * @user_position: the position of station in a group. If the station is in the - * group then bits (group * 2) is the position -1 - */ -struct iwl_mu_group_mgmt_notif { - __le32 membership_status[2]; - __le32 user_position[4]; -} __packed; /* MU_GROUP_MNG_NTFY_API_S_VER_1 */ - -#define MAX_STORED_BEACON_SIZE 600 - -/** - * struct iwl_stored_beacon_notif - Stored beacon notification - * - * @system_time: system time on air rise - * @tsf: TSF on air rise - * @beacon_timestamp: beacon on air rise - * @band: band, matches &RX_RES_PHY_FLAGS_BAND_24 definition - * @channel: channel this beacon was received on - * @rates: rate in ucode internal format - * @byte_count: frame's byte count - * @data: beacon data, length in @byte_count - */ -struct iwl_stored_beacon_notif { - __le32 system_time; - __le64 tsf; - __le32 beacon_timestamp; - __le16 band; - __le16 channel; - __le32 rates; - __le32 byte_count; - u8 data[MAX_STORED_BEACON_SIZE]; -} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_2 */ - -#define LQM_NUMBER_OF_STATIONS_IN_REPORT 16 - -enum iwl_lqm_cmd_operatrions { - LQM_CMD_OPERATION_START_MEASUREMENT = 0x01, - LQM_CMD_OPERATION_STOP_MEASUREMENT = 0x02, -}; - -enum iwl_lqm_status { - LQM_STATUS_SUCCESS = 0, - LQM_STATUS_TIMEOUT = 1, - LQM_STATUS_ABORT = 2, -}; - -/** - * struct iwl_link_qual_msrmnt_cmd - Link Quality Measurement command - * @cmd_operation: command operation to be performed (start or stop) - * as defined above. - * @mac_id: MAC ID the measurement applies to. - * @measurement_time: time of the total measurement to be performed, in uSec. - * @timeout: maximum time allowed until a response is sent, in uSec. - */ -struct iwl_link_qual_msrmnt_cmd { - __le32 cmd_operation; - __le32 mac_id; - __le32 measurement_time; - __le32 timeout; -} __packed /* LQM_CMD_API_S_VER_1 */; - -/** - * struct iwl_link_qual_msrmnt_notif - Link Quality Measurement notification - * - * @frequent_stations_air_time: an array containing the total air time - * (in uSec) used by the most frequently transmitting stations. - * @number_of_stations: the number of uniqe stations included in the array - * (a number between 0 to 16) - * @total_air_time_other_stations: the total air time (uSec) used by all the - * stations which are not included in the above report. - * @time_in_measurement_window: the total time in uSec in which a measurement - * took place. - * @tx_frame_dropped: the number of TX frames dropped due to retry limit during - * measurement - * @mac_id: MAC ID the measurement applies to. - * @status: return status. may be one of the LQM_STATUS_* defined above. - * @reserved: reserved. - */ -struct iwl_link_qual_msrmnt_notif { - __le32 frequent_stations_air_time[LQM_NUMBER_OF_STATIONS_IN_REPORT]; - __le32 number_of_stations; - __le32 total_air_time_other_stations; - __le32 time_in_measurement_window; - __le32 tx_frame_dropped; - __le32 mac_id; - __le32 status; - u8 reserved[12]; -} __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */ - -/** - * struct iwl_channel_switch_noa_notif - Channel switch NOA notification - * - * @id_and_color: ID and color of the MAC - */ -struct iwl_channel_switch_noa_notif { - __le32 id_and_color; -} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */ - -/* Operation types for the debug mem access */ -enum { - DEBUG_MEM_OP_READ = 0, - DEBUG_MEM_OP_WRITE = 1, - DEBUG_MEM_OP_WRITE_BYTES = 2, -}; - -#define DEBUG_MEM_MAX_SIZE_DWORDS 32 - -/** - * struct iwl_dbg_mem_access_cmd - Request the device to read/write memory - * @op: DEBUG_MEM_OP_* - * @addr: address to read/write from/to - * @len: in dwords, to read/write - * @data: for write opeations, contains the source buffer - */ -struct iwl_dbg_mem_access_cmd { - __le32 op; - __le32 addr; - __le32 len; - __le32 data[]; -} __packed; /* DEBUG_(U|L)MAC_RD_WR_CMD_API_S_VER_1 */ - -/* Status responses for the debug mem access */ -enum { - DEBUG_MEM_STATUS_SUCCESS = 0x0, - DEBUG_MEM_STATUS_FAILED = 0x1, - DEBUG_MEM_STATUS_LOCKED = 0x2, - DEBUG_MEM_STATUS_HIDDEN = 0x3, - DEBUG_MEM_STATUS_LENGTH = 0x4, -}; - -/** - * struct iwl_dbg_mem_access_rsp - Response to debug mem commands - * @status: DEBUG_MEM_STATUS_* - * @len: read dwords (0 for write operations) - * @data: contains the read DWs - */ -struct iwl_dbg_mem_access_rsp { - __le32 status; - __le32 len; - __le32 data[]; -} __packed; /* DEBUG_(U|L)MAC_RD_WR_RSP_API_S_VER_1 */ - -/** - * struct iwl_nvm_access_complete_cmd - NVM_ACCESS commands are completed - * @reserved: reserved - */ -struct iwl_nvm_access_complete_cmd { - __le32 reserved; -} __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ - -/** - * enum iwl_extended_cfg_flag - commands driver may send before - * finishing init flow - * @IWL_INIT_DEBUG_CFG: driver is going to send debug config command - * @IWL_INIT_NVM: driver is going to send NVM_ACCESS commands - * @IWL_INIT_PHY: driver is going to send PHY_DB commands - */ -enum iwl_extended_cfg_flags { - IWL_INIT_DEBUG_CFG, - IWL_INIT_NVM, - IWL_INIT_PHY, -}; - -/** - * struct iwl_extended_cfg_cmd - mark what commands ucode should wait for - * before finishing init flows - * @init_flags: values from iwl_extended_cfg_flags - */ -struct iwl_init_extended_cfg_cmd { - __le32 init_flags; -} __packed; /* INIT_EXTENDED_CFG_CMD_API_S_VER_1 */ - -/* - * struct iwl_nvm_get_info - request to get NVM data - */ -struct iwl_nvm_get_info { - __le32 reserved; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_S_VER_1 */ - -/** - * struct iwl_nvm_get_info_general - general NVM data - * @flags: 1 - empty, 0 - valid - * @nvm_version: nvm version - * @board_type: board type - * @reserved: reserved - */ -struct iwl_nvm_get_info_general { - __le32 flags; - __le16 nvm_version; - u8 board_type; - u8 reserved; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_GENERAL_S_VER_1 */ - -/** - * struct iwl_nvm_get_info_sku - mac information - * @enable_24g: band 2.4G enabled - * @enable_5g: band 5G enabled - * @enable_11n: 11n enabled - * @enable_11ac: 11ac enabled - * @mimo_disable: MIMO enabled - * @ext_crypto: Extended crypto enabled - */ -struct iwl_nvm_get_info_sku { - __le32 enable_24g; - __le32 enable_5g; - __le32 enable_11n; - __le32 enable_11ac; - __le32 mimo_disable; - __le32 ext_crypto; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_MAC_SKU_SECTION_S_VER_1 */ - -/** - * struct iwl_nvm_get_info_phy - phy information - * @tx_chains: BIT 0 chain A, BIT 1 chain B - * @rx_chains: BIT 0 chain A, BIT 1 chain B - */ -struct iwl_nvm_get_info_phy { - __le32 tx_chains; - __le32 rx_chains; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_PHY_SKU_SECTION_S_VER_1 */ - -#define IWL_NUM_CHANNELS (51) - -/** - * struct iwl_nvm_get_info_regulatory - regulatory information - * @lar_enabled: is LAR enabled - * @channel_profile: regulatory data of this channel - * @reserved: reserved - */ -struct iwl_nvm_get_info_regulatory { - __le32 lar_enabled; - __le16 channel_profile[IWL_NUM_CHANNELS]; - __le16 reserved; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_REGULATORY_S_VER_1 */ - -/** - * struct iwl_nvm_get_info_rsp - response to get NVM data - * @general: general NVM data - * @mac_sku: data relating to MAC sku - * @phy_sku: data relating to PHY sku - * @regulatory: regulatory data - */ -struct iwl_nvm_get_info_rsp { - struct iwl_nvm_get_info_general general; - struct iwl_nvm_get_info_sku mac_sku; - struct iwl_nvm_get_info_phy phy_sku; - struct iwl_nvm_get_info_regulatory regulatory; -} __packed; /* GRP_REGULATORY_NVM_GET_INFO_CMD_RSP_S_VER_1 */ - -/** - * struct iwl_mvm_antenna_coupling_notif - antenna coupling notification - * @isolation: antenna isolation value - */ -struct iwl_mvm_antenna_coupling_notif { - __le32 isolation; -} __packed; +#include "fw/api/tdls.h" +#include "fw/api/mac-cfg.h" +#include "fw/api/offload.h" +#include "fw/api/context.h" +#include "fw/api/time-event.h" +#include "fw/api/datapath.h" +#include "fw/api/phy.h" +#include "fw/api/config.h" +#include "fw/api/alive.h" +#include "fw/api/binding.h" +#include "fw/api/cmdhdr.h" +#include "fw/api/coex.h" +#include "fw/api/commands.h" +#include "fw/api/d3.h" +#include "fw/api/filter.h" +#include "fw/api/led.h" +#include "fw/api/mac.h" +#include "fw/api/nvm-reg.h" +#include "fw/api/phy-ctxt.h" +#include "fw/api/power.h" +#include "fw/api/rs.h" +#include "fw/api/rx.h" +#include "fw/api/scan.h" +#include "fw/api/sf.h" +#include "fw/api/sta.h" +#include "fw/api/stats.h" +#include "fw/api/tof.h" +#include "fw/api/tx.h" #endif /* __fw_api_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 82863e9273eb..83485493a79a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -78,7 +78,7 @@ #include "iwl-eeprom-parse.h" #include "mvm.h" -#include "fw-dbg.h" +#include "fw/dbg.h" #include "iwl-phy-db.h" #define MVM_UCODE_ALIVE_TIMEOUT HZ @@ -144,134 +144,6 @@ static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm) return ret; } -void iwl_free_fw_paging(struct iwl_mvm *mvm) -{ - int i; - - if (!mvm->fw_paging_db[0].fw_paging_block) - return; - - for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { - struct iwl_fw_paging *paging = &mvm->fw_paging_db[i]; - - if (!paging->fw_paging_block) { - IWL_DEBUG_FW(mvm, - "Paging: block %d already freed, continue to next page\n", - i); - - continue; - } - dma_unmap_page(mvm->trans->dev, paging->fw_paging_phys, - paging->fw_paging_size, DMA_BIDIRECTIONAL); - - __free_pages(paging->fw_paging_block, - get_order(paging->fw_paging_size)); - paging->fw_paging_block = NULL; - } - kfree(mvm->trans->paging_download_buf); - mvm->trans->paging_download_buf = NULL; - mvm->trans->paging_db = NULL; - - memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); -} - -static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image) -{ - int sec_idx, idx; - u32 offset = 0; - - /* - * find where is the paging image start point: - * if CPU2 exist and it's in paging format, then the image looks like: - * CPU1 sections (2 or more) - * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 - * CPU2 sections (not paged) - * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 - * non paged to CPU2 paging sec - * CPU2 paging CSS - * CPU2 paging image (including instruction and data) - */ - for (sec_idx = 0; sec_idx < image->num_sec; sec_idx++) { - if (image->sec[sec_idx].offset == PAGING_SEPARATOR_SECTION) { - sec_idx++; - break; - } - } - - /* - * If paging is enabled there should be at least 2 more sections left - * (one for CSS and one for Paging data) - */ - if (sec_idx >= image->num_sec - 1) { - IWL_ERR(mvm, "Paging: Missing CSS and/or paging sections\n"); - iwl_free_fw_paging(mvm); - return -EINVAL; - } - - /* copy the CSS block to the dram */ - IWL_DEBUG_FW(mvm, "Paging: load paging CSS to FW, sec = %d\n", - sec_idx); - - memcpy(page_address(mvm->fw_paging_db[0].fw_paging_block), - image->sec[sec_idx].data, - mvm->fw_paging_db[0].fw_paging_size); - dma_sync_single_for_device(mvm->trans->dev, - mvm->fw_paging_db[0].fw_paging_phys, - mvm->fw_paging_db[0].fw_paging_size, - DMA_BIDIRECTIONAL); - - IWL_DEBUG_FW(mvm, - "Paging: copied %d CSS bytes to first block\n", - mvm->fw_paging_db[0].fw_paging_size); - - sec_idx++; - - /* - * copy the paging blocks to the dram - * loop index start from 1 since that CSS block already copied to dram - * and CSS index is 0. - * loop stop at num_of_paging_blk since that last block is not full. - */ - for (idx = 1; idx < mvm->num_of_paging_blk; idx++) { - struct iwl_fw_paging *block = &mvm->fw_paging_db[idx]; - - memcpy(page_address(block->fw_paging_block), - image->sec[sec_idx].data + offset, - block->fw_paging_size); - dma_sync_single_for_device(mvm->trans->dev, - block->fw_paging_phys, - block->fw_paging_size, - DMA_BIDIRECTIONAL); - - - IWL_DEBUG_FW(mvm, - "Paging: copied %d paging bytes to block %d\n", - mvm->fw_paging_db[idx].fw_paging_size, - idx); - - offset += mvm->fw_paging_db[idx].fw_paging_size; - } - - /* copy the last paging block */ - if (mvm->num_of_pages_in_last_blk > 0) { - struct iwl_fw_paging *block = &mvm->fw_paging_db[idx]; - - memcpy(page_address(block->fw_paging_block), - image->sec[sec_idx].data + offset, - FW_PAGING_SIZE * mvm->num_of_pages_in_last_blk); - dma_sync_single_for_device(mvm->trans->dev, - block->fw_paging_phys, - block->fw_paging_size, - DMA_BIDIRECTIONAL); - - IWL_DEBUG_FW(mvm, - "Paging: copied %d pages in the last block %d\n", - mvm->num_of_pages_in_last_blk, idx); - } - - return 0; -} - void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -293,178 +165,6 @@ void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, le32_to_cpu(dump_data[i])); } -static int iwl_alloc_fw_paging_mem(struct iwl_mvm *mvm, - const struct fw_img *image) -{ - struct page *block; - dma_addr_t phys = 0; - int blk_idx, order, num_of_pages, size, dma_enabled; - - if (mvm->fw_paging_db[0].fw_paging_block) - return 0; - - dma_enabled = is_device_dma_capable(mvm->trans->dev); - - /* ensure BLOCK_2_EXP_SIZE is power of 2 of PAGING_BLOCK_SIZE */ - BUILD_BUG_ON(BIT(BLOCK_2_EXP_SIZE) != PAGING_BLOCK_SIZE); - - num_of_pages = image->paging_mem_size / FW_PAGING_SIZE; - mvm->num_of_paging_blk = - DIV_ROUND_UP(num_of_pages, NUM_OF_PAGE_PER_GROUP); - mvm->num_of_pages_in_last_blk = - num_of_pages - - NUM_OF_PAGE_PER_GROUP * (mvm->num_of_paging_blk - 1); - - IWL_DEBUG_FW(mvm, - "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n", - mvm->num_of_paging_blk, - mvm->num_of_pages_in_last_blk); - - /* - * Allocate CSS and paging blocks in dram. - */ - for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { - /* For CSS allocate 4KB, for others PAGING_BLOCK_SIZE (32K) */ - size = blk_idx ? PAGING_BLOCK_SIZE : FW_PAGING_SIZE; - order = get_order(size); - block = alloc_pages(GFP_KERNEL, order); - if (!block) { - /* free all the previous pages since we failed */ - iwl_free_fw_paging(mvm); - return -ENOMEM; - } - - mvm->fw_paging_db[blk_idx].fw_paging_block = block; - mvm->fw_paging_db[blk_idx].fw_paging_size = size; - - if (dma_enabled) { - phys = dma_map_page(mvm->trans->dev, block, 0, - PAGE_SIZE << order, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(mvm->trans->dev, phys)) { - /* - * free the previous pages and the current one - * since we failed to map_page. - */ - iwl_free_fw_paging(mvm); - return -ENOMEM; - } - mvm->fw_paging_db[blk_idx].fw_paging_phys = phys; - } else { - mvm->fw_paging_db[blk_idx].fw_paging_phys = - PAGING_ADDR_SIG | - blk_idx << BLOCK_2_EXP_SIZE; - } - - if (!blk_idx) - IWL_DEBUG_FW(mvm, - "Paging: allocated 4K(CSS) bytes (order %d) for firmware paging.\n", - order); - else - IWL_DEBUG_FW(mvm, - "Paging: allocated 32K bytes (order %d) for firmware paging.\n", - order); - } - - return 0; -} - -static int iwl_save_fw_paging(struct iwl_mvm *mvm, - const struct fw_img *fw) -{ - int ret; - - ret = iwl_alloc_fw_paging_mem(mvm, fw); - if (ret) - return ret; - - return iwl_fill_paging_mem(mvm, fw); -} - -/* send paging cmd to FW in case CPU2 has paging image */ -static int iwl_send_paging_cmd(struct iwl_mvm *mvm, const struct fw_img *fw) -{ - struct iwl_fw_paging_cmd paging_cmd = { - .flags = cpu_to_le32(PAGING_CMD_IS_SECURED | - PAGING_CMD_IS_ENABLED | - (mvm->num_of_pages_in_last_blk << - PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), - .block_size = cpu_to_le32(BLOCK_2_EXP_SIZE), - .block_num = cpu_to_le32(mvm->num_of_paging_blk), - }; - int blk_idx; - - /* loop for for all paging blocks + CSS block */ - for (blk_idx = 0; blk_idx < mvm->num_of_paging_blk + 1; blk_idx++) { - dma_addr_t addr = mvm->fw_paging_db[blk_idx].fw_paging_phys; - __le32 phy_addr; - - addr = addr >> PAGE_2_EXP_SIZE; - phy_addr = cpu_to_le32(addr); - paging_cmd.device_phy_addr[blk_idx] = phy_addr; - } - - return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(FW_PAGING_BLOCK_CMD, - IWL_ALWAYS_LONG_GROUP, 0), - 0, sizeof(paging_cmd), &paging_cmd); -} - -/* - * Send paging item cmd to FW in case CPU2 has paging image - */ -static int iwl_trans_get_paging_item(struct iwl_mvm *mvm) -{ - int ret; - struct iwl_fw_get_item_cmd fw_get_item_cmd = { - .item_id = cpu_to_le32(IWL_FW_ITEM_ID_PAGING), - }; - - struct iwl_fw_get_item_resp *item_resp; - struct iwl_host_cmd cmd = { - .id = iwl_cmd_id(FW_GET_ITEM_CMD, IWL_ALWAYS_LONG_GROUP, 0), - .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, - .data = { &fw_get_item_cmd, }, - }; - - cmd.len[0] = sizeof(struct iwl_fw_get_item_cmd); - - ret = iwl_mvm_send_cmd(mvm, &cmd); - if (ret) { - IWL_ERR(mvm, - "Paging: Failed to send FW_GET_ITEM_CMD cmd (err = %d)\n", - ret); - return ret; - } - - item_resp = (void *)((struct iwl_rx_packet *)cmd.resp_pkt)->data; - if (item_resp->item_id != cpu_to_le32(IWL_FW_ITEM_ID_PAGING)) { - IWL_ERR(mvm, - "Paging: got wrong item in FW_GET_ITEM_CMD resp (item_id = %u)\n", - le32_to_cpu(item_resp->item_id)); - ret = -EIO; - goto exit; - } - - /* Add an extra page for headers */ - mvm->trans->paging_download_buf = kzalloc(PAGING_BLOCK_SIZE + - FW_PAGING_SIZE, - GFP_KERNEL); - if (!mvm->trans->paging_download_buf) { - ret = -ENOMEM; - goto exit; - } - mvm->trans->paging_req_addr = le32_to_cpu(item_resp->item_val); - mvm->trans->paging_db = mvm->fw_paging_db; - IWL_DEBUG_FW(mvm, - "Paging: got paging request address (paging_req_addr 0x%08x)\n", - mvm->trans->paging_req_addr); - -exit: - iwl_free_resp(&cmd); - - return ret; -} - static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, struct iwl_rx_packet *pkt, void *data) { @@ -544,48 +244,6 @@ static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, return false; } -static int iwl_mvm_init_paging(struct iwl_mvm *mvm) -{ - const struct fw_img *fw = &mvm->fw->img[mvm->cur_ucode]; - int ret; - - /* - * Configure and operate fw paging mechanism. - * The driver configures the paging flow only once. - * The CPU2 paging image is included in the IWL_UCODE_INIT image. - */ - if (!fw->paging_mem_size) - return 0; - - /* - * When dma is not enabled, the driver needs to copy / write - * the downloaded / uploaded page to / from the smem. - * This gets the location of the place were the pages are - * stored. - */ - if (!is_device_dma_capable(mvm->trans->dev)) { - ret = iwl_trans_get_paging_item(mvm); - if (ret) { - IWL_ERR(mvm, "failed to get FW paging item\n"); - return ret; - } - } - - ret = iwl_save_fw_paging(mvm, fw); - if (ret) { - IWL_ERR(mvm, "failed to save the FW paging image\n"); - return ret; - } - - ret = iwl_send_paging_cmd(mvm, fw); - if (ret) { - IWL_ERR(mvm, "failed to send the paging cmd\n"); - iwl_free_fw_paging(mvm); - return ret; - } - - return 0; -} static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, enum iwl_ucode_type ucode_type) { @@ -593,7 +251,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, struct iwl_mvm_alive_data alive_data; const struct fw_img *fw; int ret, i; - enum iwl_ucode_type old_type = mvm->cur_ucode; + enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; static const u16 alive_cmd[] = { MVM_ALIVE }; struct iwl_sf_region st_fwrd_space; @@ -606,7 +264,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, fw = iwl_get_ucode_image(mvm->fw, ucode_type); if (WARN_ON(!fw)) return -EINVAL; - mvm->cur_ucode = ucode_type; + iwl_fw_set_current_image(&mvm->fwrt, ucode_type); clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); iwl_init_notification_wait(&mvm->notif_wait, &alive_wait, @@ -615,7 +273,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); if (ret) { - mvm->cur_ucode = old_type; + iwl_fw_set_current_image(&mvm->fwrt, old_type); iwl_remove_notification(&mvm->notif_wait, &alive_wait); return ret; } @@ -639,13 +297,13 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", iwl_read_prph(trans, SB_CPU_1_STATUS), iwl_read_prph(trans, SB_CPU_2_STATUS)); - mvm->cur_ucode = old_type; + iwl_fw_set_current_image(&mvm->fwrt, old_type); return ret; } if (!alive_data.valid) { IWL_ERR(mvm, "Loaded ucode is not valid!\n"); - mvm->cur_ucode = old_type; + iwl_fw_set_current_image(&mvm->fwrt, old_type); return -EIO; } @@ -673,10 +331,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, */ memset(&mvm->queue_info, 0, sizeof(mvm->queue_info)); - if (iwl_mvm_is_dqa_supported(mvm)) - mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].hw_queue_refcount = 1; - else - mvm->queue_info[IWL_MVM_CMD_QUEUE].hw_queue_refcount = 1; + mvm->queue_info[IWL_MVM_DQA_CMD_QUEUE].hw_queue_refcount = 1; for (i = 0; i < IEEE80211_MAX_QUEUES; i++) atomic_set(&mvm->mac80211_queue_stop_count[i], 0); @@ -733,7 +388,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) } if (IWL_MVM_PARSE_NVM && read_nvm) { - ret = iwl_nvm_init(mvm, true); + ret = iwl_nvm_init(mvm); if (ret) { IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); goto error; @@ -757,8 +412,10 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) /* Read the NVM only at driver load time, no need to do this twice */ if (!IWL_MVM_PARSE_NVM && read_nvm) { - ret = iwl_mvm_nvm_get_from_fw(mvm); - if (ret) { + mvm->nvm_data = iwl_fw_get_nvm(&mvm->fwrt); + if (IS_ERR(mvm->nvm_data)) { + ret = PTR_ERR(mvm->nvm_data); + mvm->nvm_data = NULL; IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); return ret; } @@ -774,7 +431,7 @@ error: static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) { struct iwl_phy_cfg_cmd phy_cfg_cmd; - enum iwl_ucode_type ucode_type = mvm->cur_ucode; + enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; /* Set parameters */ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); @@ -799,7 +456,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) }; int ret; - if (iwl_mvm_has_new_tx_api(mvm)) + if (iwl_mvm_has_unified_ucode(mvm)) return iwl_run_unified_mvm_ucode(mvm, true); lockdep_assert_held(&mvm->mutex); @@ -818,22 +475,21 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT); if (ret) { IWL_ERR(mvm, "Failed to start INIT ucode: %d\n", ret); - goto error; + goto remove_notif; } if (mvm->cfg->device_family < IWL_DEVICE_FAMILY_8000) { ret = iwl_mvm_send_bt_init_conf(mvm); if (ret) - goto error; + goto remove_notif; } /* Read the NVM only at driver load time, no need to do this twice */ if (read_nvm) { - /* Read nvm */ - ret = iwl_nvm_init(mvm, true); + ret = iwl_nvm_init(mvm); if (ret) { IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); - goto error; + goto remove_notif; } } @@ -841,8 +497,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) if (mvm->nvm_file_name) iwl_mvm_load_nvm_to_nic(mvm); - ret = iwl_nvm_check_version(mvm->nvm_data, mvm->trans); - WARN_ON(ret); + WARN_ON(iwl_nvm_check_version(mvm->nvm_data, mvm->trans)); /* * abort after reading the nvm in case RF Kill is on, we will complete @@ -851,9 +506,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) if (iwl_mvm_is_radio_hw_killed(mvm)) { IWL_DEBUG_RF_KILL(mvm, "jump over all phy activities due to RF kill\n"); - iwl_remove_notification(&mvm->notif_wait, &calib_wait); - ret = 1; - goto out; + goto remove_notif; } mvm->calibrating = true; @@ -861,17 +514,13 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) /* Send TX valid antennas before triggering calibrations */ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) - goto error; + goto remove_notif; - /* - * Send phy configurations command to init uCode - * to start the 16.0 uCode init image internal calibrations. - */ ret = iwl_send_phy_cfg_cmd(mvm); if (ret) { IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", ret); - goto error; + goto remove_notif; } /* @@ -879,15 +528,21 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) * just wait for the calibration complete notification. */ ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, - MVM_UCODE_CALIB_TIMEOUT); + MVM_UCODE_CALIB_TIMEOUT); + if (!ret) + goto out; - if (ret && iwl_mvm_is_radio_hw_killed(mvm)) { + if (iwl_mvm_is_radio_hw_killed(mvm)) { IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); - ret = 1; + ret = 0; + } else { + IWL_ERR(mvm, "Failed to run INIT calibrations: %d\n", + ret); } + goto out; -error: +remove_notif: iwl_remove_notification(&mvm->notif_wait, &calib_wait); out: mvm->calibrating = false; @@ -910,95 +565,6 @@ out: return ret; } -static void iwl_mvm_parse_shared_mem_a000(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) -{ - struct iwl_shared_mem_cfg *mem_cfg = (void *)pkt->data; - int i, lmac; - int lmac_num = le32_to_cpu(mem_cfg->lmac_num); - - if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem))) - return; - - mvm->smem_cfg.num_lmacs = lmac_num; - mvm->smem_cfg.num_txfifo_entries = - ARRAY_SIZE(mem_cfg->lmac_smem[0].txfifo_size); - mvm->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size); - - for (lmac = 0; lmac < lmac_num; lmac++) { - struct iwl_shared_mem_lmac_cfg *lmac_cfg = - &mem_cfg->lmac_smem[lmac]; - - for (i = 0; i < ARRAY_SIZE(lmac_cfg->txfifo_size); i++) - mvm->smem_cfg.lmac[lmac].txfifo_size[i] = - le32_to_cpu(lmac_cfg->txfifo_size[i]); - mvm->smem_cfg.lmac[lmac].rxfifo1_size = - le32_to_cpu(lmac_cfg->rxfifo1_size); - } -} - -static void iwl_mvm_parse_shared_mem(struct iwl_mvm *mvm, - struct iwl_rx_packet *pkt) -{ - struct iwl_shared_mem_cfg_v2 *mem_cfg = (void *)pkt->data; - int i; - - mvm->smem_cfg.num_lmacs = 1; - - mvm->smem_cfg.num_txfifo_entries = ARRAY_SIZE(mem_cfg->txfifo_size); - for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) - mvm->smem_cfg.lmac[0].txfifo_size[i] = - le32_to_cpu(mem_cfg->txfifo_size[i]); - - mvm->smem_cfg.lmac[0].rxfifo1_size = - le32_to_cpu(mem_cfg->rxfifo_size[0]); - mvm->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo_size[1]); - - /* new API has more data, from rxfifo_addr field and on */ - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) { - BUILD_BUG_ON(sizeof(mvm->smem_cfg.internal_txfifo_size) != - sizeof(mem_cfg->internal_txfifo_size)); - - for (i = 0; - i < ARRAY_SIZE(mvm->smem_cfg.internal_txfifo_size); - i++) - mvm->smem_cfg.internal_txfifo_size[i] = - le32_to_cpu(mem_cfg->internal_txfifo_size[i]); - } -} - -static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm) -{ - struct iwl_host_cmd cmd = { - .flags = CMD_WANT_SKB, - .data = { NULL, }, - .len = { 0, }, - }; - struct iwl_rx_packet *pkt; - - lockdep_assert_held(&mvm->mutex); - - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG)) - cmd.id = iwl_cmd_id(SHARED_MEM_CFG_CMD, SYSTEM_GROUP, 0); - else - cmd.id = SHARED_MEM_CFG; - - if (WARN_ON(iwl_mvm_send_cmd(mvm, &cmd))) - return; - - pkt = cmd.resp_pkt; - if (iwl_mvm_has_new_tx_api(mvm)) - iwl_mvm_parse_shared_mem_a000(mvm, pkt); - else - iwl_mvm_parse_shared_mem(mvm, pkt); - - IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n"); - - iwl_free_resp(&cmd); -} - static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) { struct iwl_ltr_config_cmd cmd = { @@ -1048,8 +614,8 @@ static union acpi_object *iwl_mvm_sar_find_wifi_pkg(struct iwl_mvm *mvm, union acpi_object *data, int data_size) { + union acpi_object *wifi_pkg = NULL; int i; - union acpi_object *wifi_pkg; /* * We need at least two packages, one for the revision and one @@ -1431,6 +997,17 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) { return 0; } + +int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, + int prof_b) +{ + return -ENOENT; +} + +int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) +{ + return -ENOENT; +} #endif /* CONFIG_ACPI */ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) @@ -1467,7 +1044,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) { int ret; - if (iwl_mvm_has_new_tx_api(mvm)) + if (iwl_mvm_has_unified_ucode(mvm)) return iwl_run_unified_mvm_ucode(mvm, false); ret = iwl_run_init_mvm_ucode(mvm, false); @@ -1477,9 +1054,6 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) if (ret) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); - /* this can't happen */ - if (WARN_ON(ret > 0)) - ret = -ERFKILL; return ret; } @@ -1497,7 +1071,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) if (ret) return ret; - return iwl_mvm_init_paging(mvm); + return iwl_init_paging(&mvm->fwrt, mvm->fwrt.cur_fw_img); } int iwl_mvm_up(struct iwl_mvm *mvm) @@ -1518,24 +1092,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - iwl_mvm_get_shared_mem_conf(mvm); + iwl_get_shared_mem_conf(&mvm->fwrt); ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) IWL_ERR(mvm, "Failed to initialize Smart Fifo\n"); - mvm->fw_dbg_conf = FW_DBG_INVALID; + mvm->fwrt.dump.conf = FW_DBG_INVALID; /* if we have a destination, assume EARLY START */ if (mvm->fw->dbg_dest_tlv) - mvm->fw_dbg_conf = FW_DBG_START_FROM_ALIVE; - iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_START_FROM_ALIVE); + mvm->fwrt.dump.conf = FW_DBG_START_FROM_ALIVE; + iwl_fw_start_dbg_conf(&mvm->fwrt, FW_DBG_START_FROM_ALIVE); ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); if (ret) goto error; - /* Send phy db control command and then phy db calibration*/ - if (!iwl_mvm_has_new_tx_api(mvm)) { + if (!iwl_mvm_has_unified_ucode(mvm)) { + /* Send phy db control command and then phy db calibration */ ret = iwl_send_phy_db_data(mvm->phy_db); if (ret) goto error; @@ -1551,7 +1125,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* Init RSS configuration */ /* TODO - remove a000 disablement when we have RXQ config API */ - if (iwl_mvm_has_new_rx_api(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { + if (iwl_mvm_has_new_rx_api(mvm) && + mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_A000) { ret = iwl_send_rss_cfg_cmd(mvm); if (ret) { IWL_ERR(mvm, "Failed to configure RSS queues: %d\n", @@ -1569,14 +1144,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm) /* reset quota debouncing buffer - 0xff will yield invalid data */ memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd)); - /* Enable DQA-mode if required */ - if (iwl_mvm_is_dqa_supported(mvm)) { - ret = iwl_mvm_send_dqa_cmd(mvm); - if (ret) - goto error; - } else { - IWL_DEBUG_FW(mvm, "Working in non-DQA mode\n"); - } + ret = iwl_mvm_send_dqa_cmd(mvm); + if (ret) + goto error; /* Add auxiliary station for scanning */ ret = iwl_mvm_add_aux_sta(mvm); @@ -1611,7 +1181,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) } /* TODO: read the budget from BIOS / Platform NVM */ - if (iwl_mvm_is_ctdp_supported(mvm) && mvm->cooling_dev.cur_state > 0) { + + /* + * In case there is no budget from BIOS / Platform NVM the default + * budget should be 2000mW (cooling state 0). + */ + if (iwl_mvm_is_ctdp_supported(mvm)) { ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, mvm->cooling_dev.cur_state); if (ret) @@ -1657,6 +1232,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) goto error; + iwl_mvm_leds_sync(mvm); + IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index 3cac4278a5fd..005e2e7278a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,26 +68,45 @@ #include "iwl-csr.h" #include "mvm.h" -/* Set led register on */ -static void iwl_mvm_led_enable(struct iwl_mvm *mvm) +static void iwl_mvm_send_led_fw_cmd(struct iwl_mvm *mvm, bool on) { - iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); + struct iwl_led_cmd led_cmd = { + .status = cpu_to_le32(on), + }; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(LONG_GROUP, LEDS_CMD), + .len = { sizeof(led_cmd), }, + .data = { &led_cmd, }, + .flags = CMD_ASYNC, + }; + int err; + + if (!iwl_mvm_firmware_running(mvm)) + return; + + err = iwl_mvm_send_cmd(mvm, &cmd); + + if (err) + IWL_WARN(mvm, "LED command failed: %d\n", err); } -/* Set led register off */ -static void iwl_mvm_led_disable(struct iwl_mvm *mvm) +static void iwl_mvm_led_set(struct iwl_mvm *mvm, bool on) { - iwl_write32(mvm->trans, CSR_LED_REG, CSR_LED_REG_TURN_OFF); + if (mvm->cfg->device_family >= IWL_DEVICE_FAMILY_8000) { + iwl_mvm_send_led_fw_cmd(mvm, on); + return; + } + + iwl_write32(mvm->trans, CSR_LED_REG, + on ? CSR_LED_REG_TURN_ON : CSR_LED_REG_TURN_OFF); } static void iwl_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { struct iwl_mvm *mvm = container_of(led_cdev, struct iwl_mvm, led); - if (brightness > 0) - iwl_mvm_led_enable(mvm); - else - iwl_mvm_led_disable(mvm); + + iwl_mvm_led_set(mvm, brightness > 0); } int iwl_mvm_leds_init(struct iwl_mvm *mvm) @@ -127,10 +148,24 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) return 0; } +void iwl_mvm_leds_sync(struct iwl_mvm *mvm) +{ + if (!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE)) + return; + + /* + * if we control through the register, we're doing it + * even when the firmware isn't up, so no need to sync + */ + if (mvm->cfg->device_family < IWL_DEVICE_FAMILY_8000) + return; + + iwl_mvm_led_set(mvm, mvm->led.brightness > 0); +} + void iwl_mvm_leds_exit(struct iwl_mvm *mvm) { - if (iwlwifi_mod_params.led_mode == IWL_LED_DISABLE || - !(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE)) + if (!(mvm->init_status & IWL_MVM_INIT_STATUS_LEDS_INIT_COMPLETE)) return; led_classdev_unregister(&mvm->led); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index dc631b23e189..a2bf530eeae4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,7 +72,6 @@ #include "fw-api.h" #include "mvm.h" #include "time-event.h" -#include "fw-dbg.h" const u8 iwl_mvm_ac_to_tx_fifo[] = { IWL_MVM_TX_FIFO_VO, @@ -81,6 +80,13 @@ const u8 iwl_mvm_ac_to_tx_fifo[] = { IWL_MVM_TX_FIFO_BK, }; +const u8 iwl_mvm_ac_to_gen2_tx_fifo[] = { + IWL_GEN2_EDCA_TX_FIFO_VO, + IWL_GEN2_EDCA_TX_FIFO_VI, + IWL_GEN2_EDCA_TX_FIFO_BE, + IWL_GEN2_EDCA_TX_FIFO_BK, +}; + struct iwl_mvm_mac_iface_iterator_data { struct iwl_mvm *mvm; struct ieee80211_vif *vif; @@ -235,32 +241,17 @@ static void iwl_mvm_iface_hw_queues_iter(void *_data, u8 *mac, data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif); } -static void iwl_mvm_mac_sta_hw_queues_iter(void *_data, - struct ieee80211_sta *sta) -{ - struct iwl_mvm_hw_queues_iface_iterator_data *data = _data; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - - /* Mark the queues used by the sta */ - data->used_hw_queues |= mvmsta->tfd_queue_msk; -} - unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, struct ieee80211_vif *exclude_vif) { - u8 sta_id; struct iwl_mvm_hw_queues_iface_iterator_data data = { .exclude_vif = exclude_vif, .used_hw_queues = BIT(IWL_MVM_OFFCHANNEL_QUEUE) | - BIT(mvm->aux_queue), + BIT(mvm->aux_queue) | + BIT(IWL_MVM_DQA_GCAST_QUEUE), }; - if (iwl_mvm_is_dqa_supported(mvm)) - data.used_hw_queues |= BIT(IWL_MVM_DQA_GCAST_QUEUE); - else - data.used_hw_queues |= BIT(IWL_MVM_CMD_QUEUE); - lockdep_assert_held(&mvm->mutex); /* mark all VIF used hw queues */ @@ -268,26 +259,6 @@ unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm, mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, iwl_mvm_iface_hw_queues_iter, &data); - /* - * for DQA, the hw_queue in mac80211 is never really used for - * real traffic (only the few queue IDs covered above), so - * we can reuse the real HW queue IDs the stations use - */ - if (iwl_mvm_is_dqa_supported(mvm)) - return data.used_hw_queues; - - /* don't assign the same hw queues as TDLS stations */ - ieee80211_iterate_stations_atomic(mvm->hw, - iwl_mvm_mac_sta_hw_queues_iter, - &data); - - /* - * Some TDLS stations may be removed but are in the process of being - * drained. Don't touch their queues. - */ - for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) - data.used_hw_queues |= mvm->tfd_drained[sta_id]; - return data.used_hw_queues; } @@ -338,8 +309,7 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, NUM_TSF_IDS); } -static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) +int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_mac_iface_iterator_data data = { @@ -355,6 +325,8 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, int ret, i, queue_limit; unsigned long used_hw_queues; + lockdep_assert_held(&mvm->mutex); + /* * Allocate a MAC ID and a TSF for this MAC, along with the queues * and other resources. @@ -438,19 +410,14 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, return 0; } - if (iwl_mvm_is_dqa_supported(mvm)) { - /* - * queues in mac80211 almost entirely independent of - * the ones here - no real limit - */ - queue_limit = IEEE80211_MAX_QUEUES; - BUILD_BUG_ON(IEEE80211_MAX_QUEUES > - BITS_PER_BYTE * - sizeof(mvm->hw_queue_to_mac80211[0])); - } else { - /* need to not use too many in this case */ - queue_limit = mvm->first_agg_queue; - } + /* + * queues in mac80211 almost entirely independent of + * the ones here - no real limit + */ + queue_limit = IEEE80211_MAX_QUEUES; + BUILD_BUG_ON(IEEE80211_MAX_QUEUES > + BITS_PER_BYTE * + sizeof(mvm->hw_queue_to_mac80211[0])); /* * Find available queues, and allocate them to the ACs. When in @@ -472,27 +439,12 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, /* Allocate the CAB queue for softAP and GO interfaces */ if (vif->type == NL80211_IFTYPE_AP) { - u8 queue; - - if (!iwl_mvm_is_dqa_supported(mvm)) { - queue = find_first_zero_bit(&used_hw_queues, - mvm->first_agg_queue); - - if (queue >= mvm->first_agg_queue) { - IWL_ERR(mvm, "Failed to allocate cab queue\n"); - ret = -EIO; - goto exit_fail; - } - } else { - queue = IWL_MVM_DQA_GCAST_QUEUE; - } - /* * For TVQM this will be overwritten later with the FW assigned * queue value (when queue is enabled). */ - mvmvif->cab_queue = queue; - vif->cab_queue = queue; + mvmvif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; + vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE; } else { vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; } @@ -513,78 +465,6 @@ exit_fail: return ret; } -int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, vif, false, false); - u32 ac; - int ret; - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_mac_ctxt_allocate_resources(mvm, vif); - if (ret) - return ret; - - /* If DQA is supported - queues will be enabled when needed */ - if (iwl_mvm_is_dqa_supported(mvm)) - return 0; - - switch (vif->type) { - case NL80211_IFTYPE_P2P_DEVICE: - iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MVM_TX_FIFO_VO, 0, wdg_timeout); - break; - case NL80211_IFTYPE_AP: - iwl_mvm_enable_ac_txq(mvm, vif->cab_queue, vif->cab_queue, - IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); - /* fall through */ - default: - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac], - vif->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac], 0, - wdg_timeout); - break; - } - - return 0; -} - -void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - int ac; - - lockdep_assert_held(&mvm->mutex); - - /* - * If DQA is supported - queues were already disabled, since in - * DQA-mode the queues are a property of the STA and not of the - * vif, and at this point the STA was already deleted - */ - if (iwl_mvm_is_dqa_supported(mvm)) - return; - - switch (vif->type) { - case NL80211_IFTYPE_P2P_DEVICE: - iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MVM_OFFCHANNEL_QUEUE, - IWL_MAX_TID_COUNT, 0); - - break; - case NL80211_IFTYPE_AP: - iwl_mvm_disable_txq(mvm, vif->cab_queue, vif->cab_queue, - IWL_MAX_TID_COUNT, 0); - /* fall through */ - default: - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - iwl_mvm_disable_txq(mvm, vif->hw_queue[ac], - vif->hw_queue[ac], - IWL_MAX_TID_COUNT, 0); - } -} - static void iwl_mvm_ack_rates(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum nl80211_band band, @@ -775,7 +655,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP); for (i = 0; i < IEEE80211_NUM_ACS; i++) { - u8 txf = iwl_mvm_ac_to_tx_fifo[i]; + u8 txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, i); cmd->ac[txf].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min); @@ -908,18 +788,12 @@ static int iwl_mvm_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, { struct iwl_mac_ctx_cmd cmd = {}; u32 tfd_queue_msk = 0; - int ret, i; + int ret; WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action); - if (!iwl_mvm_is_dqa_supported(mvm)) { - for (i = 0; i < IEEE80211_NUM_ACS; i++) - if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) - tfd_queue_msk |= BIT(vif->hw_queue[i]); - } - cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC | MAC_FILTER_IN_CONTROL_AND_MGMT | MAC_FILTER_IN_BEACON | @@ -1049,83 +923,40 @@ static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size) return ie - beacon; } -static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct sk_buff *beacon) +static u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, + struct ieee80211_vif *vif) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_host_cmd cmd = { - .id = BEACON_TEMPLATE_CMD, - .flags = CMD_ASYNC, - }; - union { - struct iwl_mac_beacon_cmd_v6 beacon_cmd_v6; - struct iwl_mac_beacon_cmd_v7 beacon_cmd; - } u = {}; - struct iwl_mac_beacon_cmd beacon_cmd = {}; - struct ieee80211_tx_info *info; - u32 beacon_skb_len; - u32 rate, tx_flags; + u8 rate; - if (WARN_ON(!beacon)) - return -EINVAL; + if (info->band == NL80211_BAND_5GHZ || vif->p2p) + rate = IWL_FIRST_OFDM_RATE; + else + rate = IWL_FIRST_CCK_RATE; - beacon_skb_len = beacon->len; - - if (fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD)) { - u32 csa_offset, ecsa_offset; - - csa_offset = iwl_mvm_find_ie_offset(beacon->data, - WLAN_EID_CHANNEL_SWITCH, - beacon_skb_len); - ecsa_offset = - iwl_mvm_find_ie_offset(beacon->data, - WLAN_EID_EXT_CHANSWITCH_ANN, - beacon_skb_len); - - if (iwl_mvm_has_new_tx_api(mvm)) { - beacon_cmd.data.template_id = - cpu_to_le32((u32)mvmvif->id); - beacon_cmd.data.ecsa_offset = cpu_to_le32(ecsa_offset); - beacon_cmd.data.csa_offset = cpu_to_le32(csa_offset); - beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon_skb_len); - if (vif->type == NL80211_IFTYPE_AP) - iwl_mvm_mac_ctxt_set_tim(mvm, - &beacon_cmd.data.tim_idx, - &beacon_cmd.data.tim_size, - beacon->data, - beacon_skb_len); - cmd.len[0] = sizeof(beacon_cmd); - cmd.data[0] = &beacon_cmd; - goto send; + return rate; +} - } else { - u.beacon_cmd.data.ecsa_offset = - cpu_to_le32(ecsa_offset); - u.beacon_cmd.data.csa_offset = cpu_to_le32(csa_offset); - cmd.len[0] = sizeof(u.beacon_cmd); - cmd.data[0] = &u; - } - } else { - cmd.len[0] = sizeof(u.beacon_cmd_v6); - cmd.data[0] = &u; - } +static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon, + struct iwl_tx_cmd *tx) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_tx_info *info; + u8 rate; + u32 tx_flags; - /* TODO: for now the beacon template id is set to be the mac context id. - * Might be better to handle it as another resource ... */ - u.beacon_cmd_v6.template_id = cpu_to_le32((u32)mvmvif->id); info = IEEE80211_SKB_CB(beacon); /* Set up TX command fields */ - u.beacon_cmd_v6.tx.len = cpu_to_le16((u16)beacon_skb_len); - u.beacon_cmd_v6.tx.sta_id = mvmvif->bcast_sta.sta_id; - u.beacon_cmd_v6.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); + tx->len = cpu_to_le16((u16)beacon->len); + tx->sta_id = mvmvif->bcast_sta.sta_id; + tx->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF; tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) << TX_CMD_FLG_BT_PRIO_POS; - u.beacon_cmd_v6.tx.tx_flags = cpu_to_le32(tx_flags); + tx->tx_flags = cpu_to_le32(tx_flags); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) { @@ -1134,37 +965,141 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, mvm->mgmt_last_antenna_idx); } - u.beacon_cmd_v6.tx.rate_n_flags = + tx->rate_n_flags = cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS); - if (info->band == NL80211_BAND_5GHZ || vif->p2p) { - rate = IWL_FIRST_OFDM_RATE; - } else { - rate = IWL_FIRST_CCK_RATE; - u.beacon_cmd_v6.tx.rate_n_flags |= - cpu_to_le32(RATE_MCS_CCK_MSK); - } - u.beacon_cmd_v6.tx.rate_n_flags |= - cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); + rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif); - /* Set up TX beacon command fields */ - if (vif->type == NL80211_IFTYPE_AP) - iwl_mvm_mac_ctxt_set_tim(mvm, &u.beacon_cmd_v6.tim_idx, - &u.beacon_cmd_v6.tim_size, - beacon->data, - beacon_skb_len); + tx->rate_n_flags |= cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate)); + if (rate == IWL_FIRST_CCK_RATE) + tx->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK); + +} -send: - /* Submit command */ +static int iwl_mvm_mac_ctxt_send_beacon_cmd(struct iwl_mvm *mvm, + struct sk_buff *beacon, + void *data, int len) +{ + struct iwl_host_cmd cmd = { + .id = BEACON_TEMPLATE_CMD, + .flags = CMD_ASYNC, + }; + + cmd.len[0] = len; + cmd.data[0] = data; cmd.dataflags[0] = 0; - cmd.len[1] = beacon_skb_len; + cmd.len[1] = beacon->len; cmd.data[1] = beacon->data; cmd.dataflags[1] = IWL_HCMD_DFL_DUP; return iwl_mvm_send_cmd(mvm, &cmd); } +static int iwl_mvm_mac_ctxt_send_beacon_v6(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mac_beacon_cmd_v6 beacon_cmd = {}; + + iwl_mvm_mac_ctxt_set_tx(mvm, vif, beacon, &beacon_cmd.tx); + + beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); + + if (vif->type == NL80211_IFTYPE_AP) + iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx, + &beacon_cmd.tim_size, + beacon->data, beacon->len); + + return iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd, + sizeof(beacon_cmd)); +} + +static int iwl_mvm_mac_ctxt_send_beacon_v7(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mac_beacon_cmd_v7 beacon_cmd = {}; + + iwl_mvm_mac_ctxt_set_tx(mvm, vif, beacon, &beacon_cmd.tx); + + beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); + + if (vif->type == NL80211_IFTYPE_AP) + iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx, + &beacon_cmd.tim_size, + beacon->data, beacon->len); + + beacon_cmd.csa_offset = + cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_CHANNEL_SWITCH, + beacon->len)); + beacon_cmd.ecsa_offset = + cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_EXT_CHANSWITCH_ANN, + beacon->len)); + + return iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd, + sizeof(beacon_cmd)); +} + +static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(beacon); + struct iwl_mac_beacon_cmd beacon_cmd = {}; + u8 rate = iwl_mvm_mac_ctxt_get_lowest_rate(info, vif); + u16 flags; + + flags = iwl_mvm_mac80211_idx_to_hwrate(rate); + + if (rate == IWL_FIRST_CCK_RATE) + flags |= IWL_MAC_BEACON_CCK; + + beacon_cmd.flags = cpu_to_le16(flags); + beacon_cmd.byte_cnt = cpu_to_le16((u16)beacon->len); + beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id); + + if (vif->type == NL80211_IFTYPE_AP) + iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd.tim_idx, + &beacon_cmd.tim_size, + beacon->data, beacon->len); + + beacon_cmd.csa_offset = + cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_CHANNEL_SWITCH, + beacon->len)); + beacon_cmd.ecsa_offset = + cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_EXT_CHANSWITCH_ANN, + beacon->len)); + + return iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd, + sizeof(beacon_cmd)); +} + +static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct sk_buff *beacon) +{ + if (WARN_ON(!beacon)) + return -EINVAL; + + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD)) + return iwl_mvm_mac_ctxt_send_beacon_v6(mvm, vif, beacon); + + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE)) + return iwl_mvm_mac_ctxt_send_beacon_v9(mvm, vif, beacon); + + return iwl_mvm_mac_ctxt_send_beacon_v7(mvm, vif, beacon); +} + /* The beacon template for the AP/GO/IBSS has changed and needs update */ int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -1559,12 +1494,14 @@ static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, /* TODO: implement start trigger */ - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), + trigger)) return; if (rx_missed_bcon_since_rx >= stop_trig_missed_bcon_since_rx || rx_missed_bcon >= stop_trig_missed_bcon) - iwl_mvm_fw_dbg_collect_trig(mvm, trigger, NULL); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trigger, NULL); } void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ce901be5fba8..15f2d826bb4b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -87,7 +87,6 @@ #include "fw/error-dump.h" #include "iwl-prph.h" #include "iwl-nvm-parse.h" -#include "fw-dbg.h" static const struct ieee80211_iface_limit iwl_mvm_limits[] = { { @@ -446,8 +445,18 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); if (iwl_mvm_has_new_rx_api(mvm)) ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_STA_PM_NOTIF)) + + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_STA_PM_NOTIF)) { ieee80211_hw_set(hw, AP_LINK_PS); + } else if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) { + /* + * we absolutely need this for the new TX API since that comes + * with many more queues than the current code can deal with + * for station powersave + */ + return -EINVAL; + } if (mvm->trans->num_rx_queues > 1) ieee80211_hw_set(hw, USES_RSS); @@ -455,10 +464,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) if (mvm->trans->max_skb_frags) hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG; - if (!iwl_mvm_is_dqa_supported(mvm)) - hw->queues = mvm->first_agg_queue; - else - hw->queues = IEEE80211_MAX_QUEUES; + hw->queues = IEEE80211_MAX_QUEUES; hw->offchannel_tx_hw_queue = IWL_MVM_OFFCHANNEL_QUEUE; hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC | IEEE80211_RADIOTAP_MCS_HAVE_STBC; @@ -799,17 +805,16 @@ static void iwl_mvm_mac_tx(struct ieee80211_hw *hw, goto drop; } - if (IEEE80211_SKB_CB(skb)->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && + if (info->hw_queue == IWL_MVM_OFFCHANNEL_QUEUE && !test_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status) && !test_bit(IWL_MVM_STATUS_ROC_AUX_RUNNING, &mvm->status)) goto drop; - /* treat non-bufferable MMPDUs as broadcast if sta is sleeping */ - if (unlikely(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER && - ieee80211_is_mgmt(hdr->frame_control) && - !ieee80211_is_deauth(hdr->frame_control) && - !ieee80211_is_disassoc(hdr->frame_control) && - !ieee80211_is_action(hdr->frame_control))) + /* treat non-bufferable MMPDUs on AP interfaces as broadcast */ + if ((info->control.vif->type == NL80211_IFTYPE_AP || + info->control.vif->type == NL80211_IFTYPE_ADHOC) && + ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) sta = NULL; if (sta) { @@ -845,11 +850,11 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg) return true; } -#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \ - do { \ - if (!(le16_to_cpu(_tid_bm) & BIT(_tid))) \ - break; \ - iwl_mvm_fw_dbg_collect_trig(_mvm, _trig, _fmt); \ +#define CHECK_BA_TRIGGER(_mvm, _trig, _tid_bm, _tid, _fmt...) \ + do { \ + if (!(le16_to_cpu(_tid_bm) & BIT(_tid))) \ + break; \ + iwl_fw_dbg_collect_trig(&(_mvm)->fwrt, _trig, _fmt); \ } while (0) static void @@ -866,7 +871,8 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) return; switch (action) { @@ -1029,8 +1035,8 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) * on D3->D0 transition */ if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) { - mvm->fw_dump_desc = &iwl_mvm_dump_desc_assert; - iwl_mvm_fw_error_dump(mvm); + mvm->fwrt.dump.desc = &iwl_dump_desc_assert; + iwl_fw_error_dump(&mvm->fwrt); } /* cleanup all stale references (scan, roc), but keep the @@ -1059,9 +1065,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) iwl_mvm_reset_phy_ctxts(mvm); memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); - memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames)); - memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained)); memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); @@ -1072,7 +1076,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) mvm->vif_count = 0; mvm->rx_ba_sessions = 0; - mvm->fw_dbg_conf = FW_DBG_INVALID; + mvm->fwrt.dump.conf = FW_DBG_INVALID; /* keep statistics ticking */ iwl_mvm_accu_radio_stats(mvm); @@ -1255,16 +1259,16 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) * Lock and clear the firmware running bit here already, so that * new commands coming in elsewhere, e.g. from debugfs, will not * be able to proceed. This is important here because one of those - * debugfs files causes the fw_dump_wk to be triggered, and if we + * debugfs files causes the firmware dump to be triggered, and if we * don't stop debugfs accesses before canceling that it could be * retriggered after we flush it but before we've cleared the bit. */ clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); - cancel_delayed_work_sync(&mvm->fw_dump_wk); + iwl_fw_cancel_dump(&mvm->fwrt); cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork); cancel_delayed_work_sync(&mvm->scan_timeout_dwork); - iwl_mvm_free_fw_dump_desc(mvm); + iwl_fw_free_dump_desc(&mvm->fwrt); mutex_lock(&mvm->mutex); __iwl_mvm_mac_stop(mvm); @@ -1370,17 +1374,15 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, goto out_release; } - if (iwl_mvm_is_dqa_supported(mvm)) { - /* - * Only queue for this station is the mcast queue, - * which shouldn't be in TFD mask anyway - */ - ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->mcast_sta, - 0, vif->type, - IWL_STA_MULTICAST); - if (ret) - goto out_release; - } + /* + * Only queue for this station is the mcast queue, + * which shouldn't be in TFD mask anyway + */ + ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->mcast_sta, + 0, vif->type, + IWL_STA_MULTICAST); + if (ret) + goto out_release; iwl_mvm_vif_dbgfs_register(mvm, vif); goto out_unlock; @@ -1426,7 +1428,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, if (ret) goto out_unref_phy; - ret = iwl_mvm_add_bcast_sta(mvm, vif); + ret = iwl_mvm_add_p2p_bcast_sta(mvm, vif); if (ret) goto out_unbind; @@ -1454,8 +1456,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, out_release: if (vif->type != NL80211_IFTYPE_P2P_DEVICE) mvm->vif_count--; - - iwl_mvm_mac_ctxt_release(mvm, vif); out_unlock: mutex_unlock(&mvm->mutex); @@ -1467,40 +1467,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { - u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif); - - if (tfd_msk && !iwl_mvm_is_dqa_supported(mvm)) { - /* - * mac80211 first removes all the stations of the vif and - * then removes the vif. When it removes a station it also - * flushes the AMPDU session. So by now, all the AMPDU sessions - * of all the stations of this vif are closed, and the queues - * of these AMPDU sessions are properly closed. - * We still need to take care of the shared queues of the vif. - * Flush them here. - * For DQA mode there is no need - broacast and multicast queue - * are flushed separately. - */ - mutex_lock(&mvm->mutex); - iwl_mvm_flush_tx_path(mvm, tfd_msk, 0); - mutex_unlock(&mvm->mutex); - - /* - * There are transports that buffer a few frames in the host. - * For these, the flush above isn't enough since while we were - * flushing, the transport might have sent more frames to the - * device. To solve this, wait here until the transport is - * empty. Technically, this could have replaced the flush - * above, but flush is much faster than draining. So flush - * first, and drain to make sure we have no frames in the - * transport anymore. - * If a station still had frames on the shared queues, it is - * already marked as draining, so to complete the draining, we - * just need to wait until the transport is empty. - */ - iwl_trans_wait_tx_queues_empty(mvm->trans, tfd_msk); - } - if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { /* * Flush the ROC worker which will flush the OFFCHANNEL queue. @@ -1508,14 +1474,6 @@ static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, * queue are sent in ROC session. */ flush_work(&mvm->roc_done_wk); - } else { - /* - * By now, all the AC queues are empty. The AGG queues are - * empty too. We already got all the Tx responses for all the - * packets in the queues. The drain work can have been - * triggered. Flush it. - */ - flush_work(&mvm->sta_drained_wk); } } @@ -1556,7 +1514,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { mvm->p2p_device_vif = NULL; - iwl_mvm_rm_bcast_sta(mvm, vif); + iwl_mvm_rm_p2p_bcast_sta(mvm, vif); iwl_mvm_binding_remove_vif(mvm, vif); iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt); mvmvif->phy_ctxt = NULL; @@ -1569,7 +1527,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, iwl_mvm_mac_ctxt_remove(mvm, vif); out_release: - iwl_mvm_mac_ctxt_release(mvm, vif); mutex_unlock(&mvm->mutex); } @@ -2067,8 +2024,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * We received a beacon from the associated AP so * remove the session protection. */ - iwl_mvm_remove_time_event(mvm, mvmvif, - &mvmvif->time_event_data); + iwl_mvm_stop_session_protection(mvm, vif); iwl_mvm_sf_update(mvm, vif, false); WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); @@ -2405,15 +2361,18 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, unsigned long txqs = 0, tids = 0; int tid; + /* + * If we have TVQM then we get too high queue numbers - luckily + * we really shouldn't get here with that because such hardware + * should have firmware supporting buffer station offload. + */ + if (WARN_ON(iwl_mvm_has_new_tx_api(mvm))) + return; + spin_lock_bh(&mvmsta->lock); for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; - if (!iwl_mvm_is_dqa_supported(mvm) && - tid_data->state != IWL_AGG_ON && - tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) - continue; - if (tid_data->txq_id == IWL_MVM_INVALID_QUEUE) continue; @@ -2427,9 +2386,6 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, switch (cmd) { case STA_NOTIFY_SLEEP: - if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) - ieee80211_sta_block_awake(hw, sta, true); - for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT) ieee80211_sta_set_buffered(sta, tid, true); @@ -2572,7 +2528,8 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TDLS); tdls_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) return; if (!(tdls_trig->action_bitmap & BIT(action))) @@ -2582,9 +2539,9 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm, memcmp(tdls_trig->peer, peer_addr, ETH_ALEN) != 0) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "TDLS event occurred, peer %pM, action %d", - peer_addr, action); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "TDLS event occurred, peer %pM, action %d", + peer_addr, action); } static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm, @@ -2631,9 +2588,6 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, if (WARN_ON_ONCE(!mvmvif->phy_ctxt)) return -EINVAL; - /* if a STA is being removed, reuse its ID */ - flush_work(&mvm->sta_drained_wk); - /* * If we are in a STA removal flow and in DQA mode: * @@ -2648,8 +2602,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, * make sure the worker is no longer handling frames for this STA. */ if (old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST && - iwl_mvm_is_dqa_supported(mvm)) { + new_state == IEEE80211_STA_NOTEXIST) { iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta); flush_work(&mvm->add_stream_wk); @@ -3892,7 +3845,9 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "pre CSA to freq %d\n", chsw->chandef.center_freq1); - iwl_fw_dbg_trigger_simple_stop(mvm, vif, FW_DBG_TRIGGER_CHANNEL_SWITCH); + iwl_fw_dbg_trigger_simple_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), + FW_DBG_TRIGGER_CHANNEL_SWITCH); switch (vif->type) { case NL80211_IFTYPE_AP: @@ -3931,11 +3886,16 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, /* Schedule the time event to a bit before beacon 1, * to make sure we're in the new channel when the - * GO/AP arrives. + * GO/AP arrives. In case count <= 1 immediately schedule the + * TE (this might result with some packet loss or connection + * loss). */ - apply_time = chsw->device_timestamp + - ((vif->bss_conf.beacon_int * (chsw->count - 1) - - IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024); + if (chsw->count <= 1) + apply_time = 0; + else + apply_time = chsw->device_timestamp + + ((vif->bss_conf.beacon_int * (chsw->count - 1) - + IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024); if (chsw->block_tx) iwl_mvm_csa_client_absent(mvm, vif); @@ -4029,8 +3989,7 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw, return; /* Make sure we're done with the deferred traffic before flushing */ - if (iwl_mvm_is_dqa_supported(mvm)) - flush_work(&mvm->add_stream_wk); + flush_work(&mvm->add_stream_wk); mutex_lock(&mvm->mutex); mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -4167,11 +4126,11 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const struct ieee80211_event *event) { -#define CHECK_MLME_TRIGGER(_cnt, _fmt...) \ - do { \ - if ((trig_mlme->_cnt) && --(trig_mlme->_cnt)) \ - break; \ - iwl_mvm_fw_dbg_collect_trig(mvm, trig, _fmt); \ +#define CHECK_MLME_TRIGGER(_cnt, _fmt...) \ + do { \ + if ((trig_mlme->_cnt) && --(trig_mlme->_cnt)) \ + break; \ + iwl_fw_dbg_collect_trig(&(mvm)->fwrt, trig, _fmt); \ } while (0) struct iwl_fw_dbg_trigger_tlv *trig; @@ -4182,7 +4141,8 @@ static void iwl_mvm_event_mlme_callback(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME); trig_mlme = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) return; if (event->u.mlme.data == ASSOC_EVENT) { @@ -4223,16 +4183,17 @@ static void iwl_mvm_event_bar_rx_callback(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) return; if (!(le16_to_cpu(ba_trig->rx_bar) & BIT(event->u.ba.tid))) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "BAR received from %pM, tid %d, ssn %d", - event->u.ba.sta->addr, event->u.ba.tid, - event->u.ba.ssn); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "BAR received from %pM, tid %d, ssn %d", + event->u.ba.sta->addr, event->u.ba.tid, + event->u.ba.ssn); } static void @@ -4248,15 +4209,16 @@ iwl_mvm_event_frame_timeout_callback(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) return; if (!(le16_to_cpu(ba_trig->frame_timeout) & BIT(event->u.ba.tid))) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "Frame from %pM timed out, tid %d", - event->u.ba.sta->addr, event->u.ba.tid); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "Frame from %pM timed out, tid %d", + event->u.ba.sta->addr, event->u.ba.tid); } static void iwl_mvm_mac_event_callback(struct ieee80211_hw *hw, @@ -4290,7 +4252,8 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); /* TODO - remove a000 disablement when we have RXQ config API */ - if (!iwl_mvm_has_new_rx_api(mvm) || iwl_mvm_has_new_tx_api(mvm)) + if (!iwl_mvm_has_new_rx_api(mvm) || + mvm->trans->cfg->device_family == IWL_DEVICE_FAMILY_A000) return; notif->cookie = mvm->queue_sync_cookie; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ddd8719f27b8..83303bac0e4b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -87,6 +87,8 @@ #include "fw-api.h" #include "constants.h" #include "tof.h" +#include "fw/runtime.h" +#include "fw/dbg.h" #define IWL_MVM_MAX_ADDRESSES 5 /* RSSI offset for WkP */ @@ -119,6 +121,9 @@ */ #define IWL_MVM_CS_UNBLOCK_TX_TIMEOUT 3 +/* offchannel queue towards mac80211 */ +#define IWL_MVM_OFFCHANNEL_QUEUE 0 + extern const struct ieee80211_ops iwl_mvm_hw_ops; /** @@ -137,34 +142,6 @@ struct iwl_mvm_mod_params { }; extern struct iwl_mvm_mod_params iwlmvm_mod_params; -/** - * struct iwl_mvm_dump_ptrs - set of pointers needed for the fw-error-dump - * - * @op_mode_ptr: pointer to the buffer coming from the mvm op_mode - * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the - * transport's data. - * @trans_len: length of the valid data in trans_ptr - * @op_mode_len: length of the valid data in op_mode_ptr - */ -struct iwl_mvm_dump_ptrs { - struct iwl_trans_dump_data *trans_ptr; - void *op_mode_ptr; - u32 op_mode_len; -}; - -/** - * struct iwl_mvm_dump_desc - describes the dump - * @len: length of trig_desc->data - * @trig_desc: the description of the dump - */ -struct iwl_mvm_dump_desc { - size_t len; - /* must be last */ - struct iwl_fw_error_dump_trigger_desc trig_desc; -}; - -extern const struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert; - struct iwl_mvm_phy_ctxt { u16 id; u16 color; @@ -606,19 +583,6 @@ enum iwl_mvm_tdls_cs_state { IWL_MVM_TDLS_SW_ACTIVE, }; -#define MAX_NUM_LMAC 2 -struct iwl_mvm_shared_mem_cfg { - int num_lmacs; - int num_txfifo_entries; - struct { - u32 txfifo_size[TX_FIFO_MAX_NUM]; - u32 rxfifo1_size; - } lmac[MAX_NUM_LMAC]; - u32 rxfifo2_size; - u32 internal_txfifo_addr; - u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM]; -}; - /** * struct iwl_mvm_reorder_buffer - per ra/tid/queue reorder buffer * @head_sn: reorder window head sn @@ -766,7 +730,6 @@ struct iwl_mvm { */ struct iwl_mvm_vif *bf_allowed_vif; - enum iwl_ucode_type cur_ucode; bool hw_registered; bool calibrating; u32 error_event_table[2]; @@ -815,10 +778,7 @@ struct iwl_mvm { /* NVM sections */ struct iwl_nvm_section nvm_sections[NVM_MAX_NUM_SECTIONS]; - /* Paging section */ - struct iwl_fw_paging fw_paging_db[NUM_OF_FW_PAGING_BLOCKS]; - u16 num_of_paging_blk; - u16 num_of_pages_in_last_blk; + struct iwl_fw_runtime fwrt; /* EEPROM MAC addresses */ struct mac_address addresses[IWL_MVM_MAX_ADDRESSES]; @@ -826,11 +786,7 @@ struct iwl_mvm { /* data related to data path */ struct iwl_rx_phy_info last_phy_info; struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT]; - struct work_struct sta_drained_wk; unsigned long sta_deferred_frames[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; - unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; - atomic_t pending_frames[IWL_MVM_STATION_COUNT]; - u32 tfd_drained[IWL_MVM_STATION_COUNT]; u8 rx_ba_sessions; /* configured by mac80211 */ @@ -847,9 +803,6 @@ struct iwl_mvm { /* max number of simultaneous scans the FW supports */ unsigned int max_scans; - /* ts of the beginning of a non-collect fw dbg data period */ - unsigned long fw_dbg_non_collect_ts_start[FW_DBG_TRIGGER_MAX - 1]; - /* UMAC scan tracking */ u32 scan_uid_status[IWL_MVM_MAX_UMAC_SCANS]; @@ -925,10 +878,6 @@ struct iwl_mvm { /* -1 for always, 0 for never, >0 for that many times */ s8 fw_restart; - u8 fw_dbg_conf; - struct delayed_work fw_dump_wk; - const struct iwl_mvm_dump_desc *fw_dump_desc; - const struct iwl_fw_dbg_trigger_tlv *fw_dump_trig; #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; @@ -975,8 +924,6 @@ struct iwl_mvm { struct iwl_bt_coex_profile_notif last_bt_notif; struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; - u32 last_ant_isol; - u8 last_corun_lut; u8 bt_tx_prio; enum iwl_bt_force_ant_mode bt_force_ant_mode; @@ -1010,9 +957,6 @@ struct iwl_mvm { u16 probe_queue; u16 p2p_dev_queue; - u8 first_agg_queue; - u8 last_agg_queue; - /* Indicate if device power save is allowed */ u8 ps_disabled; /* u8 instead of bool to ease debugfs_create_* usage */ unsigned int max_amsdu_len; /* used for debugfs only */ @@ -1055,7 +999,6 @@ struct iwl_mvm { } peer; } tdls_cs; - struct iwl_mvm_shared_mem_cfg smem_cfg; u32 ciphers[IWL_MVM_NUM_CIPHERS]; struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS]; @@ -1095,7 +1038,6 @@ struct iwl_mvm { * @IWL_MVM_STATUS_IN_D0I3: NIC is in D0i3 * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running * @IWL_MVM_STATUS_D3_RECONFIG: D3 reconfiguration is being done - * @IWL_MVM_STATUS_DUMPING_FW_LOG: FW log is being dumped * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running */ enum iwl_mvm_status { @@ -1107,7 +1049,6 @@ enum iwl_mvm_status { IWL_MVM_STATUS_IN_D0I3, IWL_MVM_STATUS_ROC_AUX_RUNNING, IWL_MVM_STATUS_D3_RECONFIG, - IWL_MVM_STATUS_DUMPING_FW_LOG, IWL_MVM_STATUS_FIRMWARE_RUNNING, }; @@ -1180,12 +1121,6 @@ static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_D0I3_SUPPORT); } -static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm) -{ - return fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_DQA_SUPPORT); -} - static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) { /* For now we only use this mode to differentiate between @@ -1238,13 +1173,6 @@ static inline bool iwl_mvm_is_wifi_mcc_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC); } -static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm) -{ - return fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) && - IWL_MVM_BT_COEX_CORUNNING; -} - static inline bool iwl_mvm_bt_is_rrc_supported(struct iwl_mvm *mvm) { return fw_has_capa(&mvm->fw->ucode_capa, @@ -1287,6 +1215,12 @@ static inline bool iwl_mvm_has_new_tx_api(struct iwl_mvm *mvm) return mvm->trans->cfg->use_tfh; } +static inline bool iwl_mvm_has_unified_ucode(struct iwl_mvm *mvm) +{ + /* TODO - better define this */ + return mvm->trans->cfg->device_family >= IWL_DEVICE_FAMILY_A000; +} + static inline bool iwl_mvm_is_cdb_supported(struct iwl_mvm *mvm) { /* @@ -1308,6 +1242,12 @@ static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_NEW_RX_STATS); } +static inline bool iwl_mvm_has_new_ats_coex_api(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_COEX_ATS_EXTERNAL); +} + static inline struct agg_tx_status * iwl_mvm_get_agg_status(struct iwl_mvm *mvm, void *tx_resp) { @@ -1340,6 +1280,14 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm) } extern const u8 iwl_mvm_ac_to_tx_fifo[]; +extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[]; + +static inline u8 iwl_mvm_mac_ac_to_tx_fifo(struct iwl_mvm *mvm, + enum ieee80211_ac_numbers ac) +{ + return iwl_mvm_has_new_tx_api(mvm) ? + iwl_mvm_ac_to_gen2_tx_fifo[ac] : iwl_mvm_ac_to_tx_fifo[ac]; +} struct iwl_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ @@ -1425,8 +1373,7 @@ int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear); void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm); /* NVM */ -int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic); -int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm); +int iwl_nvm_init(struct iwl_mvm *mvm); int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm); int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm); @@ -1510,7 +1457,6 @@ u8 iwl_mvm_get_ctrl_pos(struct cfg80211_chan_def *chandef); /* MAC (virtual interface) programming */ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool force_assoc_off, const u8 *bssid_override); @@ -1573,9 +1519,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); -/* Paging */ -void iwl_free_fw_paging(struct iwl_mvm *mvm); - /* MVM debugfs */ #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); @@ -1619,6 +1562,7 @@ void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm, #ifdef CONFIG_IWLWIFI_LEDS int iwl_mvm_leds_init(struct iwl_mvm *mvm); void iwl_mvm_leds_exit(struct iwl_mvm *mvm); +void iwl_mvm_leds_sync(struct iwl_mvm *mvm); #else static inline int iwl_mvm_leds_init(struct iwl_mvm *mvm) { @@ -1627,6 +1571,9 @@ static inline int iwl_mvm_leds_init(struct iwl_mvm *mvm) static inline void iwl_mvm_leds_exit(struct iwl_mvm *mvm) { } +static inline void iwl_mvm_leds_sync(struct iwl_mvm *mvm) +{ +} #endif /* D3 (WoWLAN, NetDetect) */ @@ -1764,10 +1711,6 @@ bool iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, int iwl_mvm_tvqm_enable_txq(struct iwl_mvm *mvm, int mac80211_queue, u8 sta_id, u8 tid, unsigned int timeout); -/* - * Disable a TXQ. - * Note that in non-DQA mode the %mac80211_queue and %tid params are ignored. - */ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, u8 tid, u8 flags); int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq); @@ -1777,33 +1720,15 @@ int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq); */ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm) { - u32 cmd_queue = iwl_mvm_is_dqa_supported(mvm) ? IWL_MVM_DQA_CMD_QUEUE : - IWL_MVM_CMD_QUEUE; - return ((BIT(mvm->cfg->base_params->num_of_queues) - 1) & - ~BIT(cmd_queue)); -} - -static inline -void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, - u8 fifo, u16 ssn, unsigned int wdg_timeout) -{ - struct iwl_trans_txq_scd_cfg cfg = { - .fifo = fifo, - .tid = IWL_MAX_TID_COUNT, - .aggregate = false, - .frame_limit = IWL_FRAME_LIMIT, - }; - - iwl_mvm_enable_txq(mvm, queue, mac80211_queue, ssn, &cfg, wdg_timeout); + ~BIT(IWL_MVM_DQA_CMD_QUEUE)); } static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { - if (!iwl_mvm_has_new_tx_api(mvm)) - iwl_free_fw_paging(mvm); + iwl_free_fw_paging(&mvm->fwrt); clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); - mvm->fw_dbg_conf = FW_DBG_INVALID; + iwl_fw_dump_conf_clear(&mvm->fwrt); iwl_trans_stop_device(mvm->trans); } @@ -1826,6 +1751,7 @@ void iwl_mvm_thermal_exit(struct iwl_mvm *mvm); void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state); int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp); void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm); int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm); int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget); @@ -1899,21 +1825,7 @@ int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif, u32 duration, u32 timeout); bool iwl_mvm_lqm_active(struct iwl_mvm *mvm); -#ifdef CONFIG_ACPI int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b); int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm); -#else -static inline -int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) -{ - return -ENOENT; -} - -static inline -int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) -{ - return -ENOENT; -} -#endif /* CONFIG_ACPI */ #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index dac7e542a190..422aa6be9932 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -292,7 +292,8 @@ static struct iwl_nvm_data * iwl_parse_nvm_sections(struct iwl_mvm *mvm) { struct iwl_nvm_section *sections = mvm->nvm_sections; - const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku; + const __be16 *hw; + const __le16 *sw, *calib, *regulatory, *mac_override, *phy_sku; bool lar_enabled; /* Checking for required sections */ @@ -326,10 +327,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm) } } - if (WARN_ON(!mvm->cfg)) - return NULL; - - hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data; + hw = (const __be16 *)sections[mvm->cfg->nvm_hw_section_num].data; sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data; calib = (const __le16 *)sections[NVM_SECTION_TYPE_CALIBRATION].data; regulatory = (const __le16 *)sections[NVM_SECTION_TYPE_REGULATORY].data; @@ -546,101 +544,7 @@ int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm) return ret; } -int iwl_mvm_nvm_get_from_fw(struct iwl_mvm *mvm) -{ - struct iwl_nvm_get_info cmd = {}; - struct iwl_nvm_get_info_rsp *rsp; - struct iwl_trans *trans = mvm->trans; - struct iwl_host_cmd hcmd = { - .flags = CMD_WANT_SKB | CMD_SEND_IN_RFKILL, - .data = { &cmd, }, - .len = { sizeof(cmd) }, - .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_GET_INFO) - }; - int ret; - bool lar_fw_supported = !iwlwifi_mod_params.lar_disable && - fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_LAR_SUPPORT); - - lockdep_assert_held(&mvm->mutex); - - ret = iwl_mvm_send_cmd(mvm, &hcmd); - if (ret) - return ret; - - if (WARN(iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp), - "Invalid payload len in NVM response from FW %d", - iwl_rx_packet_payload_len(hcmd.resp_pkt))) { - ret = -EINVAL; - goto out; - } - - rsp = (void *)hcmd.resp_pkt->data; - if (le32_to_cpu(rsp->general.flags)) { - IWL_ERR(mvm, "Invalid NVM data from FW\n"); - ret = -EINVAL; - goto out; - } - - mvm->nvm_data = kzalloc(sizeof(*mvm->nvm_data) + - sizeof(struct ieee80211_channel) * - IWL_NUM_CHANNELS, GFP_KERNEL); - if (!mvm->nvm_data) { - ret = -ENOMEM; - goto out; - } - - iwl_set_hw_address_from_csr(trans, mvm->nvm_data); - /* TODO: if platform NVM has MAC address - override it here */ - - if (!is_valid_ether_addr(mvm->nvm_data->hw_addr)) { - IWL_ERR(trans, "no valid mac address was found\n"); - ret = -EINVAL; - goto err_free; - } - - IWL_INFO(trans, "base HW address: %pM\n", mvm->nvm_data->hw_addr); - - /* Initialize general data */ - mvm->nvm_data->nvm_version = le16_to_cpu(rsp->general.nvm_version); - - /* Initialize MAC sku data */ - mvm->nvm_data->sku_cap_11ac_enable = - le32_to_cpu(rsp->mac_sku.enable_11ac); - mvm->nvm_data->sku_cap_11n_enable = - le32_to_cpu(rsp->mac_sku.enable_11n); - mvm->nvm_data->sku_cap_band_24GHz_enable = - le32_to_cpu(rsp->mac_sku.enable_24g); - mvm->nvm_data->sku_cap_band_52GHz_enable = - le32_to_cpu(rsp->mac_sku.enable_5g); - mvm->nvm_data->sku_cap_mimo_disabled = - le32_to_cpu(rsp->mac_sku.mimo_disable); - - /* Initialize PHY sku data */ - mvm->nvm_data->valid_tx_ant = (u8)le32_to_cpu(rsp->phy_sku.tx_chains); - mvm->nvm_data->valid_rx_ant = (u8)le32_to_cpu(rsp->phy_sku.rx_chains); - - /* Initialize regulatory data */ - mvm->nvm_data->lar_enabled = - le32_to_cpu(rsp->regulatory.lar_enabled) && lar_fw_supported; - - iwl_init_sbands(trans->dev, trans->cfg, mvm->nvm_data, - rsp->regulatory.channel_profile, - mvm->nvm_data->valid_tx_ant & mvm->fw->valid_tx_ant, - mvm->nvm_data->valid_rx_ant & mvm->fw->valid_rx_ant, - rsp->regulatory.lar_enabled && lar_fw_supported); - - iwl_free_resp(&hcmd); - return 0; - -err_free: - kfree(mvm->nvm_data); -out: - iwl_free_resp(&hcmd); - return ret; -} - -int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) +int iwl_nvm_init(struct iwl_mvm *mvm) { int ret, section; u32 size_read = 0; @@ -651,63 +555,61 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic) return -EINVAL; /* load NVM values from nic */ - if (read_nvm_from_nic) { - /* Read From FW NVM */ - IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); - - nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, - GFP_KERNEL); - if (!nvm_buffer) - return -ENOMEM; - for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) { - /* we override the constness for initial read */ - ret = iwl_nvm_read_section(mvm, section, nvm_buffer, - size_read); - if (ret < 0) - continue; - size_read += ret; - temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); - if (!temp) { - ret = -ENOMEM; - break; - } + /* Read From FW NVM */ + IWL_DEBUG_EEPROM(mvm->trans->dev, "Read from NVM\n"); + + nvm_buffer = kmalloc(mvm->cfg->base_params->eeprom_size, + GFP_KERNEL); + if (!nvm_buffer) + return -ENOMEM; + for (section = 0; section < NVM_MAX_NUM_SECTIONS; section++) { + /* we override the constness for initial read */ + ret = iwl_nvm_read_section(mvm, section, nvm_buffer, + size_read); + if (ret < 0) + continue; + size_read += ret; + temp = kmemdup(nvm_buffer, ret, GFP_KERNEL); + if (!temp) { + ret = -ENOMEM; + break; + } - iwl_mvm_nvm_fixups(mvm, section, temp, ret); + iwl_mvm_nvm_fixups(mvm, section, temp, ret); - mvm->nvm_sections[section].data = temp; - mvm->nvm_sections[section].length = ret; + mvm->nvm_sections[section].data = temp; + mvm->nvm_sections[section].length = ret; #ifdef CONFIG_IWLWIFI_DEBUGFS - switch (section) { - case NVM_SECTION_TYPE_SW: - mvm->nvm_sw_blob.data = temp; - mvm->nvm_sw_blob.size = ret; - break; - case NVM_SECTION_TYPE_CALIBRATION: - mvm->nvm_calib_blob.data = temp; - mvm->nvm_calib_blob.size = ret; - break; - case NVM_SECTION_TYPE_PRODUCTION: - mvm->nvm_prod_blob.data = temp; - mvm->nvm_prod_blob.size = ret; - break; - case NVM_SECTION_TYPE_PHY_SKU: - mvm->nvm_phy_sku_blob.data = temp; - mvm->nvm_phy_sku_blob.size = ret; + switch (section) { + case NVM_SECTION_TYPE_SW: + mvm->nvm_sw_blob.data = temp; + mvm->nvm_sw_blob.size = ret; + break; + case NVM_SECTION_TYPE_CALIBRATION: + mvm->nvm_calib_blob.data = temp; + mvm->nvm_calib_blob.size = ret; + break; + case NVM_SECTION_TYPE_PRODUCTION: + mvm->nvm_prod_blob.data = temp; + mvm->nvm_prod_blob.size = ret; + break; + case NVM_SECTION_TYPE_PHY_SKU: + mvm->nvm_phy_sku_blob.data = temp; + mvm->nvm_phy_sku_blob.size = ret; + break; + default: + if (section == mvm->cfg->nvm_hw_section_num) { + mvm->nvm_hw_blob.data = temp; + mvm->nvm_hw_blob.size = ret; break; - default: - if (section == mvm->cfg->nvm_hw_section_num) { - mvm->nvm_hw_blob.data = temp; - mvm->nvm_hw_blob.size = ret; - break; - } } -#endif } - if (!size_read) - IWL_ERR(mvm, "OTP is blank\n"); - kfree(nvm_buffer); +#endif } + if (!size_read) + IWL_ERR(mvm, "OTP is blank\n"); + kfree(nvm_buffer); /* Only if PNVM selected in the mod param - load external NVM */ if (mvm->nvm_file_name) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 9c175d5e9d67..231878969332 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -82,11 +82,10 @@ #include "iwl-io.h" #include "iwl-prph.h" #include "rs.h" -#include "fw-api-scan.h" +#include "fw/api/scan.h" #include "time-event.h" -#include "fw-dbg.h" #include "fw-api.h" -#include "fw-api-scan.h" +#include "fw/api/scan.h" #define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux" MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -257,8 +256,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, RX_HANDLER_ASYNC_LOCKED), - RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, - iwl_mvm_rx_ant_coupling_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER(BA_WINDOW_STATUS_NOTIFICATION_ID, iwl_mvm_window_status_notif, RX_HANDLER_SYNC), @@ -326,7 +323,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(INIT_COMPLETE_NOTIF), HCMD_NAME(PHY_CONTEXT_CMD), HCMD_NAME(DBG_CFG), - HCMD_NAME(ANTENNA_COUPLING_NOTIFICATION), HCMD_NAME(SCAN_CFG_CMD), HCMD_NAME(SCAN_REQ_UMAC), HCMD_NAME(SCAN_ABORT_UMAC), @@ -351,13 +347,13 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(BINDING_CONTEXT_CMD), HCMD_NAME(TIME_QUOTA_CMD), HCMD_NAME(NON_QOS_TX_COUNTER_CMD), + HCMD_NAME(LEDS_CMD), HCMD_NAME(LQ_CMD), HCMD_NAME(FW_PAGING_BLOCK_CMD), HCMD_NAME(SCAN_OFFLOAD_REQUEST_CMD), HCMD_NAME(SCAN_OFFLOAD_ABORT_CMD), HCMD_NAME(HOT_SPOT_CMD), HCMD_NAME(SCAN_OFFLOAD_PROFILES_QUERY_CMD), - HCMD_NAME(BT_COEX_UPDATE_CORUN_LUT), HCMD_NAME(BT_COEX_UPDATE_REDUCED_TXP), HCMD_NAME(BT_COEX_CI), HCMD_NAME(PHY_CONFIGURATION_CMD), @@ -388,6 +384,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC), HCMD_NAME(REPLY_RX_PHY_CMD), HCMD_NAME(REPLY_RX_MPDU_CMD), + HCMD_NAME(FRAME_RELEASE), HCMD_NAME(BA_NOTIF), HCMD_NAME(MCC_UPDATE_CMD), HCMD_NAME(MCC_CHUB_UPDATE_CMD), @@ -510,8 +507,6 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) return 0; } -static void iwl_mvm_fw_error_dump_wk(struct work_struct *work); - static void iwl_mvm_tx_unblock_dwork(struct work_struct *work) { struct iwl_mvm *mvm = @@ -535,6 +530,34 @@ unlock: mutex_unlock(&mvm->mutex); } +static int iwl_mvm_fwrt_dump_start(void *ctx) +{ + struct iwl_mvm *mvm = ctx; + int ret; + + ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT); + if (ret) + return ret; + + mutex_lock(&mvm->mutex); + + return 0; +} + +static void iwl_mvm_fwrt_dump_end(void *ctx) +{ + struct iwl_mvm *mvm = ctx; + + mutex_unlock(&mvm->mutex); + + iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); +} + +static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { + .dump_start = iwl_mvm_fwrt_dump_start, + .dump_end = iwl_mvm_fwrt_dump_end, +}; + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -580,6 +603,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw = fw; mvm->hw = hw; + iwl_fw_runtime_init(&mvm->fwrt, trans, fw, &iwl_mvm_fwrt_ops, mvm); + mvm->init_status = 0; if (iwl_mvm_has_new_rx_api(mvm)) { @@ -596,32 +621,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; - if (!iwl_mvm_is_dqa_supported(mvm)) { - mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1; - - if (mvm->cfg->base_params->num_of_queues == 16) { - mvm->aux_queue = 11; - mvm->first_agg_queue = 12; - BUILD_BUG_ON(BITS_PER_BYTE * - sizeof(mvm->hw_queue_to_mac80211[0]) < 12); - } else { - mvm->aux_queue = 15; - mvm->first_agg_queue = 16; - BUILD_BUG_ON(BITS_PER_BYTE * - sizeof(mvm->hw_queue_to_mac80211[0]) < 16); - } - } else { - mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; - mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; - mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; - mvm->first_agg_queue = IWL_MVM_DQA_MIN_DATA_QUEUE; - mvm->last_agg_queue = IWL_MVM_DQA_MAX_DATA_QUEUE; - } + mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE; + mvm->probe_queue = IWL_MVM_DQA_AP_PROBE_RESP_QUEUE; + mvm->p2p_dev_queue = IWL_MVM_DQA_P2P_DEVICE_QUEUE; + mvm->sf_state = SF_UNINIT; - if (iwl_mvm_has_new_tx_api(mvm)) - mvm->cur_ucode = IWL_UCODE_REGULAR; + if (iwl_mvm_has_unified_ucode(mvm)) + iwl_fw_set_current_image(&mvm->fwrt, IWL_UCODE_REGULAR); else - mvm->cur_ucode = IWL_UCODE_INIT; + iwl_fw_set_current_image(&mvm->fwrt, IWL_UCODE_INIT); mvm->drop_bcn_ap_mode = true; mutex_init(&mvm->mutex); @@ -635,9 +643,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); - INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); - INIT_DELAYED_WORK(&mvm->fw_dump_wk, iwl_mvm_fw_error_dump_wk); INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work); INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk); INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk); @@ -688,10 +694,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.command_groups = iwl_mvm_groups; trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); - if (iwl_mvm_is_dqa_supported(mvm)) - trans_cfg.cmd_queue = IWL_MVM_DQA_CMD_QUEUE; - else - trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE; + trans_cfg.cmd_queue = IWL_MVM_DQA_CMD_QUEUE; trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; trans_cfg.scd_set_active = true; @@ -749,7 +752,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_stop_device(mvm); iwl_mvm_unref(mvm, IWL_MVM_REF_INIT_UCODE); mutex_unlock(&mvm->mutex); - /* returns 0 if successful, 1 if success but in rfkill */ if (err < 0) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); goto out_free; @@ -800,7 +802,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_leds_exit(mvm); iwl_mvm_thermal_exit(mvm); out_free: - flush_delayed_work(&mvm->fw_dump_wk); + iwl_fw_flush_dump(&mvm->fwrt); if (iwlmvm_mod_params.init_dbg) return op_mode; @@ -920,7 +922,7 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_FW_NOTIF); cmds_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) return; for (i = 0; i < ARRAY_SIZE(cmds_trig->cmds); i++) { @@ -932,9 +934,9 @@ static inline void iwl_mvm_rx_check_trigger(struct iwl_mvm *mvm, cmds_trig->cmds[i].group_id != pkt->hdr.group_id) continue; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "CMD 0x%02x.%02x received", - pkt->hdr.group_id, pkt->hdr.cmd); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "CMD 0x%02x.%02x received", + pkt->hdr.group_id, pkt->hdr.cmd); break; } } @@ -980,8 +982,10 @@ static void iwl_mvm_rx_common(struct iwl_mvm *mvm, list_add_tail(&entry->list, &mvm->async_handlers_list); spin_unlock(&mvm->async_handlers_lock); schedule_work(&mvm->async_handlers_wk); - break; + return; } + + iwl_fwrt_handle_notification(&mvm->fwrt, rxb); } static void iwl_mvm_rx(struct iwl_op_mode *op_mode, @@ -1131,7 +1135,7 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) * Stop the device if we run OPERATIONAL firmware or if we are in the * middle of the calibrations. */ - return state && (mvm->cur_ucode != IWL_UCODE_INIT || calibrating); + return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || calibrating); } static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) @@ -1160,57 +1164,6 @@ static void iwl_mvm_reprobe_wk(struct work_struct *wk) module_put(THIS_MODULE); } -static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) -{ - struct iwl_mvm *mvm = - container_of(work, struct iwl_mvm, fw_dump_wk.work); - - if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT)) - return; - - mutex_lock(&mvm->mutex); - - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - /* stop recording */ - iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); - - iwl_mvm_fw_error_dump(mvm); - - /* start recording again if the firmware is not crashed */ - if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && - mvm->fw->dbg_dest_tlv) { - iwl_clear_bits_prph(mvm->trans, - MON_BUFF_SAMPLE_CTL, 0x100); - iwl_clear_bits_prph(mvm->trans, - MON_BUFF_SAMPLE_CTL, 0x1); - iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x1); - } - } else { - u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE); - u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL); - - /* stop recording */ - iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); - udelay(100); - iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); - /* wait before we collect the data till the DBGC stop */ - udelay(500); - - iwl_mvm_fw_error_dump(mvm); - - /* start recording again if the firmware is not crashed */ - if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && - mvm->fw->dbg_dest_tlv) { - iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, in_sample); - iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, out_ctrl); - } - } - - mutex_unlock(&mvm->mutex); - - iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT); -} - void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) { iwl_abort_notification_waits(&mvm->notif_wait); @@ -1234,7 +1187,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) * can't recover this since we're already half suspended. */ if (!mvm->fw_restart && fw_error) { - iwl_mvm_fw_dbg_collect_desc(mvm, &iwl_mvm_dump_desc_assert, + iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, NULL); } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { struct iwl_mvm_reprobe *reprobe; @@ -1260,7 +1213,7 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) reprobe->dev = mvm->trans->dev; INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); schedule_work(&reprobe->work); - } else if (mvm->cur_ucode == IWL_UCODE_REGULAR && + } else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && mvm->hw_registered) { /* don't let the transport/FW power down */ iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); @@ -1439,7 +1392,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n"); - if (WARN_ON_ONCE(mvm->cur_ucode != IWL_UCODE_REGULAR)) + if (WARN_ON_ONCE(mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)) return -EINVAL; set_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status); @@ -1665,7 +1618,7 @@ int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm) IWL_DEBUG_RPM(mvm, "MVM exiting D0i3\n"); - if (WARN_ON_ONCE(mvm->cur_ucode != IWL_UCODE_REGULAR)) + if (WARN_ON_ONCE(mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR)) return -EINVAL; mutex_lock(&mvm->d0i3_suspend_mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index fb9eaf003ea5..7ee8e9077baf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -251,7 +251,7 @@ int iwl_mvm_phy_ctxt_changed(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) { - enum iwl_phy_ctxt_action action = FW_CTXT_ACTION_MODIFY; + enum iwl_ctxt_action action = FW_CTXT_ACTION_MODIFY; lockdep_assert_held(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index e684811f8e8b..c11fe2621d51 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -34,7 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH - * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -75,7 +75,7 @@ #include "iwl-debug.h" #include "mvm.h" #include "iwl-modparams.h" -#include "fw-api-power.h" +#include "fw/api/power.h" #define POWER_KEEP_ALIVE_PERIOD_SEC 25 @@ -186,7 +186,7 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, if (!mvmvif->queue_params[ac].uapsd) continue; - if (mvm->cur_ucode != IWL_UCODE_WOWLAN) + if (mvm->fwrt.cur_fw_img != IWL_UCODE_WOWLAN) cmd->flags |= cpu_to_le16(POWER_FLAGS_ADVANCE_PM_ENA_MSK); @@ -220,14 +220,15 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm, BIT(IEEE80211_AC_BK))) { cmd->flags |= cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK); cmd->snooze_interval = cpu_to_le16(IWL_MVM_PS_SNOOZE_INTERVAL); - cmd->snooze_window = (mvm->cur_ucode == IWL_UCODE_WOWLAN) ? - cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) : - cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW); + cmd->snooze_window = + (mvm->fwrt.cur_fw_img == IWL_UCODE_WOWLAN) ? + cpu_to_le16(IWL_MVM_WOWLAN_PS_SNOOZE_WINDOW) : + cpu_to_le16(IWL_MVM_PS_SNOOZE_WINDOW); } cmd->uapsd_max_sp = mvm->hw->uapsd_max_sp_len; - if (mvm->cur_ucode == IWL_UCODE_WOWLAN || cmd->flags & + if (mvm->fwrt.cur_fw_img == IWL_UCODE_WOWLAN || cmd->flags & cpu_to_le16(POWER_FLAGS_SNOOZE_ENA_MSK)) { cmd->rx_data_timeout_uapsd = cpu_to_le32(IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT); @@ -502,7 +503,7 @@ static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, struct iwl_mac_power_cmd cmd = {}; iwl_mvm_power_build_cmd(mvm, vif, &cmd, - mvm->cur_ucode != IWL_UCODE_WOWLAN); + mvm->fwrt.cur_fw_img != IWL_UCODE_WOWLAN); iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd)); @@ -525,8 +526,8 @@ int iwl_mvm_power_update_device(struct iwl_mvm *mvm) cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); #ifdef CONFIG_IWLWIFI_DEBUGFS - if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 : - mvm->disable_power_off) + if ((mvm->fwrt.cur_fw_img == IWL_UCODE_WOWLAN) ? + mvm->disable_power_off_d3 : mvm->disable_power_off) cmd.flags &= cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif @@ -933,7 +934,7 @@ static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm, if (!mvmvif->bf_data.bf_enabled) return 0; - if (mvm->cur_ucode == IWL_UCODE_WOWLAN) + if (mvm->fwrt.cur_fw_img == IWL_UCODE_WOWLAN) cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3); mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled || diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 8999a1199d60..ba7bd049d3d4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -622,7 +622,9 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, IWL_DEBUG_HT(mvm, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); - ret = ieee80211_start_tx_ba_session(sta, tid, 5000); + + /* start BA session until the peer sends del BA */ + ret = ieee80211_start_tx_ba_session(sta, tid, 0); if (ret == -EAGAIN) { /* * driver and mac80211 is out of sync @@ -636,15 +638,31 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_mvm *mvm, return ret; } -static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, u8 tid, - struct iwl_lq_sta *lq_data, +static void rs_tl_turn_on_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, + u8 tid, struct iwl_lq_sta *lq_sta, struct ieee80211_sta *sta) { - if (tid < IWL_MAX_TID_COUNT) - rs_tl_turn_on_agg_for_tid(mvm, lq_data, tid, sta); - else + struct iwl_mvm_tid_data *tid_data; + + /* + * In AP mode, tid can be equal to IWL_MAX_TID_COUNT + * when the frame is not QoS + */ + if (WARN_ON_ONCE(tid > IWL_MAX_TID_COUNT)) { IWL_ERR(mvm, "tid exceeds max TID count: %d/%d\n", tid, IWL_MAX_TID_COUNT); + return; + } else if (tid == IWL_MAX_TID_COUNT) { + return; + } + + tid_data = &mvmsta->tid_data[tid]; + if ((tid_data->state == IWL_AGG_OFF) && + (lq_sta->tx_agg_tid_en & BIT(tid)) && + (tid_data->tx_count_last >= IWL_MVM_RS_AGG_START_THRESHOLD)) { + IWL_DEBUG_RATE(mvm, "try to aggregate tid %d\n", tid); + rs_tl_turn_on_agg_for_tid(mvm, lq_sta, tid, sta); + } } static inline int get_num_of_ant_from_rate(u32 rate_n_flags) @@ -753,8 +771,38 @@ static int rs_collect_tpc_data(struct iwl_mvm *mvm, window); } +static void rs_update_tid_tpt_stats(struct iwl_mvm *mvm, + struct iwl_mvm_sta *mvmsta, + u8 tid, int successes) +{ + struct iwl_mvm_tid_data *tid_data; + + if (tid >= IWL_MAX_TID_COUNT) + return; + + tid_data = &mvmsta->tid_data[tid]; + + /* + * Measure if there're enough successful transmits per second. + * These statistics are used only to decide if we can start a + * BA session, so it should be updated only when A-MPDU is + * off. + */ + if (tid_data->state != IWL_AGG_OFF) + return; + + if (time_is_before_jiffies(tid_data->tpt_meas_start + HZ) || + (tid_data->tx_count >= IWL_MVM_RS_AGG_START_THRESHOLD)) { + tid_data->tx_count_last = tid_data->tx_count; + tid_data->tx_count = 0; + tid_data->tpt_meas_start = jiffies; + } else { + tid_data->tx_count += successes; + } +} + static int rs_collect_tlc_data(struct iwl_mvm *mvm, - struct iwl_lq_sta *lq_sta, + struct iwl_mvm_sta *mvmsta, u8 tid, struct iwl_scale_tbl_info *tbl, int scale_index, int attempts, int successes) { @@ -764,12 +812,14 @@ static int rs_collect_tlc_data(struct iwl_mvm *mvm, return -EINVAL; if (tbl->column != RS_COLUMN_INVALID) { - struct lq_sta_pers *pers = &lq_sta->pers; + struct lq_sta_pers *pers = &mvmsta->lq_sta.pers; pers->tx_stats[tbl->column][scale_index].total += attempts; pers->tx_stats[tbl->column][scale_index].success += successes; } + rs_update_tid_tpt_stats(mvm, mvmsta, tid, successes); + /* Select window for current tx bit rate */ window = &(tbl->win[scale_index]); return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes, @@ -1211,12 +1261,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (time_after(jiffies, (unsigned long)(lq_sta->last_tx + (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) { - int t; - IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); - for (t = 0; t < IWL_MAX_TID_COUNT; t++) - ieee80211_stop_tx_ba_session(sta, t); - iwl_mvm_rs_rate_init(mvm, sta, info->band, false); return; } @@ -1312,7 +1357,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, if (info->status.ampdu_ack_len == 0) info->status.ampdu_len = 1; - rs_collect_tlc_data(mvm, lq_sta, curr_tbl, tx_resp_rate.index, + rs_collect_tlc_data(mvm, mvmsta, tid, curr_tbl, tx_resp_rate.index, info->status.ampdu_len, info->status.ampdu_ack_len); @@ -1351,7 +1396,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, tx_resp_rate.index, 1, i < retries ? 0 : legacy_success, reduced_txp); - rs_collect_tlc_data(mvm, lq_sta, tmp_tbl, + rs_collect_tlc_data(mvm, mvmsta, tid, tmp_tbl, tx_resp_rate.index, 1, i < retries ? 0 : legacy_success); } @@ -1673,14 +1718,14 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_scale_tbl_info *tbl, enum rs_action scale_action) { - struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if ((!is_vht(&tbl->rate) && !is_ht(&tbl->rate)) || tbl->rate.index < IWL_RATE_MCS_5_INDEX || scale_action == RS_ACTION_DOWNSCALE) - sta_priv->tlc_amsdu = false; + mvmsta->tlc_amsdu = false; else - sta_priv->tlc_amsdu = true; + mvmsta->tlc_amsdu = true; } /* @@ -2228,11 +2273,10 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, u16 high_low; s32 sr; u8 prev_agg = lq_sta->is_agg; - struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); - struct iwl_mvm_tid_data *tid_data; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct rs_rate *rate; - lq_sta->is_agg = !!sta_priv->agg_tids; + lq_sta->is_agg = !!mvmsta->agg_tids; /* * Select rate-scale / modulation-mode table to work with in @@ -2480,44 +2524,12 @@ lq_update: } } + if (!ndp) + rs_tl_turn_on_agg(mvm, mvmsta, tid, lq_sta, sta); + if (done_search && lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_ENDED) { - /* If the "active" (non-search) mode was legacy, - * and we've tried switching antennas, - * but we haven't been able to try HT modes (not available), - * stay with best antenna legacy modulation for a while - * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(&tbl1->rate)) { - IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); - - if (tid != IWL_MAX_TID_COUNT) { - tid_data = &sta_priv->tid_data[tid]; - if (tid_data->state != IWL_AGG_OFF) { - IWL_DEBUG_RATE(mvm, - "Stop aggregation on tid %d\n", - tid); - ieee80211_stop_tx_ba_session(sta, tid); - } - } - rs_set_stay_in_table(mvm, 1, lq_sta); - } else { - /* If we're in an HT mode, and all 3 mode switch actions - * have been tried and compared, stay in this best modulation - * mode for a while before next round of mode comparisons. */ - if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && - (lq_sta->tx_agg_tid_en & (1 << tid)) && - (tid != IWL_MAX_TID_COUNT)) { - tid_data = &sta_priv->tid_data[tid]; - if (tid_data->state == IWL_AGG_OFF && !ndp) { - IWL_DEBUG_RATE(mvm, - "try to aggregate tid %d\n", - tid); - rs_tl_turn_on_agg(mvm, tid, - lq_sta, sta); - } - } - rs_set_stay_in_table(mvm, 0, lq_sta); - } + rs_set_stay_in_table(mvm, is_legacy(&tbl1->rate), lq_sta); } } @@ -2900,10 +2912,10 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, gfp_t gfp) { - struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate; struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; + struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta; IWL_DEBUG_RATE(mvm, "create station rate scale window\n"); @@ -2917,7 +2929,7 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); lq_sta->pers.last_rssi = S8_MIN; - return &sta_priv->lq_sta; + return &mvmsta->lq_sta; } static int rs_vht_highest_rx_mcs_index(struct ieee80211_sta_vht_cap *vht_cap, @@ -3109,8 +3121,8 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct ieee80211_hw *hw = mvm->hw; struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; - struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta); - struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta; + struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); + struct iwl_lq_sta *lq_sta = &mvmsta->lq_sta; struct ieee80211_supported_band *sband; unsigned long supp; /* must be unsigned long for for_each_set_bit */ @@ -3119,8 +3131,8 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, sband = hw->wiphy->bands[band]; - lq_sta->lq.sta_id = sta_priv->sta_id; - sta_priv->tlc_amsdu = false; + lq_sta->lq.sta_id = mvmsta->sta_id; + mvmsta->tlc_amsdu = false; for (j = 0; j < LQ_SIZE; j++) rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]); @@ -3130,7 +3142,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, IWL_DEBUG_RATE(mvm, "LQ: *** rate scale station global init for station %d ***\n", - sta_priv->sta_id); + mvmsta->sta_id); /* TODO: what is a good starting rate for STA? About middle? Maybe not * the lowest or the highest rate.. Could consider using RSSI from * previous packets? Need to have IEEE 802.1X auth succeed immediately diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 622d543abb70..184c749766f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -67,7 +67,6 @@ #include "iwl-trans.h" #include "mvm.h" #include "fw-api.h" -#include "fw-dbg.h" /* * iwl_mvm_rx_rx_phy_cmd - REPLY_RX_PHY_CMD handler @@ -397,10 +396,12 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, rssi = le32_to_cpu(rssi_trig->rssi); trig_check = - iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, + iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(mvmsta->vif), trig); if (trig_check && rx_status->signal < rssi) - iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + NULL); } if (ieee80211_is_data(hdr->frame_control)) @@ -624,7 +625,7 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_STATS); trig_stats = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) return; trig_offset = le32_to_cpu(trig_stats->stop_offset); @@ -636,7 +637,7 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) if (le32_to_cpup((__le32 *) (pkt->data + trig_offset)) < trig_thold) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, NULL); } void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 71c8b800ffa9..67ffd9774712 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -63,7 +63,6 @@ #include "iwl-trans.h" #include "mvm.h" #include "fw-api.h" -#include "fw-dbg.h" static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb, int queue, struct ieee80211_sta *sta) @@ -854,7 +853,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rcu_read_lock(); - if (le16_to_cpu(desc->status) & IWL_RX_MPDU_STATUS_SRC_STA_FOUND) { + if (desc->status & cpu_to_le16(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) { u8 id = desc->sta_id_flags & IWL_RX_MPDU_SIF_STA_ID_MASK; if (!WARN_ON_ONCE(id >= ARRAY_SIZE(mvm->fw_id_to_mac_id))) { @@ -908,10 +907,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rssi = le32_to_cpu(rssi_trig->rssi); trig_check = - iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif, + iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(mvmsta->vif), trig); if (trig_check && rx_status->signal < rssi) - iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + NULL); } if (ieee80211_is_data(hdr->frame_control)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 35e813bdfbe5..50983615dce6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -69,7 +69,7 @@ #include <net/mac80211.h> #include "mvm.h" -#include "fw-api-scan.h" +#include "fw/api/scan.h" #include "iwl-io.h" #define IWL_DENSE_EBS_SCAN_RATIO 5 @@ -743,7 +743,7 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm, * 4. it's not a p2p find operation. */ return ((capa->flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) && - mvm->last_ebs_successful && + mvm->last_ebs_successful && IWL_MVM_ENABLE_EBS && vif->type != NL80211_IFTYPE_P2P_DEVICE); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 027ee5e72172..411a2055dc45 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -297,60 +297,6 @@ unlock: rcu_read_unlock(); } -static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm, - struct ieee80211_sta *sta) -{ - unsigned long used_hw_queues; - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - unsigned int wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, NULL, true, false); - u32 ac; - - lockdep_assert_held(&mvm->mutex); - - used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, NULL); - - /* Find available queues, and allocate them to the ACs */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - u8 queue = find_first_zero_bit(&used_hw_queues, - mvm->first_agg_queue); - - if (queue >= mvm->first_agg_queue) { - IWL_ERR(mvm, "Failed to allocate STA queue\n"); - return -EBUSY; - } - - __set_bit(queue, &used_hw_queues); - mvmsta->hw_queue[ac] = queue; - } - - /* Found a place for all queues - enable them */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { - iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac], - mvmsta->hw_queue[ac], - iwl_mvm_ac_to_tx_fifo[ac], 0, - wdg_timeout); - mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]); - } - - return 0; -} - -static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm, - struct ieee80211_sta *sta) -{ - struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); - unsigned long sta_msk; - int i; - - lockdep_assert_held(&mvm->mutex); - - /* disable the TDLS STA-specific queues */ - sta_msk = mvmsta->tfd_queue_msk; - for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE) - iwl_mvm_disable_txq(mvm, i, i, IWL_MAX_TID_COUNT, 0); -} - /* Disable aggregations for a bitmap of TIDs for a given station */ static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue, unsigned long disable_agg_tids, @@ -758,7 +704,7 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm, { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_trans_txq_scd_cfg cfg = { - .fifo = iwl_mvm_ac_to_tx_fifo[ac], + .fifo = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac), .sta_id = mvmsta->sta_id, .tid = tid, .frame_limit = IWL_FRAME_LIMIT, @@ -1316,7 +1262,7 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, u16 seq = IEEE80211_SEQ_TO_SN(tid_data->seq_number); cfg.tid = i; - cfg.fifo = iwl_mvm_ac_to_tx_fifo[ac]; + cfg.fifo = iwl_mvm_mac_ac_to_tx_fifo(mvm, ac); cfg.aggregate = (txq_id >= IWL_MVM_DQA_MIN_DATA_QUEUE || txq_id == IWL_MVM_DQA_BSS_CLIENT_QUEUE); @@ -1330,8 +1276,50 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY; } } +} - atomic_set(&mvm->pending_frames[mvm_sta->sta_id], 0); +static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, + struct iwl_mvm_int_sta *sta, + const u8 *addr, + u16 mac_id, u16 color) +{ + struct iwl_mvm_add_sta_cmd cmd; + int ret; + u32 status; + + lockdep_assert_held(&mvm->mutex); + + memset(&cmd, 0, sizeof(cmd)); + cmd.sta_id = sta->sta_id; + cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, + color)); + if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) + cmd.station_type = sta->type; + + if (!iwl_mvm_has_new_tx_api(mvm)) + cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); + cmd.tid_disable_tx = cpu_to_le16(0xffff); + + if (addr) + memcpy(cmd.addr, addr, ETH_ALEN); + + ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, + iwl_mvm_add_sta_cmd_size(mvm), + &cmd, &status); + if (ret) + return ret; + + switch (status & IWL_ADD_STA_STATUS_MASK) { + case ADD_STA_SUCCESS: + IWL_DEBUG_INFO(mvm, "Internal station added.\n"); + return 0; + default: + ret = -EIO; + IWL_ERR(mvm, "Add internal station failed, status=0x%x\n", + status); + break; + } + return ret; } int iwl_mvm_add_sta(struct iwl_mvm *mvm, @@ -1342,6 +1330,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_rxq_dup_data *dup_data; int i, ret, sta_id; + bool sta_update = false; + unsigned int sta_flags = 0; lockdep_assert_held(&mvm->mutex); @@ -1356,10 +1346,25 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, spin_lock_init(&mvm_sta->lock); - /* In DQA mode, if this is a HW restart, re-alloc existing queues */ - if (iwl_mvm_is_dqa_supported(mvm) && - test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + /* if this is a HW restart re-alloc existing queues */ + if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + struct iwl_mvm_int_sta tmp_sta = { + .sta_id = sta_id, + .type = mvm_sta->sta_type, + }; + + /* + * First add an empty station since allocating + * a queue requires a valid station + */ + ret = iwl_mvm_add_int_sta_common(mvm, &tmp_sta, sta->addr, + mvmvif->id, mvmvif->color); + if (ret) + goto err; + iwl_mvm_realloc_queues_after_restart(mvm, mvm_sta); + sta_update = true; + sta_flags = iwl_mvm_has_new_tx_api(mvm) ? 0 : STA_MODIFY_QUEUES; goto update_fw; } @@ -1376,33 +1381,15 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, mvm_sta->sta_type = sta->tdls ? IWL_STA_TDLS_LINK : IWL_STA_LINK; /* HW restart, don't assume the memory has been zeroed */ - atomic_set(&mvm->pending_frames[sta_id], 0); mvm_sta->tid_disable_agg = 0xffff; /* No aggs at first */ mvm_sta->tfd_queue_msk = 0; - /* - * Allocate new queues for a TDLS station, unless we're in DQA mode, - * and then they'll be allocated dynamically - */ - if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) { - ret = iwl_mvm_tdls_sta_init(mvm, sta); - if (ret) - return ret; - } else if (!iwl_mvm_is_dqa_supported(mvm)) { - for (i = 0; i < IEEE80211_NUM_ACS; i++) - if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) - mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); - } - /* for HW restart - reset everything but the sequence number */ for (i = 0; i <= IWL_MAX_TID_COUNT; i++) { u16 seq = mvm_sta->tid_data[i].seq_number; memset(&mvm_sta->tid_data[i], 0, sizeof(mvm_sta->tid_data[i])); mvm_sta->tid_data[i].seq_number = seq; - if (!iwl_mvm_is_dqa_supported(mvm)) - continue; - /* * Mark all queues for this STA as unallocated and defer TX * frames until the queue is allocated @@ -1436,7 +1423,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, mvm_sta->dup_data = dup_data; } - if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { + if (!iwl_mvm_has_new_tx_api(mvm)) { ret = iwl_mvm_reserve_sta_stream(mvm, sta, ieee80211_vif_type_p2p(vif)); if (ret) @@ -1444,7 +1431,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, } update_fw: - ret = iwl_mvm_sta_send_to_fw(mvm, sta, false, 0); + ret = iwl_mvm_sta_send_to_fw(mvm, sta, sta_update, sta_flags); if (ret) goto err; @@ -1462,8 +1449,6 @@ update_fw: return 0; err: - if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) - iwl_mvm_tdls_sta_deinit(mvm, sta); return ret; } @@ -1536,79 +1521,6 @@ static int iwl_mvm_rm_sta_common(struct iwl_mvm *mvm, u8 sta_id) return 0; } -void iwl_mvm_sta_drained_wk(struct work_struct *wk) -{ - struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, sta_drained_wk); - u8 sta_id; - - /* - * The mutex is needed because of the SYNC cmd, but not only: if the - * work would run concurrently with iwl_mvm_rm_sta, it would run before - * iwl_mvm_rm_sta sets the station as busy, and exit. Then - * iwl_mvm_rm_sta would set the station as busy, and nobody will clean - * that later. - */ - mutex_lock(&mvm->mutex); - - for_each_set_bit(sta_id, mvm->sta_drained, IWL_MVM_STATION_COUNT) { - int ret; - struct ieee80211_sta *sta = - rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id], - lockdep_is_held(&mvm->mutex)); - - /* - * This station is in use or RCU-removed; the latter happens in - * managed mode, where mac80211 removes the station before we - * can remove it from firmware (we can only do that after the - * MAC is marked unassociated), and possibly while the deauth - * frame to disconnect from the AP is still queued. Then, the - * station pointer is -ENOENT when the last skb is reclaimed. - */ - if (!IS_ERR(sta) || PTR_ERR(sta) == -ENOENT) - continue; - - if (PTR_ERR(sta) == -EINVAL) { - IWL_ERR(mvm, "Drained sta %d, but it is internal?\n", - sta_id); - continue; - } - - if (!sta) { - IWL_ERR(mvm, "Drained sta %d, but it was NULL?\n", - sta_id); - continue; - } - - WARN_ON(PTR_ERR(sta) != -EBUSY); - /* This station was removed and we waited until it got drained, - * we can now proceed and remove it. - */ - ret = iwl_mvm_rm_sta_common(mvm, sta_id); - if (ret) { - IWL_ERR(mvm, - "Couldn't remove sta %d after it was drained\n", - sta_id); - continue; - } - RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); - clear_bit(sta_id, mvm->sta_drained); - - if (mvm->tfd_drained[sta_id]) { - unsigned long i, msk = mvm->tfd_drained[sta_id]; - - for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE) - iwl_mvm_disable_txq(mvm, i, i, - IWL_MAX_TID_COUNT, 0); - - mvm->tfd_drained[sta_id] = 0; - IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n", - sta_id, msk); - } - } - - mutex_unlock(&mvm->mutex); -} - static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvm_sta) @@ -1632,10 +1544,11 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm, int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvm_sta) { - int i, ret; + int i; for (i = 0; i < ARRAY_SIZE(mvm_sta->tid_data); i++) { u16 txq_id; + int ret; spin_lock_bh(&mvm_sta->lock); txq_id = mvm_sta->tid_data[i].txq_id; @@ -1646,10 +1559,10 @@ int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm, ret = iwl_trans_wait_txq_empty(mvm->trans, txq_id); if (ret) - break; + return ret; } - return ret; + return 0; } int iwl_mvm_rm_sta(struct iwl_mvm *mvm, @@ -1666,79 +1579,65 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, if (iwl_mvm_has_new_rx_api(mvm)) kfree(mvm_sta->dup_data); - if ((vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id == sta_id) || - iwl_mvm_is_dqa_supported(mvm)){ - ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); - if (ret) - return ret; - /* flush its queues here since we are freeing mvm_sta */ - ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); - if (ret) - return ret; - if (iwl_mvm_has_new_tx_api(mvm)) { - ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta); - } else { - u32 q_mask = mvm_sta->tfd_queue_msk; + ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); + if (ret) + return ret; - ret = iwl_trans_wait_tx_queues_empty(mvm->trans, - q_mask); - } - if (ret) - return ret; - ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); - - /* If DQA is supported - the queues can be disabled now */ - if (iwl_mvm_is_dqa_supported(mvm)) { - iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); - /* - * If pending_frames is set at this point - it must be - * driver internal logic error, since queues are empty - * and removed successuly. - * warn on it but set it to 0 anyway to avoid station - * not being removed later in the function - */ - WARN_ON(atomic_xchg(&mvm->pending_frames[sta_id], 0)); - } + /* flush its queues here since we are freeing mvm_sta */ + ret = iwl_mvm_flush_sta(mvm, mvm_sta, false, 0); + if (ret) + return ret; + if (iwl_mvm_has_new_tx_api(mvm)) { + ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta); + } else { + u32 q_mask = mvm_sta->tfd_queue_msk; - /* If there is a TXQ still marked as reserved - free it */ - if (iwl_mvm_is_dqa_supported(mvm) && - mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { - u8 reserved_txq = mvm_sta->reserved_queue; - enum iwl_mvm_queue_status *status; - - /* - * If no traffic has gone through the reserved TXQ - it - * is still marked as IWL_MVM_QUEUE_RESERVED, and - * should be manually marked as free again - */ - spin_lock_bh(&mvm->queue_info_lock); - status = &mvm->queue_info[reserved_txq].status; - if (WARN((*status != IWL_MVM_QUEUE_RESERVED) && - (*status != IWL_MVM_QUEUE_FREE), - "sta_id %d reserved txq %d status %d", - sta_id, reserved_txq, *status)) { - spin_unlock_bh(&mvm->queue_info_lock); - return -EINVAL; - } + ret = iwl_trans_wait_tx_queues_empty(mvm->trans, + q_mask); + } + if (ret) + return ret; - *status = IWL_MVM_QUEUE_FREE; + ret = iwl_mvm_drain_sta(mvm, mvm_sta, false); + + iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta); + + /* If there is a TXQ still marked as reserved - free it */ + if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) { + u8 reserved_txq = mvm_sta->reserved_queue; + enum iwl_mvm_queue_status *status; + + /* + * If no traffic has gone through the reserved TXQ - it + * is still marked as IWL_MVM_QUEUE_RESERVED, and + * should be manually marked as free again + */ + spin_lock_bh(&mvm->queue_info_lock); + status = &mvm->queue_info[reserved_txq].status; + if (WARN((*status != IWL_MVM_QUEUE_RESERVED) && + (*status != IWL_MVM_QUEUE_FREE), + "sta_id %d reserved txq %d status %d", + sta_id, reserved_txq, *status)) { spin_unlock_bh(&mvm->queue_info_lock); + return -EINVAL; } - if (vif->type == NL80211_IFTYPE_STATION && - mvmvif->ap_sta_id == sta_id) { - /* if associated - we can't remove the AP STA now */ - if (vif->bss_conf.assoc) - return ret; + *status = IWL_MVM_QUEUE_FREE; + spin_unlock_bh(&mvm->queue_info_lock); + } - /* unassoc - go ahead - remove the AP STA now */ - mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; + if (vif->type == NL80211_IFTYPE_STATION && + mvmvif->ap_sta_id == sta_id) { + /* if associated - we can't remove the AP STA now */ + if (vif->bss_conf.assoc) + return ret; - /* clear d0i3_ap_sta_id if no longer relevant */ - if (mvm->d0i3_ap_sta_id == sta_id) - mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; - } + /* unassoc - go ahead - remove the AP STA now */ + mvmvif->ap_sta_id = IWL_MVM_INVALID_STA; + + /* clear d0i3_ap_sta_id if no longer relevant */ + if (mvm->d0i3_ap_sta_id == sta_id) + mvm->d0i3_ap_sta_id = IWL_MVM_INVALID_STA; } /* @@ -1755,32 +1654,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, * calls the drain worker. */ spin_lock_bh(&mvm_sta->lock); + spin_unlock_bh(&mvm_sta->lock); - /* - * There are frames pending on the AC queues for this station. - * We need to wait until all the frames are drained... - */ - if (atomic_read(&mvm->pending_frames[sta_id])) { - rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], - ERR_PTR(-EBUSY)); - spin_unlock_bh(&mvm_sta->lock); - - /* disable TDLS sta queues on drain complete */ - if (sta->tdls) { - mvm->tfd_drained[sta_id] = mvm_sta->tfd_queue_msk; - IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", sta_id); - } - - ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); - } else { - spin_unlock_bh(&mvm_sta->lock); - - if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) - iwl_mvm_tdls_sta_deinit(mvm, sta); - - ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); - RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); - } + ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); + RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); return ret; } @@ -1823,50 +1700,6 @@ void iwl_mvm_dealloc_int_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *sta) sta->sta_id = IWL_MVM_INVALID_STA; } -static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm, - struct iwl_mvm_int_sta *sta, - const u8 *addr, - u16 mac_id, u16 color) -{ - struct iwl_mvm_add_sta_cmd cmd; - int ret; - u32 status; - - lockdep_assert_held(&mvm->mutex); - - memset(&cmd, 0, sizeof(cmd)); - cmd.sta_id = sta->sta_id; - cmd.mac_id_n_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mac_id, - color)); - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) - cmd.station_type = sta->type; - - if (!iwl_mvm_has_new_tx_api(mvm)) - cmd.tfd_queue_msk = cpu_to_le32(sta->tfd_queue_msk); - cmd.tid_disable_tx = cpu_to_le16(0xffff); - - if (addr) - memcpy(cmd.addr, addr, ETH_ALEN); - - ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, - iwl_mvm_add_sta_cmd_size(mvm), - &cmd, &status); - if (ret) - return ret; - - switch (status & IWL_ADD_STA_STATUS_MASK) { - case ADD_STA_SUCCESS: - IWL_DEBUG_INFO(mvm, "Internal station added.\n"); - return 0; - default: - ret = -EIO; - IWL_ERR(mvm, "Add internal station failed, status=0x%x\n", - status); - break; - } - return ret; -} - static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) { unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ? @@ -1879,7 +1712,7 @@ static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) IWL_MAX_TID_COUNT, wdg_timeout); mvm->aux_queue = queue; - } else if (iwl_mvm_is_dqa_supported(mvm)) { + } else { struct iwl_trans_txq_scd_cfg cfg = { .fifo = IWL_MVM_TX_FIFO_MCAST, .sta_id = mvm->aux_sta.sta_id, @@ -1890,9 +1723,6 @@ static void iwl_mvm_enable_aux_queue(struct iwl_mvm *mvm) iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, &cfg, wdg_timeout); - } else { - iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue, - IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout); } } @@ -1992,7 +1822,7 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { + if (!iwl_mvm_has_new_tx_api(mvm)) { if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) queue = mvm->probe_queue; @@ -2079,8 +1909,7 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (iwl_mvm_is_dqa_supported(mvm)) - iwl_mvm_free_bcast_sta_queues(mvm, vif); + iwl_mvm_free_bcast_sta_queues(mvm, vif); ret = iwl_mvm_rm_sta_common(mvm, mvmvif->bcast_sta.sta_id); if (ret) @@ -2091,23 +1920,10 @@ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 qmask = 0; lockdep_assert_held(&mvm->mutex); - if (!iwl_mvm_is_dqa_supported(mvm)) { - qmask = iwl_mvm_mac_get_queues_mask(vif); - - /* - * The firmware defines the TFD queue mask to only be relevant - * for *unicast* queues, so the multicast (CAB) queue shouldn't - * be included. This only happens in NL80211_IFTYPE_AP vif type, - * so the next line will only have an effect there. - */ - qmask &= ~BIT(vif->cab_queue); - } - - return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, qmask, + return iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta, 0, ieee80211_vif_type_p2p(vif), IWL_STA_GENERAL_PURPOSE); } @@ -2119,7 +1935,7 @@ int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * @mvm: the mvm component * @vif: the interface to which the broadcast station is added * @bsta: the broadcast station to add. */ -int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +int iwl_mvm_add_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_int_sta *bsta = &mvmvif->bcast_sta; @@ -2150,7 +1966,7 @@ void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * Send the FW a request to remove the station from it's internal data * structures, and in addition remove it from the local data structure. */ -int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +int iwl_mvm_rm_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { int ret; @@ -2189,9 +2005,6 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (!iwl_mvm_is_dqa_supported(mvm)) - return 0; - if (WARN_ON(vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_ADHOC)) return -ENOTSUPP; @@ -2256,9 +2069,6 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) lockdep_assert_held(&mvm->mutex); - if (!iwl_mvm_is_dqa_supported(mvm)) - return 0; - iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0); iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue, @@ -2508,8 +2318,6 @@ int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, mvm_sta->tid_disable_agg &= ~BIT(tid); } else { /* In DQA-mode the queue isn't removed on agg termination */ - if (!iwl_mvm_is_dqa_supported(mvm)) - mvm_sta->tfd_queue_msk &= ~BIT(queue); mvm_sta->tid_disable_agg |= BIT(tid); } @@ -2612,19 +2420,17 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ret = -ENXIO; goto release_locks; } - } else if (iwl_mvm_is_dqa_supported(mvm) && - unlikely(mvm->queue_info[txq_id].status == + } else if (unlikely(mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_SHARED)) { ret = -ENXIO; IWL_DEBUG_TX_QUEUES(mvm, "Can't start tid %d agg on shared queue!\n", tid); goto release_locks; - } else if (!iwl_mvm_is_dqa_supported(mvm) || - mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) { + } else if (mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) { txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, - mvm->first_agg_queue, - mvm->last_agg_queue); + IWL_MVM_DQA_MIN_DATA_QUEUE, + IWL_MVM_DQA_MAX_DATA_QUEUE); if (txq_id < 0) { ret = txq_id; IWL_ERR(mvm, "Failed to allocate agg queue\n"); @@ -2742,37 +2548,34 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif, queue_status = mvm->queue_info[queue].status; spin_unlock_bh(&mvm->queue_info_lock); - /* In DQA mode, the existing queue might need to be reconfigured */ - if (iwl_mvm_is_dqa_supported(mvm)) { - /* Maybe there is no need to even alloc a queue... */ - if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY) - alloc_queue = false; + /* Maybe there is no need to even alloc a queue... */ + if (mvm->queue_info[queue].status == IWL_MVM_QUEUE_READY) + alloc_queue = false; + /* + * Only reconfig the SCD for the queue if the window size has + * changed from current (become smaller) + */ + if (!alloc_queue && buf_size < mvmsta->max_agg_bufsize) { /* - * Only reconfig the SCD for the queue if the window size has - * changed from current (become smaller) + * If reconfiguring an existing queue, it first must be + * drained */ - if (!alloc_queue && buf_size < mvmsta->max_agg_bufsize) { - /* - * If reconfiguring an existing queue, it first must be - * drained - */ - ret = iwl_trans_wait_tx_queues_empty(mvm->trans, - BIT(queue)); - if (ret) { - IWL_ERR(mvm, - "Error draining queue before reconfig\n"); - return ret; - } + ret = iwl_trans_wait_tx_queues_empty(mvm->trans, + BIT(queue)); + if (ret) { + IWL_ERR(mvm, + "Error draining queue before reconfig\n"); + return ret; + } - ret = iwl_mvm_reconfig_scd(mvm, queue, cfg.fifo, - mvmsta->sta_id, tid, - buf_size, ssn); - if (ret) { - IWL_ERR(mvm, - "Error reconfiguring TXQ #%d\n", queue); - return ret; - } + ret = iwl_mvm_reconfig_scd(mvm, queue, cfg.fifo, + mvmsta->sta_id, tid, + buf_size, ssn); + if (ret) { + IWL_ERR(mvm, + "Error reconfiguring TXQ #%d\n", queue); + return ret; } } @@ -2868,18 +2671,6 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, "ssn = %d, next_recl = %d\n", tid_data->ssn, tid_data->next_reclaimed); - /* - * There are still packets for this RA / TID in the HW. - * Not relevant for DQA mode, since there is no need to disable - * the queue. - */ - if (!iwl_mvm_is_dqa_supported(mvm) && - tid_data->ssn != tid_data->next_reclaimed) { - tid_data->state = IWL_EMPTYING_HW_QUEUE_DELBA; - err = 0; - break; - } - tid_data->ssn = 0xffff; tid_data->state = IWL_AGG_OFF; spin_unlock_bh(&mvmsta->lock); @@ -2887,12 +2678,6 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); - - if (!iwl_mvm_is_dqa_supported(mvm)) { - int mac_queue = vif->hw_queue[tid_to_mac80211_ac[tid]]; - - iwl_mvm_disable_txq(mvm, txq_id, mac_queue, tid, 0); - } return 0; case IWL_AGG_STARTING: case IWL_EMPTYING_HW_QUEUE_ADDBA: @@ -2962,13 +2747,6 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_drain_sta(mvm, mvmsta, false); iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false); - - if (!iwl_mvm_is_dqa_supported(mvm)) { - int mac_queue = vif->hw_queue[tid_to_mac80211_ac[tid]]; - - iwl_mvm_disable_txq(mvm, tid_data->txq_id, mac_queue, - tid, 0); - } } return 0; @@ -3587,15 +3365,6 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, u16 n_queued; tid_data = &mvmsta->tid_data[tid]; - if (WARN(!iwl_mvm_is_dqa_supported(mvm) && - tid_data->state != IWL_AGG_ON && - tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA, - "TID %d state is %d\n", - tid, tid_data->state)) { - spin_unlock_bh(&mvmsta->lock); - ieee80211_sta_eosp(sta); - return; - } n_queued = iwl_mvm_tid_queued(mvm, tid_data); if (n_queued > remaining) { @@ -3689,13 +3458,8 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, mvm_sta->disable_tx = disable; - /* - * Tell mac80211 to start/stop queuing tx for this station, - * but don't stop queuing if there are still pending frames - * for this station. - */ - if (disable || !atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) - ieee80211_sta_block_awake(mvm->hw, sta, disable); + /* Tell mac80211 to start/stop queuing tx for this station */ + ieee80211_sta_block_awake(mvm->hw, sta, disable); iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 05fecbe87da4..d13893806513 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -222,16 +222,7 @@ struct iwl_mvm_vif; * we remove the STA of the AP. The flush can be done synchronously against the * fw. * Drain means that the fw will drop all the frames sent to a specific station. - * This is useful when a client (if we are IBSS / GO or AP) disassociates. In - * that case, we need to drain all the frames for that client from the AC queues - * that are shared with the other clients. Only then, we can remove the STA in - * the fw. In order to do so, we track the non-AMPDU packets for each station. - * If mac80211 removes a STA and if it still has non-AMPDU packets pending in - * the queues, we mark this station as %EBUSY in %fw_id_to_mac_id, and drop all - * the frames for this STA (%iwl_mvm_rm_sta). When the last frame is dropped - * (we know about it with its Tx response), we remove the station in fw and set - * it as %NULL in %fw_id_to_mac_id: this is the purpose of - * %iwl_mvm_sta_drained_wk. + * This is useful when a client (if we are IBSS / GO or AP) disassociates. */ /** @@ -325,6 +316,10 @@ enum iwl_mvm_agg_state { * @is_tid_active: has this TID sent traffic in the last * %IWL_MVM_DQA_QUEUE_TIMEOUT time period. If %txq_id is invalid, this * field should be ignored. + * @tpt_meas_start: time of the throughput measurements start, is reset every HZ + * @tx_count_last: number of frames transmitted during the last second + * @tx_count: counts the number of frames transmitted since the last reset of + * tpt_meas_start */ struct iwl_mvm_tid_data { struct sk_buff_head deferred_tx_frames; @@ -339,6 +334,9 @@ struct iwl_mvm_tid_data { u16 ssn; u16 tx_time; bool is_tid_active; + unsigned long tpt_meas_start; + u32 tx_count_last; + u32 tx_count; }; struct iwl_mvm_key_pn { @@ -371,7 +369,6 @@ struct iwl_mvm_rxq_dup_data { * struct iwl_mvm_sta - representation of a station in the driver * @sta_id: the index of the station in the fw (will be replaced by id_n_color) * @tfd_queue_msk: the tfd queues used by the station - * @hw_queue: per-AC mapping of the TFD queues used by station * @mac_id_n_color: the MAC context this station is linked to * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for * tid. @@ -409,7 +406,6 @@ struct iwl_mvm_rxq_dup_data { struct iwl_mvm_sta { u32 sta_id; u32 tfd_queue_msk; - u8 hw_queue[IEEE80211_NUM_ACS]; u32 mac_id_n_color; u16 tid_disable_agg; u8 max_agg_bufsize; @@ -533,9 +529,9 @@ void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm); int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_add_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); +int iwl_mvm_rm_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, @@ -548,7 +544,6 @@ int iwl_mvm_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_dealloc_snif_sta(struct iwl_mvm *mvm); -void iwl_mvm_sta_drained_wk(struct work_struct *wk); void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, struct ieee80211_sta *sta); void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 5a682722adce..4d0314912e94 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,7 +75,6 @@ #include "mvm.h" #include "iwl-io.h" #include "iwl-prph.h" -#include "fw-dbg.h" /* * For the high priority TE use a time event type that has similar priority to @@ -130,10 +131,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk) * issue as it will have to complete before the next command is * executed, and a new time event means a new command. */ - if (iwl_mvm_is_dqa_supported(mvm)) - iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC); - else - iwl_mvm_flush_tx_path(mvm, queues, CMD_ASYNC); + iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true, CMD_ASYNC); } static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) @@ -248,7 +246,9 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TIME_EVENT); te_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, te_data->vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(te_data->vif), + trig)) return; for (i = 0; i < ARRAY_SIZE(te_trig->time_events); i++) { @@ -263,11 +263,11 @@ static void iwl_mvm_te_check_trigger(struct iwl_mvm *mvm, !(trig_status_bitmap & BIT(le32_to_cpu(notif->status)))) continue; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "Time event %d Action 0x%x received status: %d", - te_data->id, - le32_to_cpu(notif->action), - le32_to_cpu(notif->status)); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "Time event %d Action 0x%x received status: %d", + te_data->id, + le32_to_cpu(notif->action), + le32_to_cpu(notif->status)); break; } } @@ -728,8 +728,21 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + u32 id; lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->time_event_lock); + id = te_data->id; + spin_unlock_bh(&mvm->time_event_lock); + + if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { + IWL_DEBUG_TE(mvm, + "don't remove TE with id=%u (not session protection)\n", + id); + return; + } + iwl_mvm_remove_time_event(mvm, mvmvif, te_data); } @@ -861,8 +874,23 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); if (te_data->running) { - IWL_DEBUG_TE(mvm, "CS period is already scheduled\n"); - return -EBUSY; + u32 id; + + spin_lock_bh(&mvm->time_event_lock); + id = te_data->id; + spin_unlock_bh(&mvm->time_event_lock); + + if (id == TE_CHANNEL_SWITCH_PERIOD) { + IWL_DEBUG_TE(mvm, "CS period is already scheduled\n"); + return -EBUSY; + } + + /* + * Remove the session protection time event to allow the + * channel switch. If we got here, we just heard a beacon so + * the session protection is not needed anymore anyway. + */ + iwl_mvm_remove_time_event(mvm, mvmvif, te_data); } time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c index 634175b2480c..2d0b8a391308 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.c @@ -61,7 +61,7 @@ * *****************************************************************************/ #include "mvm.h" -#include "fw-api-tof.h" +#include "fw/api/tof.h" #define IWL_MVM_TOF_RANGE_REQ_MAX_ID 256 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h index 8c3421c9991d..2ff560aa1a82 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tof.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tof.h @@ -63,7 +63,7 @@ #ifndef __tof_h__ #define __tof_h__ -#include "fw-api-tof.h" +#include "fw/api/tof.h" struct iwl_mvm_tof_data { struct iwl_tof_config_cmd tof_cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 453a785a3ea5..8876c2abc440 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -71,7 +71,7 @@ #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT HZ -static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) +void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm) { struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle; u32 duration = tt->params.ct_kill_duration; @@ -629,7 +629,7 @@ static int iwl_mvm_tzone_get_temp(struct thermal_zone_device *device, mutex_lock(&mvm->mutex); if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) { + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { ret = -EIO; goto out; } @@ -680,7 +680,7 @@ static int iwl_mvm_tzone_set_trip_temp(struct thermal_zone_device *device, mutex_lock(&mvm->mutex); if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) { + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { ret = -EIO; goto out; } @@ -795,7 +795,7 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, mutex_lock(&mvm->mutex); if (!iwl_mvm_firmware_running(mvm) || - mvm->cur_ucode != IWL_UCODE_REGULAR) { + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) { ret = -EIO; goto unlock; } @@ -813,7 +813,7 @@ unlock: return ret; } -static struct thermal_cooling_device_ops tcooling_ops = { +static const struct thermal_cooling_device_ops tcooling_ops = { .get_max_state = iwl_mvm_tcool_get_max_state, .get_cur_state = iwl_mvm_tcool_get_cur_state, .set_cur_state = iwl_mvm_tcool_set_cur_state, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 5fcc9dd6be56..172b5e63d3fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -74,7 +74,6 @@ #include "iwl-eeprom-parse.h" #include "mvm.h" #include "sta.h" -#include "fw-dbg.h" static void iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, @@ -89,15 +88,15 @@ iwl_mvm_bar_check_trigger(struct iwl_mvm *mvm, const u8 *addr, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_BA); ba_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) return; if (!(le16_to_cpu(ba_trig->tx_bar) & BIT(tid))) return; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "BAR sent to %pM, tid %d, ssn %d", - addr, tid, ssn); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "BAR sent to %pM, tid %d, ssn %d", + addr, tid, ssn); } #define OPT_HDR(type, skb, off) \ @@ -559,9 +558,6 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif; - if (!iwl_mvm_is_dqa_supported(mvm)) - return info->hw_queue; - mvmvif = iwl_mvm_vif_from_mac80211(info->control.vif); switch (info->control.vif->type) { @@ -660,8 +656,7 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) if (ap_sta_id != IWL_MVM_INVALID_STA) sta_id = ap_sta_id; - } else if (iwl_mvm_is_dqa_supported(mvm) && - info.control.vif->type == NL80211_IFTYPE_MONITOR) { + } else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) { queue = mvm->aux_queue; } } @@ -680,17 +675,6 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) return -1; } - /* - * Increase the pending frames counter, so that later when a reply comes - * in and the counter is decreased - we don't start getting negative - * values. - * Note that we don't need to make sure it isn't agg'd, since we're - * TXing non-sta - * For DQA mode - we shouldn't increase it though - */ - if (!iwl_mvm_is_dqa_supported(mvm)) - atomic_inc(&mvm->pending_frames[sta_id]); - return 0; } @@ -758,7 +742,7 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, max_amsdu_len = sta->max_amsdu_len; /* the Tx FIFO to which this A-MSDU will be routed */ - txf = iwl_mvm_ac_to_tx_fifo[tid_to_mac80211_ac[tid]]; + txf = iwl_mvm_mac_ac_to_tx_fifo(mvm, tid_to_mac80211_ac[tid]); /* * Don't send an AMSDU that will be longer than the TXF. @@ -767,7 +751,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * fifo to be able to send bursts. */ max_amsdu_len = min_t(unsigned int, max_amsdu_len, - mvm->smem_cfg.lmac[0].txfifo_size[txf] - 256); + mvm->fwrt.smem_cfg.lmac[0].txfifo_size[txf] - + 256); if (unlikely(dbg_max_amsdu_len)) max_amsdu_len = min_t(unsigned int, max_amsdu_len, @@ -1000,22 +985,13 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, } } - if (iwl_mvm_is_dqa_supported(mvm) || is_ampdu) - txq_id = mvmsta->tid_data[tid].txq_id; - - if (sta->tdls && !iwl_mvm_is_dqa_supported(mvm)) { - /* default to TID 0 for non-QoS packets */ - u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid; - - txq_id = mvmsta->hw_queue[tid_to_mac80211_ac[tdls_tid]]; - } + txq_id = mvmsta->tid_data[tid].txq_id; WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); /* Check if TXQ needs to be allocated or re-activated */ if (unlikely(txq_id == IWL_MVM_INVALID_QUEUE || - !mvmsta->tid_data[tid].is_tid_active) && - iwl_mvm_is_dqa_supported(mvm)) { + !mvmsta->tid_data[tid].is_tid_active)) { /* If TXQ needs to be allocated... */ if (txq_id == IWL_MVM_INVALID_QUEUE) { iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb); @@ -1042,7 +1018,7 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, txq_id); } - if (iwl_mvm_is_dqa_supported(mvm) && !iwl_mvm_has_new_tx_api(mvm)) { + if (!iwl_mvm_has_new_tx_api(mvm)) { /* Keep track of the time of the last frame for this RA/TID */ mvm->queue_info[txq_id].last_frame_time[tid] = jiffies; @@ -1076,10 +1052,6 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb, spin_unlock(&mvmsta->lock); - /* Increase pending frames count if this isn't AMPDU or DQA queue */ - if (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu) - atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); - return 0; drop_unlock_sta: @@ -1148,8 +1120,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, lockdep_assert_held(&mvmsta->lock); if ((tid_data->state == IWL_AGG_ON || - tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA || - iwl_mvm_is_dqa_supported(mvm)) && + tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) && iwl_mvm_tid_queued(mvm, tid_data) == 0) { /* * Now that this aggregation or DQA queue is empty tell @@ -1183,13 +1154,6 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm, IWL_DEBUG_TX_QUEUES(mvm, "Can continue DELBA flow ssn = next_recl = %d\n", tid_data->next_reclaimed); - if (!iwl_mvm_is_dqa_supported(mvm)) { - u8 mac80211_ac = tid_to_mac80211_ac[tid]; - - iwl_mvm_disable_txq(mvm, tid_data->txq_id, - vif->hw_queue[mac80211_ac], tid, - CMD_ASYNC); - } tid_data->state = IWL_AGG_OFF; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -1301,7 +1265,7 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS); status_trig = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, NULL, trig)) return; for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) { @@ -1312,9 +1276,9 @@ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm, if (status_trig->statuses[i].status != (status & TX_STATUS_MSK)) continue; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, - "Tx status %d was received", - status & TX_STATUS_MSK); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, + "Tx status %d was received", + status & TX_STATUS_MSK); break; } } @@ -1373,6 +1337,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, while (!skb_queue_empty(&skbs)) { struct sk_buff *skb = __skb_dequeue(&skbs); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + bool flushed = false; skb_freed++; @@ -1386,11 +1351,15 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, case TX_STATUS_DIRECT_DONE: info->flags |= IEEE80211_TX_STAT_ACK; break; + case TX_STATUS_FAIL_FIFO_FLUSHED: + case TX_STATUS_FAIL_DRAIN_FLOW: + flushed = true; + break; case TX_STATUS_FAIL_DEST_PS: - /* In DQA, the FW should have stopped the queue and not + /* the FW should have stopped the queue and not * return this status */ - WARN_ON(iwl_mvm_is_dqa_supported(mvm)); + WARN_ON(1); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; break; default: @@ -1408,7 +1377,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, /* Single frame failure in an AMPDU queue => send BAR */ if (info->flags & IEEE80211_TX_CTL_AMPDU && !(info->flags & IEEE80211_TX_STAT_ACK) && - !(info->flags & IEEE80211_TX_STAT_TX_FILTERED)) + !(info->flags & IEEE80211_TX_STAT_TX_FILTERED) && !flushed) info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; info->flags &= ~IEEE80211_TX_CTL_AMPDU; @@ -1446,26 +1415,21 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, ieee80211_tx_status(mvm->hw, skb); } - if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue) { - /* If this is an aggregation queue, we use the ssn since: - * ssn = wifi seq_num % 256. - * The seq_ctl is the sequence control of the packet to which - * this Tx response relates. But if there is a hole in the - * bitmap of the BA we received, this Tx response may allow to - * reclaim the hole and all the subsequent packets that were - * already acked. In that case, seq_ctl != ssn, and the next - * packet to be reclaimed will be ssn and not seq_ctl. In that - * case, several packets will be reclaimed even if - * frame_count = 1. - * - * The ssn is the index (% 256) of the latest packet that has - * treated (acked / dropped) + 1. - */ - next_reclaimed = ssn; - } else { - /* The next packet to be reclaimed is the one after this one */ - next_reclaimed = IEEE80211_SEQ_TO_SN(seq_ctl + 0x10); - } + /* This is an aggregation queue or might become one, so we use + * the ssn since: ssn = wifi seq_num % 256. + * The seq_ctl is the sequence control of the packet to which + * this Tx response relates. But if there is a hole in the + * bitmap of the BA we received, this Tx response may allow to + * reclaim the hole and all the subsequent packets that were + * already acked. In that case, seq_ctl != ssn, and the next + * packet to be reclaimed will be ssn and not seq_ctl. In that + * case, several packets will be reclaimed even if + * frame_count = 1. + * + * The ssn is the index (% 256) of the latest packet that has + * treated (acked / dropped) + 1. + */ + next_reclaimed = ssn; IWL_DEBUG_TX_REPLY(mvm, "TXQ %d status %s (0x%08x)\n", @@ -1548,49 +1512,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, mvmsta = NULL; } - /* - * If the txq is not an AMPDU queue, there is no chance we freed - * several skbs. Check that out... - */ - if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue) - goto out; - - /* We can't free more than one frame at once on a shared queue */ - WARN_ON(skb_freed > 1); - - /* If we have still frames for this STA nothing to do here */ - if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) - goto out; - - if (mvmsta && mvmsta->vif->type == NL80211_IFTYPE_AP) { - - /* - * If there are no pending frames for this STA and - * the tx to this station is not disabled, notify - * mac80211 that this station can now wake up in its - * STA table. - * If mvmsta is not NULL, sta is valid. - */ - - spin_lock_bh(&mvmsta->lock); - - if (!mvmsta->disable_tx) - ieee80211_sta_block_awake(mvm->hw, sta, false); - - spin_unlock_bh(&mvmsta->lock); - } - - if (PTR_ERR(sta) == -EBUSY || PTR_ERR(sta) == -ENOENT) { - /* - * We are draining and this was the last packet - pre_rcu_remove - * has been called already. We might be after the - * synchronize_net already. - * Don't rely on iwl_mvm_rm_sta to see the empty Tx queues. - */ - set_bit(sta_id, mvm->sta_drained); - schedule_work(&mvm->sta_drained_wk); - } - out: rcu_read_unlock(); } @@ -1605,7 +1526,7 @@ static const char *iwl_get_agg_tx_status(u16 status) AGG_TX_STATE_(BT_PRIO); AGG_TX_STATE_(FEW_BYTES); AGG_TX_STATE_(ABORT); - AGG_TX_STATE_(LAST_SENT_TTL); + AGG_TX_STATE_(TX_ON_AIR_DROP); AGG_TX_STATE_(LAST_SENT_TRY_CNT); AGG_TX_STATE_(LAST_SENT_BT_KILL); AGG_TX_STATE_(SCD_QUERY); @@ -1654,9 +1575,8 @@ static void iwl_mvm_rx_tx_cmd_agg(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta; int queue = SEQ_TO_QUEUE(sequence); - if (WARN_ON_ONCE(queue < mvm->first_agg_queue && - (!iwl_mvm_is_dqa_supported(mvm) || - (queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE)))) + if (WARN_ON_ONCE(queue < IWL_MVM_DQA_MIN_DATA_QUEUE && + (queue != IWL_MVM_DQA_BSS_CLIENT_QUEUE))) return; if (WARN_ON_ONCE(tid == IWL_TID_NON_QOS)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index fc5a490880d0..2ea74abad73d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -70,9 +70,8 @@ #include "iwl-io.h" #include "iwl-prph.h" #include "iwl-csr.h" -#include "fw-dbg.h" #include "mvm.h" -#include "fw-api-rs.h" +#include "fw/api/rs.h" /* * Will return 0 even if the cmd failed when RFKILL is asserted unless @@ -464,8 +463,8 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", base, - (mvm->cur_ucode == IWL_UCODE_INIT) - ? "Init" : "RT"); + (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) + ? "Init" : "RT"); return; } @@ -500,7 +499,7 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) struct iwl_error_event_table table; u32 val; - if (mvm->cur_ucode == IWL_UCODE_INIT) { + if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) { if (!base) base = mvm->fw->init_errlog_ptr; } else { @@ -512,8 +511,8 @@ static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u32 base) IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", base, - (mvm->cur_ucode == IWL_UCODE_INIT) - ? "Init" : "RT"); + (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) + ? "Init" : "RT"); return; } @@ -1190,14 +1189,15 @@ void iwl_mvm_connection_loss(struct iwl_mvm *mvm, struct ieee80211_vif *vif, trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_MLME); trig_mlme = (void *)trig->data; - if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trig)) + if (!iwl_fw_dbg_trigger_check_stop(&mvm->fwrt, + ieee80211_vif_to_wdev(vif), trig)) goto out; if (trig_mlme->stop_connection_loss && --trig_mlme->stop_connection_loss) goto out; - iwl_mvm_fw_dbg_collect_trig(mvm, trig, "%s", errmsg); + iwl_fw_dbg_collect_trig(&mvm->fwrt, trig, "%s", errmsg); out: ieee80211_connection_loss(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index eddaca76d514..3fc4343581ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -244,7 +244,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, ctxt_info->hcmd_cfg.cmd_queue_addr = cpu_to_le64(trans_pcie->txq[trans_pcie->cmd_queue]->dma_addr); ctxt_info->hcmd_cfg.cmd_queue_size = - TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX); + TFD_QUEUE_CB_SIZE(TFD_CMD_SLOTS); /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_ctxt_info_init_fw_sec(trans, fw, ctxt_info); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 84f4ba01e14f..858765fed8f8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -430,6 +430,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x095B, 0x520A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9000, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9400, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9E10, iwl7265_2ac_cfg)}, /* 8000 Series */ {IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)}, @@ -710,12 +711,23 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iwl_trans->cfg = cfg_7265d; } - if (iwl_trans->cfg->rf_id && cfg == &iwla000_2ac_cfg_hr_cdb) { - if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_JF) - cfg = &iwla000_2ac_cfg_jf; - else if (iwl_trans->hw_rf_id == CSR_HW_RF_ID_TYPE_HR) - cfg = &iwla000_2ac_cfg_hr; - + if (iwl_trans->cfg->rf_id && cfg == &iwla000_2ac_cfg_hr_cdb && + iwl_trans->hw_rev != CSR_HW_REV_TYPE_HR_CDB) { + u32 rf_id_chp = CSR_HW_RF_ID_TYPE_CHIP_ID(iwl_trans->hw_rf_id); + u32 jf_chp_id = CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_JF); + u32 hr_chp_id = CSR_HW_RF_ID_TYPE_CHIP_ID(CSR_HW_RF_ID_TYPE_HR); + + if (rf_id_chp == jf_chp_id) { + if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QNJ) + cfg = &iwla000_2ax_cfg_qnj_jf_b0; + else + cfg = &iwla000_2ac_cfg_jf; + } else if (rf_id_chp == hr_chp_id) { + if (iwl_trans->hw_rev == CSR_HW_REV_TYPE_QNJ) + cfg = &iwla000_2ax_cfg_qnj_hr_a0; + else + cfg = &iwla000_2ac_cfg_hr; + } iwl_trans->cfg = cfg; } #endif @@ -825,11 +837,11 @@ static int iwl_pci_resume(struct device *device) /* * Enable rfkill interrupt (in order to keep track of the rfkill * status). Must be locked to avoid processing a possible rfkill - * interrupt while in iwl_trans_check_hw_rf_kill(). + * interrupt while in iwl_pcie_check_hw_rf_kill(). */ mutex_lock(&trans_pcie->mutex); iwl_enable_rfkill_int(trans); - iwl_trans_check_hw_rf_kill(trans); + iwl_pcie_check_hw_rf_kill(trans); mutex_unlock(&trans_pcie->mutex); return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index a1ea9ef97ed9..4fb7647995c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -661,10 +661,16 @@ static inline void iwl_pcie_sw_reset(struct iwl_trans *trans) usleep_range(5000, 6000); } +static inline u8 iwl_pcie_get_cmd_index(struct iwl_txq *q, u32 index) +{ + return index & (q->n_window - 1); +} + static inline void *iwl_pcie_get_tfd(struct iwl_trans_pcie *trans_pcie, struct iwl_txq *txq, int idx) { - return txq->tfds + trans_pcie->tfd_size * idx; + return txq->tfds + trans_pcie->tfd_size * iwl_pcie_get_cmd_index(txq, + idx); } static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) @@ -726,11 +732,6 @@ static inline bool iwl_queue_used(const struct iwl_txq *q, int i) !(i < q->read_ptr && i >= q->write_ptr); } -static inline u8 get_cmd_index(struct iwl_txq *q, u32 index) -{ - return index & (q->n_window - 1); -} - static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -793,7 +794,7 @@ void iwl_pcie_rx_allocator_work(struct work_struct *data); void iwl_pcie_apm_config(struct iwl_trans *trans); int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); void iwl_pcie_synchronize_irqs(struct iwl_trans *trans); -bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans); +bool iwl_pcie_check_hw_rf_kill(struct iwl_trans *trans); void iwl_trans_pcie_handle_stop_rfkill(struct iwl_trans *trans, bool was_in_rfkill); void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq); @@ -808,6 +809,8 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); void iwl_pcie_apply_destination(struct iwl_trans *trans); +void iwl_pcie_free_tso_page(struct iwl_trans_pcie *trans_pcie, + struct sk_buff *skb); #ifdef CONFIG_INET struct iwl_tso_hdr_page *get_page_hdr(struct iwl_trans *trans, size_t len); #endif diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 942736d3fa75..a06b6612b658 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -1168,7 +1168,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, sequence = le16_to_cpu(pkt->hdr.sequence); index = SEQ_TO_INDEX(sequence); - cmd_index = get_cmd_index(txq, index); + cmd_index = iwl_pcie_get_cmd_index(txq, index); if (rxq->id == 0) iwl_op_mode_rx(trans->op_mode, &rxq->napi, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index b84b78293e7b..c59f4581e972 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -307,7 +307,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, mutex_lock(&trans_pcie->mutex); /* If platform's RF_KILL switch is NOT set to KILL */ - hw_rfkill = iwl_trans_check_hw_rf_kill(trans); + hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); if (hw_rfkill && !run_in_rfkill) { ret = -ERFKILL; goto out; @@ -340,7 +340,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, goto out; /* re-check RF-Kill state since we may have missed the interrupt */ - hw_rfkill = iwl_trans_check_hw_rf_kill(trans); + hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); if (hw_rfkill && !run_in_rfkill) ret = -ERFKILL; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 3927bbf04f72..2e3e013ec95a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -986,7 +986,7 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, &first_ucode_section); } -bool iwl_trans_check_hw_rf_kill(struct iwl_trans *trans) +bool iwl_pcie_check_hw_rf_kill(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill = iwl_is_rfkill_set(trans); @@ -1252,7 +1252,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, mutex_lock(&trans_pcie->mutex); /* If platform's RF_KILL switch is NOT set to KILL */ - hw_rfkill = iwl_trans_check_hw_rf_kill(trans); + hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); if (hw_rfkill && !run_in_rfkill) { ret = -ERFKILL; goto out; @@ -1300,7 +1300,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, ret = iwl_pcie_load_given_ucode(trans, fw); /* re-check RF-Kill state since we may have missed the interrupt */ - hw_rfkill = iwl_trans_check_hw_rf_kill(trans); + hw_rfkill = iwl_pcie_check_hw_rf_kill(trans); if (hw_rfkill && !run_in_rfkill) ret = -ERFKILL; @@ -1663,7 +1663,7 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) trans_pcie->is_down = false; /* ...rfkill can call stop_device and set it false if needed */ - iwl_trans_check_hw_rf_kill(trans); + iwl_pcie_check_hw_rf_kill(trans); /* Make sure we sync here, because we'll need full access later */ if (low_power) @@ -1847,8 +1847,8 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, * These bits say the device is running, and should keep running for * at least a short while (at least as long as MAC_ACCESS_REQ stays 1), * but they do not indicate that embedded SRAM is restored yet; - * 3945 and 4965 have volatile SRAM, and must save/restore contents - * to/from host DRAM when sleeping/waking for power-saving. + * HW with volatile SRAM must save/restore contents to/from + * host DRAM when sleeping/waking for power-saving. * Each direction takes approximately 1/4 millisecond; with this * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a * series of register accesses are expected (e.g. reading Event Log), @@ -1856,8 +1856,9 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, * * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that * SRAM is okay/restored. We don't check that here because this call - * is just for hardware register access; but GP1 MAC_SLEEP check is a - * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log). + * is just for hardware register access; but GP1 MAC_SLEEP + * check is a good idea before accessing the SRAM of HW with + * volatile SRAM (e.g. reading Event Log). * * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. @@ -2839,7 +2840,7 @@ static struct iwl_trans_dump_data spin_lock_bh(&cmdq->lock); ptr = cmdq->write_ptr; for (i = 0; i < cmdq->n_window; i++) { - u8 idx = get_cmd_index(cmdq, ptr); + u8 idx = iwl_pcie_get_cmd_index(cmdq, ptr); u32 caplen, cmdlen; cmdlen = iwl_trans_pcie_get_cmdlen(trans, cmdq->tfds + @@ -3142,7 +3143,18 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, iwl_set_bit(trans, CSR_HOST_CHICKEN, CSR_HOST_CHICKEN_PM_IDLE_SRC_DIS_SB_PME); +#if IS_ENABLED(CONFIG_IWLMVM) trans->hw_rf_id = iwl_read32(trans, CSR_HW_RF_ID); + if (trans->hw_rf_id == CSR_HW_RF_ID_TYPE_HR) { + u32 hw_status; + + hw_status = iwl_read_prph(trans, UMAG_GEN_HW_STATUS); + if (hw_status & UMAG_GEN_HW_IS_FPGA) + trans->cfg = &iwla000_2ax_cfg_qnj_hr_f0; + else + trans->cfg = &iwla000_2ac_cfg_hr; + } +#endif iwl_pcie_set_interrupt_capa(pdev, trans); trans->hw_id = (pdev->device << 16) + pdev->subsystem_device; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index a3795ba0d7b9..d74613fcb756 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -55,7 +55,7 @@ #include "iwl-csr.h" #include "iwl-io.h" #include "internal.h" -#include "mvm/fw-api.h" +#include "fw/api/tx.h" /* * iwl_pcie_gen2_tx_stop - Stop all Tx DMA channels @@ -88,14 +88,14 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_txq *txq, u16 byte_cnt, int num_tbs) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = txq->bc_tbl.addr; - int write_ptr = txq->write_ptr; + int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); u8 filled_tfd_size, num_fetch_chunks; u16 len = byte_cnt; __le16 bc_ent; len = DIV_ROUND_UP(len, 4); - if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) + if (WARN_ON(len > 0xFFF || idx >= txq->n_window)) return; filled_tfd_size = offsetof(struct iwl_tfh_tfd, tbs) + @@ -111,7 +111,7 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_txq *txq, u16 byte_cnt, num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1; bc_ent = cpu_to_le16(len | (num_fetch_chunks << 12)); - scd_bc_tbl->tfd_offset[write_ptr] = bc_ent; + scd_bc_tbl->tfd_offset[idx] = bc_ent; } /* @@ -176,16 +176,12 @@ static void iwl_pcie_gen2_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) /* rd_ptr is bounded by TFD_QUEUE_SIZE_MAX and * idx is bounded by n_window */ - int rd_ptr = txq->read_ptr; - int idx = get_cmd_index(txq, rd_ptr); + int idx = iwl_pcie_get_cmd_index(txq, txq->read_ptr); lockdep_assert_held(&txq->lock); - /* We have only q->n_window txq->entries, but we use - * TFD_QUEUE_SIZE_MAX tfds - */ iwl_pcie_gen2_tfd_unmap(trans, &txq->entries[idx].meta, - iwl_pcie_get_tfd(trans_pcie, txq, rd_ptr)); + iwl_pcie_get_tfd(trans_pcie, txq, idx)); /* free SKB */ if (txq->entries) { @@ -373,8 +369,9 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); struct iwl_tfh_tfd *tfd = - iwl_pcie_get_tfd(trans_pcie, txq, txq->write_ptr); + iwl_pcie_get_tfd(trans_pcie, txq, idx); dma_addr_t tb_phys; bool amsdu; int i, len, tb1_len, tb2_len, hdr_len; @@ -386,10 +383,10 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, (*ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_A_MSDU_PRESENT); - tb_phys = iwl_pcie_get_first_tb_dma(txq, txq->write_ptr); + tb_phys = iwl_pcie_get_first_tb_dma(txq, idx); /* The first TB points to bi-directional DMA data */ if (!amsdu) - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + memcpy(&txq->first_tb_bufs[idx], &dev_cmd->hdr, IWL_FIRST_TB_SIZE); iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, IWL_FIRST_TB_SIZE); @@ -422,16 +419,16 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, hdr_len = ieee80211_hdrlen(hdr->frame_control); if (amsdu) { - if (!iwl_pcie_gen2_build_amsdu(trans, skb, tfd, - tb1_len + IWL_FIRST_TB_SIZE, - hdr_len, dev_cmd)) + if (iwl_pcie_gen2_build_amsdu(trans, skb, tfd, + tb1_len + IWL_FIRST_TB_SIZE, + hdr_len, dev_cmd)) goto out_err; /* * building the A-MSDU might have changed this data, so memcpy * it now */ - memcpy(&txq->first_tb_bufs[txq->write_ptr], &dev_cmd->hdr, + memcpy(&txq->first_tb_bufs[idx], &dev_cmd->hdr, IWL_FIRST_TB_SIZE); return tfd; } @@ -484,6 +481,7 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct iwl_cmd_meta *out_meta; struct iwl_txq *txq = trans_pcie->txq[txq_id]; + int idx; void *tfd; if (WARN_ONCE(!test_bit(txq_id, trans_pcie->queue_used), @@ -497,16 +495,18 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, spin_lock(&txq->lock); + idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); + /* Set up driver data for this TFD */ - txq->entries[txq->write_ptr].skb = skb; - txq->entries[txq->write_ptr].cmd = dev_cmd; + txq->entries[idx].skb = skb; + txq->entries[idx].cmd = dev_cmd; dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(txq->write_ptr))); + INDEX_TO_SEQ(idx))); /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_meta = &txq->entries[txq->write_ptr].meta; + out_meta = &txq->entries[idx].meta; out_meta->flags = 0; tfd = iwl_pcie_gen2_build_tfd(trans, txq, dev_cmd, skb, out_meta); @@ -562,7 +562,7 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, unsigned long flags; void *dup_buf = NULL; dma_addr_t phys_addr; - int idx, i, cmd_pos; + int i, cmd_pos, idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); u16 copy_size, cmd_size, tb0_size; bool had_nocopy = false; u8 group_id = iwl_cmd_groupid(cmd->id); @@ -651,7 +651,6 @@ static int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans, goto free_dup_buf; } - idx = get_cmd_index(txq, txq->write_ptr); out_cmd = txq->entries[idx].cmd; out_meta = &txq->entries[idx].meta; @@ -937,6 +936,15 @@ void iwl_pcie_gen2_txq_unmap(struct iwl_trans *trans, int txq_id) IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", txq_id, txq->read_ptr); + if (txq_id != trans_pcie->cmd_queue) { + int idx = iwl_pcie_get_cmd_index(txq, txq->read_ptr); + struct sk_buff *skb = txq->entries[idx].skb; + + if (WARN_ON_ONCE(!skb)) + continue; + + iwl_pcie_free_tso_page(trans_pcie, skb); + } iwl_pcie_gen2_free_tfd(trans, txq); txq->read_ptr = iwl_queue_inc_wrap(txq->read_ptr); @@ -1033,6 +1041,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, .flags = CMD_WANT_SKB, }; int ret, qid; + u32 wr_ptr; txq = kzalloc(sizeof(*txq), GFP_KERNEL); if (!txq) @@ -1060,7 +1069,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, cmd->tfdq_addr = cpu_to_le64(txq->dma_addr); cmd->byte_cnt_addr = cpu_to_le64(txq->bc_tbl.dma); - cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(TFD_QUEUE_SIZE_MAX)); + cmd->cb_size = cpu_to_le32(TFD_QUEUE_CB_SIZE(TFD_TX_CMD_SLOTS)); ret = iwl_trans_send_cmd(trans, &hcmd); if (ret) @@ -1073,6 +1082,7 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, rsp = (void *)hcmd.resp_pkt->data; qid = le16_to_cpu(rsp->queue_number); + wr_ptr = le16_to_cpu(rsp->write_pointer); if (qid >= ARRAY_SIZE(trans_pcie->txq)) { WARN_ONCE(1, "queue index %d unsupported", qid); @@ -1088,10 +1098,11 @@ int iwl_trans_pcie_dyn_txq_alloc(struct iwl_trans *trans, txq->id = qid; trans_pcie->txq[qid] = txq; + wr_ptr &= (TFD_QUEUE_SIZE_MAX - 1); /* Place first TFD at index corresponding to start sequence number */ - txq->read_ptr = le16_to_cpu(rsp->write_pointer); - txq->write_ptr = le16_to_cpu(rsp->write_pointer); + txq->read_ptr = wr_ptr; + txq->write_ptr = wr_ptr; iwl_write_direct32(trans, HBUS_TARG_WRPTR, (txq->write_ptr) | (qid << 16)); IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d\n", qid); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 034bdb4a0b06..c645d10d3707 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -43,8 +43,7 @@ #include "iwl-scd.h" #include "iwl-op-mode.h" #include "internal.h" -/* FIXME: need to abstract out TX command (once we know what it looks like) */ -#include "dvm/commands.h" +#include "fw/api/tx.h" #define IWL_TX_CRC_SIZE 4 #define IWL_TX_DELIMITER_SIZE 4 @@ -107,7 +106,7 @@ static int iwl_queue_init(struct iwl_txq *q, int slots_num) q->n_window = slots_num; /* slots_num must be power-of-two size, otherwise - * get_cmd_index is broken. */ + * iwl_pcie_get_cmd_index is broken. */ if (WARN_ON(!is_power_of_2(slots_num))) return -EINVAL; @@ -429,7 +428,7 @@ void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq) * idx is bounded by n_window */ int rd_ptr = txq->read_ptr; - int idx = get_cmd_index(txq, rd_ptr); + int idx = iwl_pcie_get_cmd_index(txq, rd_ptr); lockdep_assert_held(&txq->lock); @@ -578,8 +577,8 @@ int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq, return 0; } -static void iwl_pcie_free_tso_page(struct iwl_trans_pcie *trans_pcie, - struct sk_buff *skb) +void iwl_pcie_free_tso_page(struct iwl_trans_pcie *trans_pcie, + struct sk_buff *skb) { struct page **page_ptr; @@ -1101,7 +1100,8 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, for (; txq->read_ptr != tfd_num; txq->read_ptr = iwl_queue_inc_wrap(txq->read_ptr)) { - struct sk_buff *skb = txq->entries[txq->read_ptr].skb; + int idx = iwl_pcie_get_cmd_index(txq, txq->read_ptr); + struct sk_buff *skb = txq->entries[idx].skb; if (WARN_ON_ONCE(!skb)) continue; @@ -1110,7 +1110,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, __skb_queue_tail(skbs, skb); - txq->entries[txq->read_ptr].skb = NULL; + txq->entries[idx].skb = NULL; if (!trans->cfg->use_tfh) iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq); @@ -1560,7 +1560,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, goto free_dup_buf; } - idx = get_cmd_index(txq, txq->write_ptr); + idx = iwl_pcie_get_cmd_index(txq, txq->write_ptr); out_cmd = txq->entries[idx].cmd; out_meta = &txq->entries[idx].meta; @@ -1752,7 +1752,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, spin_lock_bh(&txq->lock); - cmd_index = get_cmd_index(txq, index); + cmd_index = iwl_pcie_get_cmd_index(txq, index); cmd = txq->entries[cmd_index].cmd; meta = &txq->entries[cmd_index].meta; group_id = cmd->hdr.group_id; @@ -2370,7 +2370,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb1_len = ALIGN(len, 4); /* Tell NIC about any 2-byte padding after MAC header */ if (tb1_len != len) - tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_MH_PAD); } else { tb1_len = len; } diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index a3c066f90afc..012930d35434 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -125,8 +125,8 @@ void hostap_remove_interface(struct net_device *dev, int rtnl_locked, else unregister_netdev(dev); - /* dev->destructor = free_netdev() will free the device data, including - * private data, when removing the device */ + /* 'dev->needs_free_netdev = true' implies device data, including + * private data, will be freed when the device is removed */ } diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index c84fd8490601..56f6e3b71f48 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -210,7 +210,7 @@ struct ezusb_packet { } __packed; /* Table of devices that work or may work with this driver */ -static struct usb_device_id ezusb_table[] = { +static const struct usb_device_id ezusb_table[] = { {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)}, {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)}, {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)}, diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c index 043bd1c23c19..b0b86f701061 100644 --- a/drivers/net/wireless/intersil/p54/p54usb.c +++ b/drivers/net/wireless/intersil/p54/p54usb.c @@ -41,7 +41,7 @@ MODULE_FIRMWARE("isl3887usb"); * whenever you add a new device. */ -static struct usb_device_id p54u_table[] = { +static const struct usb_device_id p54u_table[] = { /* Version 1 devices (pci chip + net2280) */ {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ diff --git a/drivers/net/wireless/marvell/libertas/if_usb.c b/drivers/net/wireless/marvell/libertas/if_usb.c index e53025ea6689..16e54c757dd0 100644 --- a/drivers/net/wireless/marvell/libertas/if_usb.c +++ b/drivers/net/wireless/marvell/libertas/if_usb.c @@ -52,7 +52,7 @@ static const struct lbs_fw_table fw_table[] = { { MODEL_8682, "libertas/usb8682.bin", NULL } }; -static struct usb_device_id if_usb_table[] = { +static const struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 }, { USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 }, diff --git a/drivers/net/wireless/marvell/libertas_tf/if_usb.c b/drivers/net/wireless/marvell/libertas_tf/if_usb.c index e0ade40d9497..e9104eca327b 100644 --- a/drivers/net/wireless/marvell/libertas_tf/if_usb.c +++ b/drivers/net/wireless/marvell/libertas_tf/if_usb.c @@ -31,7 +31,7 @@ module_param_named(fw_name, lbtf_fw_name, charp, 0644); MODULE_FIRMWARE("lbtf_usb.bin"); -static struct usb_device_id if_usb_table[] = { +static const struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ { USB_DEVICE(0x1286, 0x2001) }, { USB_DEVICE(0x05a3, 0x8388) }, diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index 16c77c27f1b6..725206914911 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -572,6 +572,8 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac) mwifiex_dbg(priv->adapter, CMD, "cmd: %s: tid %d\n", __func__, tid); + memset(&add_ba_req, 0, sizeof(add_ba_req)); + if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && priv->adapter->is_hw_11ac_capable && diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 06ad2d50f9b0..32c5074da84c 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -889,23 +889,15 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, switch (type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - priv->bss_num = mwifiex_get_unused_bss_num(adapter, - MWIFIEX_BSS_TYPE_STA); priv->bss_role = MWIFIEX_BSS_ROLE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: - priv->bss_num = mwifiex_get_unused_bss_num(adapter, - MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_STA; break; case NL80211_IFTYPE_P2P_GO: - priv->bss_num = mwifiex_get_unused_bss_num(adapter, - MWIFIEX_BSS_TYPE_P2P); priv->bss_role = MWIFIEX_BSS_ROLE_UAP; break; case NL80211_IFTYPE_AP: - priv->bss_num = mwifiex_get_unused_bss_num(adapter, - MWIFIEX_BSS_TYPE_UAP); priv->bss_role = MWIFIEX_BSS_ROLE_UAP; break; default: @@ -923,6 +915,8 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, adapter->rx_locked = false; spin_unlock_irqrestore(&adapter->rx_proc_lock, flags); + mwifiex_set_mac_address(priv, dev); + return 0; } @@ -2012,6 +2006,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, priv->state_11h.is_11h_active = false; } + mwifiex_config_uap_11d(priv, ¶ms->beacon); + if (mwifiex_config_start_uap(priv, bss_cfg)) { mwifiex_dbg(priv->adapter, ERROR, "Failed to start AP\n"); @@ -2963,6 +2959,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, } mwifiex_init_priv_params(priv, dev); + mwifiex_set_mac_address(priv, dev); + priv->netdev = dev; ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE, @@ -2990,7 +2988,6 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, dev_net_set(dev, wiphy_net(wiphy)); dev->ieee80211_ptr = &priv->wdev; dev->ieee80211_ptr->iftype = priv->bss_mode; - memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); dev->flags |= IFF_BROADCAST | IFF_MULTICAST; @@ -3123,11 +3120,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) priv->dfs_chan_sw_workqueue = NULL; } /* Clear the priv in adapter */ - priv->netdev->ieee80211_ptr = NULL; priv->netdev = NULL; - priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - - priv->media_connected = false; switch (priv->bss_mode) { case NL80211_IFTYPE_UNSPECIFIED: @@ -3395,11 +3388,8 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy, for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv && priv->netdev) { - mwifiex_stop_net_dev_queue(priv->netdev, adapter); - if (netif_carrier_ok(priv->netdev)) - netif_carrier_off(priv->netdev); - } + if (priv && priv->netdev) + netif_device_detach(priv->netdev); } for (i = 0; i < retry_num; i++) { @@ -3470,11 +3460,8 @@ static int mwifiex_cfg80211_resume(struct wiphy *wiphy) for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv && priv->netdev) { - if (!netif_carrier_ok(priv->netdev)) - netif_carrier_on(priv->netdev); - mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); - } + if (priv && priv->netdev) + netif_device_attach(priv->netdev); } if (!wiphy->wowlan_config) @@ -4215,7 +4202,7 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) if (adapter->config_bands & BAND_A) n_channels_a = mwifiex_band_5ghz.n_channels; - adapter->num_in_chan_stats = max_t(u32, n_channels_bg, n_channels_a); + adapter->num_in_chan_stats = n_channels_bg + n_channels_a; adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) * adapter->num_in_chan_stats); diff --git a/drivers/net/wireless/marvell/mwifiex/cfp.c b/drivers/net/wireless/marvell/mwifiex/cfp.c index 6e2994308526..bfe84e55df77 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfp.c +++ b/drivers/net/wireless/marvell/mwifiex/cfp.c @@ -180,11 +180,9 @@ static struct region_code_mapping region_code_mapping_t[] = { u8 *mwifiex_11d_code_2_region(u8 code) { u8 i; - u8 size = sizeof(region_code_mapping_t)/ - sizeof(struct region_code_mapping); /* Look for code in mapping table */ - for (i = 0; i < size; i++) + for (i = 0; i < ARRAY_SIZE(region_code_mapping_t); i++) if (region_code_mapping_t[i].code == code) return region_code_mapping_t[i].region; diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index 8dad52886034..0edc5d621304 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -26,6 +26,8 @@ #include "11n.h" #include "11ac.h" +static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); + /* * This function initializes a command node. * @@ -427,7 +429,7 @@ int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter) * The function calls the completion callback for all the command * buffers that still have response buffers associated with them. */ -int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) +void mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_array; u32 i; @@ -436,7 +438,7 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) if (!adapter->cmd_pool) { mwifiex_dbg(adapter, FATAL, "info: FREE_CMD_BUF: cmd_pool is null\n"); - return 0; + return; } cmd_array = adapter->cmd_pool; @@ -464,8 +466,6 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter) kfree(adapter->cmd_pool); adapter->cmd_pool = NULL; } - - return 0; } /* @@ -666,7 +666,7 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, cmd_no == HostCmd_CMD_802_11_SCAN_EXT) { mwifiex_queue_scan_cmd(priv, cmd_node); } else { - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node); queue_work(adapter->workqueue, &adapter->main_work); if (cmd_node->wait_q_enabled) ret = mwifiex_wait_queue_complete(adapter, cmd_node); @@ -684,11 +684,12 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no, */ void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, - struct cmd_ctrl_node *cmd_node, u32 add_tail) + struct cmd_ctrl_node *cmd_node) { struct host_cmd_ds_command *host_cmd = NULL; u16 command; unsigned long flags; + bool add_tail = true; host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data); if (!host_cmd) { @@ -1075,7 +1076,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) * In case of scan commands, all pending commands in scan pending queue * are cancelled. */ -void +static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL; diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index f6f105a7d3ff..6f4239be609d 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -940,8 +940,6 @@ mwifiex_reset_write(struct file *file, if (adapter->if_ops.card_reset) { dev_info(adapter->dev, "Resetting per request\n"); - adapter->hw_status = MWIFIEX_HW_STATUS_RESET; - mwifiex_cancel_all_pending_cmd(adapter); adapter->if_ops.card_reset(adapter); } diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 3ecb59f7405b..e11919db7818 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -337,17 +337,9 @@ void mwifiex_wake_up_net_dev_queue(struct net_device *netdev, struct mwifiex_adapter *adapter) { unsigned long dev_queue_flags; - unsigned int i; spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); - - for (i = 0; i < netdev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(netdev, i); - - if (netif_tx_queue_stopped(txq)) - netif_tx_wake_queue(txq); - } - + netif_tx_wake_all_queues(netdev); spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags); } @@ -358,30 +350,20 @@ void mwifiex_stop_net_dev_queue(struct net_device *netdev, struct mwifiex_adapter *adapter) { unsigned long dev_queue_flags; - unsigned int i; spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags); - - for (i = 0; i < netdev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(netdev, i); - - if (!netif_tx_queue_stopped(txq)) - netif_tx_stop_queue(txq); - } - + netif_tx_stop_all_queues(netdev); spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags); } /* - * This function releases the lock variables and frees the locks and - * associated locks. + * This function invalidates the list heads. */ -static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) +static void mwifiex_invalidate_lists(struct mwifiex_adapter *adapter) { struct mwifiex_private *priv; s32 i, j; - /* Free lists */ list_del(&adapter->cmd_free_q); list_del(&adapter->cmd_pending_q); list_del(&adapter->scan_pending_q); @@ -418,9 +400,11 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) mwifiex_cancel_all_pending_cmd(adapter); wake_up_interruptible(&adapter->cmd_wait_q.wait); wake_up_interruptible(&adapter->hs_activate_wait_q); +} - /* Free lock variables */ - mwifiex_free_lock_list(adapter); +void mwifiex_free_cmd_buffers(struct mwifiex_adapter *adapter) +{ + mwifiex_invalidate_lists(adapter); /* Free command buffer */ mwifiex_dbg(adapter, INFO, "info: free cmd buffer\n"); diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index b89596c18b41..d87aeff70cef 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -253,7 +253,7 @@ mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer) priv->wps_ie_len, *buffer); /* Wrap the generic IE buffer with a pass through TLV type */ - ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE); + ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); ie_header.len = cpu_to_le16(priv->wps_ie_len); memcpy(*buffer, &ie_header, sizeof(ie_header)); *buffer += sizeof(ie_header); diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index f2600b827e81..ee40b739b289 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(mfg_mode, "manufacturing mode enable:1, disable:0"); bool aggr_ctrl; module_param(aggr_ctrl, bool, 0000); -MODULE_PARM_DESC(aggr_ctrl, "usb tx aggreataon enable:1, disable:0"); +MODULE_PARM_DESC(aggr_ctrl, "usb tx aggregation enable:1, disable:0"); /* * This function registers the device and performs all the necessary @@ -588,7 +588,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) if (mwifiex_init_channel_scan_gap(adapter)) { mwifiex_dbg(adapter, ERROR, "could not init channel stats table\n"); - goto err_init_fw; + goto err_init_chan_scan; } if (driver_mode) { @@ -636,6 +636,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) err_add_intf: vfree(adapter->chan_stats); +err_init_chan_scan: wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); err_init_fw: @@ -653,6 +654,7 @@ err_dnld_fw: if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { pr_debug("info: %s: shutdown mwifiex\n", __func__); mwifiex_shutdown_drv(adapter); + mwifiex_free_cmd_buffers(adapter); } init_failed = true; @@ -665,8 +667,11 @@ done: release_firmware(adapter->firmware); adapter->firmware = NULL; } - if (init_failed) + if (init_failed) { + if (adapter->irq_wakeup >= 0) + device_init_wakeup(adapter->dev, false); mwifiex_free_adapter(adapter); + } /* Tell all current and future waiters we're finished */ complete_all(fw_done); @@ -935,31 +940,44 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -/* - * CFG802.11 network device handler for setting MAC address. - */ -static int -mwifiex_set_mac_address(struct net_device *dev, void *addr) +int mwifiex_set_mac_address(struct mwifiex_private *priv, + struct net_device *dev) { - struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - struct sockaddr *hw_addr = addr; int ret; + u64 mac_addr; - memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); + if (priv->bss_type != MWIFIEX_BSS_TYPE_P2P) + goto done; + + mac_addr = ether_addr_to_u64(priv->curr_addr); + mac_addr |= BIT_ULL(MWIFIEX_MAC_LOCAL_ADMIN_BIT); + u64_to_ether_addr(mac_addr, priv->curr_addr); /* Send request to firmware */ ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_MAC_ADDRESS, HostCmd_ACT_GEN_SET, 0, NULL, true); - if (!ret) - memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN); - else + if (ret) { mwifiex_dbg(priv->adapter, ERROR, "set mac address failed: ret=%d\n", ret); + return ret; + } +done: memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); + return 0; +} - return ret; +/* CFG802.11 network device handler for setting MAC address. + */ +static int +mwifiex_ndo_set_mac_address(struct net_device *dev, void *addr) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct sockaddr *hw_addr = addr; + + memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN); + return mwifiex_set_mac_address(priv, dev); } /* @@ -1252,7 +1270,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_open = mwifiex_open, .ndo_stop = mwifiex_close, .ndo_start_xmit = mwifiex_hard_start_xmit, - .ndo_set_mac_address = mwifiex_set_mac_address, + .ndo_set_mac_address = mwifiex_ndo_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = mwifiex_tx_timeout, .ndo_get_stats = mwifiex_get_stats, @@ -1296,7 +1314,6 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->gen_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr); - memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA || GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { @@ -1352,26 +1369,12 @@ static void mwifiex_main_work_queue(struct work_struct *work) mwifiex_main_process(adapter); } -/* - * This function gets called during PCIe function level reset. Required - * code is extracted from mwifiex_remove_card() - */ -int -mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) +/* Common teardown code used for both device removal and reset */ +static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) { struct mwifiex_private *priv; int i; - if (!adapter) - goto exit_return; - - wait_for_completion(adapter->fw_done); - /* Caller should ensure we aren't suspending while this happens */ - reinit_completion(adapter->fw_done); - - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - mwifiex_deauthenticate(priv, NULL); - /* We can no longer handle interrupts once we start doing the teardown * below. */ @@ -1380,6 +1383,7 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) adapter->surprise_removed = true; mwifiex_terminate_workqueue(adapter); + adapter->int_status = 0; /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { @@ -1393,12 +1397,9 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) } mwifiex_dbg(adapter, CMD, "cmd: calling mwifiex_shutdown_drv...\n"); - mwifiex_shutdown_drv(adapter); - if (adapter->if_ops.down_dev) - adapter->if_ops.down_dev(adapter); - mwifiex_dbg(adapter, CMD, "cmd: mwifiex_shutdown_drv done\n"); + if (atomic_read(&adapter->rx_pending) || atomic_read(&adapter->tx_pending) || atomic_read(&adapter->cmd_pending)) { @@ -1420,10 +1421,37 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + + wiphy_unregister(adapter->wiphy); + wiphy_free(adapter->wiphy); + adapter->wiphy = NULL; + vfree(adapter->chan_stats); + mwifiex_free_cmd_buffers(adapter); +} + +/* + * This function gets called during PCIe function level reset. + */ +int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + + if (!adapter) + return 0; + + wait_for_completion(adapter->fw_done); + /* Caller should ensure we aren't suspending while this happens */ + reinit_completion(adapter->fw_done); + + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + mwifiex_deauthenticate(priv, NULL); + + mwifiex_uninit_sw(adapter); + + if (adapter->if_ops.down_dev) + adapter->if_ops.down_dev(adapter); - mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); -exit_return: return 0; } EXPORT_SYMBOL_GPL(mwifiex_shutdown_sw); @@ -1506,6 +1534,7 @@ err_kmalloc: mwifiex_dbg(adapter, ERROR, "info: %s: shutdown mwifiex\n", __func__); mwifiex_shutdown_drv(adapter); + mwifiex_free_cmd_buffers(adapter); } complete_all(adapter->fw_done); @@ -1605,10 +1634,8 @@ mwifiex_add_card(void *card, struct completion *fw_done, adapter->cmd_wait_q.status = 0; adapter->scan_wait_q_woken = false; - if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB) { + if ((num_possible_cpus() > 1) || adapter->iface_type == MWIFIEX_USB) adapter->rx_work_enabled = true; - pr_notice("rx work enabled, cpus %d\n", num_possible_cpus()); - } adapter->workqueue = alloc_workqueue("MWIFIEX_WORK_QUEUE", @@ -1653,8 +1680,11 @@ err_registerdev: if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) { pr_debug("info: %s: shutdown mwifiex\n", __func__); mwifiex_shutdown_drv(adapter); + mwifiex_free_cmd_buffers(adapter); } err_kmalloc: + if (adapter->irq_wakeup >= 0) + device_init_wakeup(adapter->dev, false); mwifiex_free_adapter(adapter); err_init_sw: @@ -1676,64 +1706,10 @@ EXPORT_SYMBOL_GPL(mwifiex_add_card); */ int mwifiex_remove_card(struct mwifiex_adapter *adapter) { - struct mwifiex_private *priv = NULL; - int i; - if (!adapter) - goto exit_remove; - - /* We can no longer handle interrupts once we start doing the teardown - * below. */ - if (adapter->if_ops.disable_int) - adapter->if_ops.disable_int(adapter); - - adapter->surprise_removed = true; - - mwifiex_terminate_workqueue(adapter); - - /* Stop data */ - for (i = 0; i < adapter->priv_num; i++) { - priv = adapter->priv[i]; - if (priv && priv->netdev) { - mwifiex_stop_net_dev_queue(priv->netdev, adapter); - if (netif_carrier_ok(priv->netdev)) - netif_carrier_off(priv->netdev); - } - } - - mwifiex_dbg(adapter, CMD, - "cmd: calling mwifiex_shutdown_drv...\n"); - - mwifiex_shutdown_drv(adapter); - mwifiex_dbg(adapter, CMD, - "cmd: mwifiex_shutdown_drv done\n"); - if (atomic_read(&adapter->rx_pending) || - atomic_read(&adapter->tx_pending) || - atomic_read(&adapter->cmd_pending)) { - mwifiex_dbg(adapter, ERROR, - "rx_pending=%d, tx_pending=%d,\t" - "cmd_pending=%d\n", - atomic_read(&adapter->rx_pending), - atomic_read(&adapter->tx_pending), - atomic_read(&adapter->cmd_pending)); - } - - for (i = 0; i < adapter->priv_num; i++) { - priv = adapter->priv[i]; - - if (!priv) - continue; - - rtnl_lock(); - if (priv->netdev && - priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED) - mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); - rtnl_unlock(); - } - vfree(adapter->chan_stats); + return 0; - wiphy_unregister(adapter->wiphy); - wiphy_free(adapter->wiphy); + mwifiex_uninit_sw(adapter); if (adapter->irq_wakeup >= 0) device_init_wakeup(adapter->dev, false); @@ -1748,7 +1724,6 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter) "info: free adapter\n"); mwifiex_free_adapter(adapter); -exit_remove: return 0; } EXPORT_SYMBOL_GPL(mwifiex_remove_card); diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index f8cf3079ac7d..a76bd797e454 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -165,6 +165,8 @@ enum { /* Address alignment */ #define MWIFIEX_ALIGN_ADDR(p, a) (((long)(p) + (a) - 1) & ~((a) - 1)) +#define MWIFIEX_MAC_LOCAL_ADMIN_BIT 41 + /** *enum mwifiex_debug_level - marvell wifi debug level */ @@ -1077,9 +1079,9 @@ int mwifiex_get_debug_info(struct mwifiex_private *, struct mwifiex_debug_info *); int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter); -int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); +void mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter); +void mwifiex_free_cmd_buffers(struct mwifiex_adapter *adapter); void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter); -void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter); void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter); void mwifiex_cancel_scan(struct mwifiex_adapter *adapter); @@ -1087,8 +1089,7 @@ void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter, struct cmd_ctrl_node *cmd_node); void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter, - struct cmd_ctrl_node *cmd_node, - u32 addtail); + struct cmd_ctrl_node *cmd_node); int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter); int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter); @@ -1563,6 +1564,9 @@ int mwifiex_config_start_uap(struct mwifiex_private *priv, void mwifiex_uap_del_sta_data(struct mwifiex_private *priv, struct mwifiex_sta_node *node); +void mwifiex_config_uap_11d(struct mwifiex_private *priv, + struct cfg80211_beacon_data *beacon_data); + void mwifiex_init_11h_params(struct mwifiex_private *priv); int mwifiex_is_11h_active(struct mwifiex_private *priv); int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag); @@ -1672,6 +1676,8 @@ void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, struct sk_buff *event_skb); void mwifiex_multi_chan_resync(struct mwifiex_adapter *adapter); +int mwifiex_set_mac_address(struct mwifiex_private *priv, + struct net_device *dev); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 21f2201405d1..cd314946452c 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1043,12 +1043,14 @@ static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) mwifiex_unmap_pci_memory(adapter, card->cmdrsp_buf, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(card->cmdrsp_buf); + card->cmdrsp_buf = NULL; } if (card && card->cmd_buf) { mwifiex_unmap_pci_memory(adapter, card->cmd_buf, PCI_DMA_TODEVICE); dev_kfree_skb_any(card->cmd_buf); + card->cmd_buf = NULL; } return 0; } @@ -1983,7 +1985,8 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, * (3) wifi image. * * This function bypass the header and bluetooth part, return - * the offset of tail wifi-only part. + * the offset of tail wifi-only part. If the image is already wifi-only, + * that is start with CMD1, return 0. */ static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, @@ -1991,7 +1994,7 @@ static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, const struct mwifiex_fw_data *fwdata; u32 offset = 0, data_len, dnld_cmd; int ret = 0; - bool cmd7_before = false; + bool cmd7_before = false, first_cmd = false; while (1) { /* Check for integer and buffer overflow */ @@ -2012,20 +2015,29 @@ static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, switch (dnld_cmd) { case MWIFIEX_FW_DNLD_CMD_1: - if (!cmd7_before) { - mwifiex_dbg(adapter, ERROR, - "no cmd7 before cmd1!\n"); + if (offset + data_len < data_len) { + mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); ret = -1; goto done; } - if (offset + data_len < data_len) { - mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); + + /* Image start with cmd1, already wifi-only firmware */ + if (!first_cmd) { + mwifiex_dbg(adapter, MSG, + "input wifi-only firmware\n"); + return 0; + } + + if (!cmd7_before) { + mwifiex_dbg(adapter, ERROR, + "no cmd7 before cmd1!\n"); ret = -1; goto done; } offset += data_len; break; case MWIFIEX_FW_DNLD_CMD_5: + first_cmd = true; /* Check for integer overflow */ if (offset + data_len < data_len) { mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); @@ -2035,6 +2047,7 @@ static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, offset += data_len; break; case MWIFIEX_FW_DNLD_CMD_6: + first_cmd = true; /* Check for integer overflow */ if (offset + data_len < data_len) { mwifiex_dbg(adapter, ERROR, "bad FW parse\n"); @@ -2051,6 +2064,7 @@ static int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter, } goto done; case MWIFIEX_FW_DNLD_CMD_7: + first_cmd = true; cmd7_before = true; break; default: @@ -2428,7 +2442,7 @@ exit: * In case of Rx packets received, the packets are uploaded from card to * host and processed accordingly. */ -static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) +static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) { int ret; u32 pcie_ireg = 0; @@ -2471,28 +2485,24 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) } if (pcie_ireg & HOST_INTR_DNLD_DONE) { - pcie_ireg &= ~HOST_INTR_DNLD_DONE; mwifiex_dbg(adapter, INTR, "info: TX DNLD Done\n"); ret = mwifiex_pcie_send_data_complete(adapter); if (ret) return ret; } if (pcie_ireg & HOST_INTR_UPLD_RDY) { - pcie_ireg &= ~HOST_INTR_UPLD_RDY; mwifiex_dbg(adapter, INTR, "info: Rx DATA\n"); ret = mwifiex_pcie_process_recv_data(adapter); if (ret) return ret; } if (pcie_ireg & HOST_INTR_EVENT_RDY) { - pcie_ireg &= ~HOST_INTR_EVENT_RDY; mwifiex_dbg(adapter, INTR, "info: Rx EVENT\n"); ret = mwifiex_pcie_process_event_ready(adapter); if (ret) return ret; } if (pcie_ireg & HOST_INTR_CMD_DONE) { - pcie_ireg &= ~HOST_INTR_CMD_DONE; if (adapter->cmd_sent) { mwifiex_dbg(adapter, INTR, "info: CMD sent Interrupt\n"); @@ -2507,75 +2517,13 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter) mwifiex_dbg(adapter, INTR, "info: cmd_sent=%d data_sent=%d\n", adapter->cmd_sent, adapter->data_sent); - if (!card->msi_enable && adapter->ps_state != PS_STATE_SLEEP) + if (!card->msi_enable && !card->msix_enable && + adapter->ps_state != PS_STATE_SLEEP) mwifiex_pcie_enable_host_int(adapter); return 0; } -static int mwifiex_process_msix_int(struct mwifiex_adapter *adapter) -{ - int ret; - u32 pcie_ireg; - unsigned long flags; - - spin_lock_irqsave(&adapter->int_lock, flags); - /* Clear out unused interrupts */ - pcie_ireg = adapter->int_status; - adapter->int_status = 0; - spin_unlock_irqrestore(&adapter->int_lock, flags); - - if (pcie_ireg & HOST_INTR_DNLD_DONE) { - mwifiex_dbg(adapter, INTR, - "info: TX DNLD Done\n"); - ret = mwifiex_pcie_send_data_complete(adapter); - if (ret) - return ret; - } - if (pcie_ireg & HOST_INTR_UPLD_RDY) { - mwifiex_dbg(adapter, INTR, - "info: Rx DATA\n"); - ret = mwifiex_pcie_process_recv_data(adapter); - if (ret) - return ret; - } - if (pcie_ireg & HOST_INTR_EVENT_RDY) { - mwifiex_dbg(adapter, INTR, - "info: Rx EVENT\n"); - ret = mwifiex_pcie_process_event_ready(adapter); - if (ret) - return ret; - } - - if (pcie_ireg & HOST_INTR_CMD_DONE) { - if (adapter->cmd_sent) { - mwifiex_dbg(adapter, INTR, - "info: CMD sent Interrupt\n"); - adapter->cmd_sent = false; - } - /* Handle command response */ - ret = mwifiex_pcie_process_cmd_complete(adapter); - if (ret) - return ret; - } - - mwifiex_dbg(adapter, INTR, - "info: cmd_sent=%d data_sent=%d\n", - adapter->cmd_sent, adapter->data_sent); - - return 0; -} - -static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) -{ - struct pcie_service_card *card = adapter->card; - - if (card->msix_enable) - return mwifiex_process_msix_int(adapter); - else - return mwifiex_process_pcie_int(adapter); -} - /* * This function downloads data from driver to card. * @@ -2934,7 +2882,6 @@ static void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter) mwifiex_pcie_delete_evtbd_ring(adapter); mwifiex_pcie_delete_rxbd_ring(adapter); mwifiex_pcie_delete_txbd_ring(adapter); - card->cmdrsp_buf = NULL; } /* @@ -3036,15 +2983,14 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter) "Failed to write driver not-ready signature\n"); } - mwifiex_pcie_free_buffers(adapter); + pci_disable_device(pdev); - if (pdev) { - pci_iounmap(pdev, card->pci_mmap); - pci_iounmap(pdev, card->pci_mmap1); - pci_disable_device(pdev); - pci_release_region(pdev, 2); - pci_release_region(pdev, 0); - } + pci_iounmap(pdev, card->pci_mmap); + pci_iounmap(pdev, card->pci_mmap1); + pci_release_region(pdev, 2); + pci_release_region(pdev, 0); + + mwifiex_pcie_free_buffers(adapter); } static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) @@ -3220,7 +3166,6 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; - int ret; struct pci_dev *pdev = card->dev; /* tx_buf_size might be changed to 3584 by firmware during @@ -3228,11 +3173,9 @@ static void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter) */ adapter->tx_buf_size = card->pcie.tx_buf_size; - ret = mwifiex_pcie_alloc_buffers(adapter); - if (!ret) - return; + mwifiex_pcie_alloc_buffers(adapter); - pci_iounmap(pdev, card->pci_mmap1); + pci_set_master(pdev); } /* This function cleans up the PCI-E host memory space. */ @@ -3240,10 +3183,13 @@ static void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter) { struct pcie_service_card *card = adapter->card; const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + struct pci_dev *pdev = card->dev; if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000)) mwifiex_dbg(adapter, ERROR, "Failed to write driver not-ready signature\n"); + pci_clear_master(pdev); + adapter->seq_num = 0; mwifiex_pcie_free_buffers(adapter); diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index ae9630b49342..c9d41ed77fc7 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1534,8 +1534,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, - true); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node); queue_work(adapter->workqueue, &adapter->main_work); /* Perform internal scan synchronously */ @@ -1948,7 +1947,8 @@ mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv) } adapter->active_scan_triggered = true; - ether_addr_copy(user_scan_cfg->random_mac, priv->random_mac); + if (priv->scan_request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) + ether_addr_copy(user_scan_cfg->random_mac, priv->random_mac); user_scan_cfg->num_ssids = priv->scan_request->n_ssids; user_scan_cfg->ssid_list = priv->scan_request->ssids; @@ -2033,7 +2033,7 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) struct cmd_ctrl_node, list); list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + mwifiex_insert_cmd_to_pending_q(adapter, cmd_node); } return; @@ -2492,6 +2492,12 @@ mwifiex_update_chan_statistics(struct mwifiex_private *priv, sizeof(struct mwifiex_chan_stats); for (i = 0 ; i < num_chan; i++) { + if (adapter->survey_idx >= adapter->num_in_chan_stats) { + mwifiex_dbg(adapter, WARN, + "FW reported too many channel results (max %d)\n", + adapter->num_in_chan_stats); + return; + } chan_stats.chan_num = fw_chan_stats->chan_num; chan_stats.bandcfg = fw_chan_stats->bandcfg; chan_stats.flags = fw_chan_stats->flags; @@ -2785,7 +2791,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, if (!scan_cfg) return -ENOMEM; - ether_addr_copy(scan_cfg->random_mac, priv->random_mac); scan_cfg->ssid_list = req_ssid; scan_cfg->num_ssids = 1; diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index f81a006668f3..fd5183c10c4e 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -390,7 +390,8 @@ mwifiex_sdio_remove(struct sdio_func *func) mwifiex_dbg(adapter, INFO, "info: SDIO func num=%d\n", func->num); ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); - if (firmware_stat == FIRMWARE_READY_SDIO && !adapter->mfg_mode) { + if (!ret && firmware_stat == FIRMWARE_READY_SDIO && + !adapter->mfg_mode) { mwifiex_deauthenticate_all(adapter); priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 534d94a206a5..fb090144a6d8 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -189,9 +189,7 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, if (pbitmap_rates != NULL) { rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); - for (i = 0; - i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); - i++) + for (i = 0; i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); i++) rate_scope->ht_mcs_rate_bitmap[i] = cpu_to_le16(pbitmap_rates[2 + i]); if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { @@ -206,9 +204,7 @@ static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, cpu_to_le16(priv->bitmap_rates[0]); rate_scope->ofdm_rate_bitmap = cpu_to_le16(priv->bitmap_rates[1]); - for (i = 0; - i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); - i++) + for (i = 0; i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); i++) rate_scope->ht_mcs_rate_bitmap[i] = cpu_to_le16(priv->bitmap_rates[2 + i]); if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { @@ -1755,7 +1751,7 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, struct mwifiex_ie_types_vhtcap *vht_capab; struct mwifiex_ie_types_aid *aid; struct mwifiex_ie_types_tdls_idle_timeout *timeout; - u8 *pos, qos_info; + u8 *pos; u16 config_len = 0; struct station_parameters *params = priv->sta_params; @@ -1789,12 +1785,11 @@ mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, put_unaligned_le16(params->capability, pos); config_len += sizeof(params->capability); - qos_info = params->uapsd_queues | (params->max_sp << 5); - wmm_qos_info = (struct mwifiex_ie_types_qos_info *)(pos + - config_len); + wmm_qos_info = (void *)(pos + config_len); wmm_qos_info->header.type = cpu_to_le16(WLAN_EID_QOS_CAPA); - wmm_qos_info->header.len = cpu_to_le16(sizeof(qos_info)); - wmm_qos_info->qos_info = qos_info; + wmm_qos_info->header.len = + cpu_to_le16(sizeof(wmm_qos_info->qos_info)); + wmm_qos_info->qos_info = 0; config_len += sizeof(struct mwifiex_ie_types_qos_info); if (params->ht_capa) { diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 2945775e83c5..0fba5b10ef2d 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -298,9 +298,8 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, priv->bitmap_rates[1] = le16_to_cpu(rate_scope->ofdm_rate_bitmap); for (i = 0; - i < - sizeof(rate_scope->ht_mcs_rate_bitmap) / - sizeof(u16); i++) + i < ARRAY_SIZE(rate_scope->ht_mcs_rate_bitmap); + i++) priv->bitmap_rates[2 + i] = le16_to_cpu(rate_scope-> ht_mcs_rate_bitmap[i]); diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 42997e05d90f..a6077ab3efc3 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -654,9 +654,9 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, */ int mwifiex_disable_auto_ds(struct mwifiex_private *priv) { - struct mwifiex_ds_auto_ds auto_ds; - - auto_ds.auto_ds = DEEP_SLEEP_OFF; + struct mwifiex_ds_auto_ds auto_ds = { + .auto_ds = DEEP_SLEEP_OFF, + }; return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true); @@ -811,8 +811,8 @@ int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) * is checked to determine WPA version. If buffer length is zero, the existing * WPA IE is reset. */ -static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv, - u8 *ie_data_ptr, u16 ie_len) +static int mwifiex_set_wpa_ie(struct mwifiex_private *priv, + u8 *ie_data_ptr, u16 ie_len) { if (ie_len) { if (ie_len > sizeof(priv->wpa_ie)) { @@ -1351,101 +1351,96 @@ static int mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, u16 ie_len) { - int ret = 0; struct ieee_types_vendor_header *pvendor_ie; const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; - u16 unparsed_len = ie_len; - int find_wpa_ie = 0; + u16 unparsed_len = ie_len, cur_ie_len; /* If the passed length is zero, reset the buffer */ if (!ie_len) { priv->gen_ie_buf_len = 0; priv->wps.session_enable = false; - return 0; - } else if (!ie_data_ptr) { + } else if (!ie_data_ptr || + ie_len <= sizeof(struct ieee_types_header)) { return -1; } pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; while (pvendor_ie) { + cur_ie_len = pvendor_ie->len + sizeof(struct ieee_types_header); + + if (pvendor_ie->element_id == WLAN_EID_RSN) { + /* IE is a WPA/WPA2 IE so call set_wpa function */ + mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len); + priv->wps.session_enable = false; + goto next_ie; + } + + if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { + /* IE is a WAPI IE so call set_wapi function */ + mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie, + cur_ie_len); + goto next_ie; + } + if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) { - /* Test to see if it is a WPA IE, if not, then it is a - * gen IE + /* Test to see if it is a WPA IE, if not, then + * it is a gen IE */ if (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))) { - find_wpa_ie = 1; - break; + /* IE is a WPA/WPA2 IE so call set_wpa function + */ + mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, + cur_ie_len); + priv->wps.session_enable = false; + goto next_ie; } - /* Test to see if it is a WPS IE, if so, enable - * wps session flag - */ if (!memcmp(pvendor_ie->oui, wps_oui, sizeof(wps_oui))) { + /* Test to see if it is a WPS IE, + * if so, enable wps session flag + */ priv->wps.session_enable = true; mwifiex_dbg(priv->adapter, MSG, - "info: WPS Session Enabled.\n"); - ret = mwifiex_set_wps_ie(priv, - (u8 *)pvendor_ie, - unparsed_len); + "WPS Session Enabled.\n"); + mwifiex_set_wps_ie(priv, (u8 *)pvendor_ie, + cur_ie_len); + goto next_ie; } } - if (pvendor_ie->element_id == WLAN_EID_RSN) { - find_wpa_ie = 1; - break; - } + /* Saved in gen_ie, such as P2P IE.etc.*/ - if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { - /* IE is a WAPI IE so call set_wapi function */ - ret = mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie, - unparsed_len); - return ret; + /* Verify that the passed length is not larger than the + * available space remaining in the buffer + */ + if (cur_ie_len < + (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { + /* Append the passed data to the end + * of the genIeBuffer + */ + memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, + (u8 *)pvendor_ie, cur_ie_len); + /* Increment the stored buffer length by the + * size passed + */ + priv->gen_ie_buf_len += cur_ie_len; } - unparsed_len -= (pvendor_ie->len + - sizeof(struct ieee_types_header)); +next_ie: + unparsed_len -= cur_ie_len; if (unparsed_len <= sizeof(struct ieee_types_header)) pvendor_ie = NULL; else pvendor_ie = (struct ieee_types_vendor_header *) - (((u8 *)pvendor_ie) + pvendor_ie->len + - sizeof(struct ieee_types_header)); + (((u8 *)pvendor_ie) + cur_ie_len); } - if (find_wpa_ie) { - /* IE is a WPA/WPA2 IE so call set_wpa function */ - ret = mwifiex_set_wpa_ie_helper(priv, (u8 *)pvendor_ie, - unparsed_len); - priv->wps.session_enable = false; - return ret; - } - - /* - * Verify that the passed length is not larger than the - * available space remaining in the buffer - */ - if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { - - /* Append the passed data to the end of the - genIeBuffer */ - memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr, - ie_len); - /* Increment the stored buffer length by the - size passed */ - priv->gen_ie_buf_len += ie_len; - } else { - /* Passed data does not fit in the remaining - buffer space */ - ret = -1; - } - - /* Return 0, or -1 for error case */ - return ret; + return 0; } /* diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index 39cd677d4159..e76af2866a19 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -130,7 +130,7 @@ mwifiex_tdls_append_rates_ie(struct mwifiex_private *priv, if (skb_tailroom(skb) < rates_size + 4) { mwifiex_dbg(priv->adapter, ERROR, - "Insuffient space while adding rates\n"); + "Insufficient space while adding rates\n"); return -ENOMEM; } diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index 477c29c9f5d9..18f7d9bf30b2 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -444,6 +444,28 @@ mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size) return; } +/* This function enable 11D if userspace set the country IE. + */ +void mwifiex_config_uap_11d(struct mwifiex_private *priv, + struct cfg80211_beacon_data *beacon_data) +{ + enum state_11d_t state_11d; + const u8 *country_ie; + + country_ie = cfg80211_find_ie(WLAN_EID_COUNTRY, beacon_data->tail, + beacon_data->tail_len); + if (country_ie) { + /* Send cmd to FW to enable 11D function */ + state_11d = ENABLE_11D; + if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, + &state_11d, true)) { + mwifiex_dbg(priv->adapter, ERROR, + "11D: failed to enable 11D\n"); + } + } +} + /* This function parses BSS related parameters from structure * and prepares TLVs. These TLVs are appended to command buffer. */ @@ -848,8 +870,6 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, int mwifiex_config_start_uap(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg) { - enum state_11d_t state_11d; - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG, HostCmd_ACT_GEN_SET, UAP_BSS_PARAMS_I, bss_cfg, true)) { @@ -858,16 +878,6 @@ int mwifiex_config_start_uap(struct mwifiex_private *priv, return -1; } - /* Send cmd to FW to enable 11D function */ - state_11d = ENABLE_11D; - if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, DOT11D_I, - &state_11d, true)) { - mwifiex_dbg(priv->adapter, ERROR, - "11D: failed to enable 11D\n"); - return -1; - } - if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START, HostCmd_ACT_GEN_SET, 0, NULL, true)) { mwifiex_dbg(priv->adapter, ERROR, diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index cb1753e43ef4..f4f2b9b27e32 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -24,7 +24,7 @@ static struct mwifiex_if_ops usb_ops; -static struct usb_device_id mwifiex_usb_table[] = { +static const struct usb_device_id mwifiex_usb_table[] = { /* 8766 */ {USB_DEVICE(USB8XXX_VID, USB8766_PID_1)}, {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8766_PID_2, @@ -1112,7 +1112,7 @@ static void mwifiex_usb_tx_aggr_tmo(unsigned long context) if (err) { mwifiex_dbg(adapter, ERROR, "prepare tx aggr skb failed, err=%d\n", err); - return; + goto unlock; } if (atomic_read(&port->tx_data_urb_pending) >= @@ -1133,6 +1133,7 @@ static void mwifiex_usb_tx_aggr_tmo(unsigned long context) done: if (err == -1) mwifiex_write_data_complete(adapter, skb_send, 0, -1); +unlock: spin_unlock_irqrestore(&port->tx_aggr_lock, flags); } diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c index 660267b359e4..7f3e3983b781 100644 --- a/drivers/net/wireless/mediatek/mt7601u/dma.c +++ b/drivers/net/wireless/mediatek/mt7601u/dma.c @@ -457,6 +457,9 @@ static void mt7601u_free_tx(struct mt7601u_dev *dev) { int i; + if (!dev->tx_q) + return; + for (i = 0; i < __MT_EP_OUT_MAX; i++) mt7601u_free_tx_queue(&dev->tx_q[i]); } @@ -484,6 +487,8 @@ static int mt7601u_alloc_tx(struct mt7601u_dev *dev) dev->tx_q = devm_kcalloc(dev->dev, __MT_EP_OUT_MAX, sizeof(*dev->tx_q), GFP_KERNEL); + if (!dev->tx_q) + return -ENOMEM; for (i = 0; i < __MT_EP_OUT_MAX; i++) if (mt7601u_alloc_tx_queue(dev, &dev->tx_q[i])) diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c index 416c6045ff31..b9e4f6793138 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.c +++ b/drivers/net/wireless/mediatek/mt7601u/usb.c @@ -19,7 +19,7 @@ #include "usb.h" #include "trace.h" -static struct usb_device_id mt7601u_device_table[] = { +static const struct usb_device_id mt7601u_device_table[] = { { USB_DEVICE(0x0b05, 0x17d3) }, { USB_DEVICE(0x0e8d, 0x760a) }, { USB_DEVICE(0x0e8d, 0x760b) }, diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile index 0d618e5e5f5b..f236b7dc2be3 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/Makefile +++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile @@ -25,7 +25,3 @@ qtnfmac_pearl_pcie-objs += \ pearl/pcie.o qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o - -# - -ccflags-y += -D__CHECK_ENDIAN diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index dda05003d522..56e5fed92a2a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -130,7 +130,6 @@ static __always_inline void qtnf_bus_unlock(struct qtnf_bus *bus) /* interface functions from common layer */ -void qtnf_rx_frame(struct device *dev, struct sk_buff *rxp); int qtnf_core_attach(struct qtnf_bus *bus); void qtnf_core_detach(struct qtnf_bus *bus); void qtnf_txflowblock(struct device *dev, bool state); diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index e3c090008125..856fa6e8327e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -266,11 +266,19 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ap_settings *settings) { struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + struct qtnf_wmac *mac = wiphy_priv(wiphy); struct qtnf_bss_config *bss_cfg; int ret; - bss_cfg = &vif->bss_cfg; + if (!cfg80211_chandef_identical(&mac->chandef, &settings->chandef)) { + memcpy(&mac->chandef, &settings->chandef, sizeof(mac->chandef)); + if (vif->vifid != 0) + pr_warn("%s: unexpected chan %u (%u MHz)\n", dev->name, + settings->chandef.chan->hw_value, + settings->chandef.chan->center_freq); + } + bss_cfg = &vif->bss_cfg; memset(bss_cfg, 0, sizeof(*bss_cfg)); bss_cfg->bcn_period = settings->beacon_interval; @@ -281,8 +289,6 @@ static int qtnf_start_ap(struct wiphy *wiphy, struct net_device *dev, bss_cfg->ssid_len = settings->ssid_len; memcpy(&bss_cfg->ssid, settings->ssid, bss_cfg->ssid_len); - memcpy(&bss_cfg->chandef, &settings->chandef, - sizeof(struct cfg80211_chan_def)); memcpy(&bss_cfg->crypto, &settings->crypto, sizeof(struct cfg80211_crypto_settings)); @@ -573,19 +579,33 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev, return ret; } +static void qtnf_scan_timeout(unsigned long data) +{ + struct qtnf_wmac *mac = (struct qtnf_wmac *)data; + + pr_warn("mac%d scan timed out\n", mac->macid); + qtnf_scan_done(mac, true); +} + static int qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct qtnf_wmac *mac = wiphy_priv(wiphy); - int ret; mac->scan_req = request; - ret = qtnf_cmd_send_scan(mac); - if (ret) + if (qtnf_cmd_send_scan(mac)) { pr_err("MAC%u: failed to start scan\n", mac->macid); + mac->scan_req = NULL; + return -EFAULT; + } - return ret; + mac->scan_timeout.data = (unsigned long)mac; + mac->scan_timeout.function = qtnf_scan_timeout; + mod_timer(&mac->scan_timeout, + jiffies + QTNF_SCAN_TIMEOUT_SEC * HZ); + + return 0; } static int @@ -593,6 +613,8 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct cfg80211_chan_def chandef; struct qtnf_bss_config *bss_cfg; int ret; @@ -605,9 +627,20 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev, bss_cfg = &vif->bss_cfg; memset(bss_cfg, 0, sizeof(*bss_cfg)); + if (sme->channel) { + /* FIXME: need to set proper nl80211_channel_type value */ + cfg80211_chandef_create(&chandef, sme->channel, + NL80211_CHAN_HT20); + /* fall-back to minimal safe chandef description */ + if (!cfg80211_chandef_valid(&chandef)) + cfg80211_chandef_create(&chandef, sme->channel, + NL80211_CHAN_HT20); + + memcpy(&mac->chandef, &chandef, sizeof(mac->chandef)); + } + bss_cfg->ssid_len = sme->ssid_len; memcpy(&bss_cfg->ssid, sme->ssid, bss_cfg->ssid_len); - bss_cfg->chandef.chan = sme->channel; bss_cfg->auth_type = sme->auth_type; bss_cfg->privacy = sme->privacy; bss_cfg->mfp = sme->mfp; @@ -677,6 +710,175 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int +qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev, + int idx, struct survey_info *survey) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct ieee80211_supported_band *sband; + struct cfg80211_chan_def *chandef; + struct ieee80211_channel *chan; + struct qtnf_chan_stats stats; + struct qtnf_vif *vif; + int ret; + + vif = qtnf_netdev_get_priv(dev); + chandef = &mac->chandef; + + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (sband && idx >= sband->n_channels) { + idx -= sband->n_channels; + sband = NULL; + } + + if (!sband) + sband = wiphy->bands[NL80211_BAND_5GHZ]; + + if (!sband || idx >= sband->n_channels) + return -ENOENT; + + chan = &sband->channels[idx]; + memset(&stats, 0, sizeof(stats)); + + survey->channel = chan; + survey->filled = 0x0; + + if (chandef->chan) { + if (chan->hw_value == chandef->chan->hw_value) + survey->filled = SURVEY_INFO_IN_USE; + } + + ret = qtnf_cmd_get_chan_stats(mac, chan->hw_value, &stats); + switch (ret) { + case 0: + if (unlikely(stats.chan_num != chan->hw_value)) { + pr_err("received stats for channel %d instead of %d\n", + stats.chan_num, chan->hw_value); + ret = -EINVAL; + break; + } + + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_SCAN | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_TX | + SURVEY_INFO_NOISE_DBM; + + survey->time_scan = stats.cca_try; + survey->time = stats.cca_try; + survey->time_tx = stats.cca_tx; + survey->time_rx = stats.cca_rx; + survey->time_busy = stats.cca_busy; + survey->noise = stats.chan_noise; + break; + case -ENOENT: + pr_debug("no stats for channel %u\n", chan->hw_value); + ret = 0; + break; + default: + pr_debug("failed to get chan(%d) stats from card\n", + chan->hw_value); + ret = -EINVAL; + break; + } + + return ret; +} + +static int +qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct net_device *ndev = wdev->netdev; + struct qtnf_vif *vif; + + if (!ndev) + return -ENODEV; + + vif = qtnf_netdev_get_priv(wdev->netdev); + + switch (vif->wdev.iftype) { + case NL80211_IFTYPE_STATION: + if (vif->sta_state == QTNF_STA_DISCONNECTED) { + pr_warn("%s: STA disconnected\n", ndev->name); + return -ENODATA; + } + break; + case NL80211_IFTYPE_AP: + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_warn("%s: AP not started\n", ndev->name); + return -ENODATA; + } + break; + default: + pr_err("unsupported vif type (%d)\n", vif->wdev.iftype); + return -ENODATA; + } + + if (!cfg80211_chandef_valid(&mac->chandef)) { + pr_err("invalid channel settings on %s\n", ndev->name); + return -ENODATA; + } + + memcpy(chandef, &mac->chandef, sizeof(*chandef)); + return 0; +} + +static int qtnf_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +{ + struct qtnf_wmac *mac = wiphy_priv(wiphy); + struct qtnf_vif *vif = qtnf_netdev_get_priv(dev); + int ret; + + pr_debug("%s: chan(%u) count(%u) radar(%u) block_tx(%u)\n", dev->name, + params->chandef.chan->hw_value, params->count, + params->radar_required, params->block_tx); + + switch (vif->wdev.iftype) { + case NL80211_IFTYPE_AP: + if (!(vif->bss_status & QTNF_STATE_AP_START)) { + pr_warn("AP not started on %s\n", dev->name); + return -ENOTCONN; + } + break; + default: + pr_err("unsupported vif type (%d) on %s\n", + vif->wdev.iftype, dev->name); + return -EOPNOTSUPP; + } + + if (vif->vifid != 0) { + if (!(mac->status & QTNF_MAC_CSA_ACTIVE)) + return -EOPNOTSUPP; + + if (!cfg80211_chandef_identical(¶ms->chandef, + &mac->csa_chandef)) + return -EINVAL; + + return 0; + } + + if (!cfg80211_chandef_valid(¶ms->chandef)) { + pr_err("%s: invalid channel\n", dev->name); + return -EINVAL; + } + + if (cfg80211_chandef_identical(¶ms->chandef, &mac->chandef)) { + pr_err("%s: switch request to the same channel\n", dev->name); + return -EALREADY; + } + + ret = qtnf_cmd_send_chan_switch(mac, params); + if (ret) + pr_warn("%s: failed to switch to channel (%u)\n", + dev->name, params->chandef.chan->hw_value); + + return ret; +} + static struct cfg80211_ops qtn_cfg80211_ops = { .add_virtual_intf = qtnf_add_virtual_intf, .change_virtual_intf = qtnf_change_virtual_intf, @@ -697,69 +899,49 @@ static struct cfg80211_ops qtn_cfg80211_ops = { .set_default_mgmt_key = qtnf_set_default_mgmt_key, .scan = qtnf_scan, .connect = qtnf_connect, - .disconnect = qtnf_disconnect + .disconnect = qtnf_disconnect, + .dump_survey = qtnf_dump_survey, + .get_channel = qtnf_get_channel, + .channel_switch = qtnf_channel_switch }; -static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy, +static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in, struct regulatory_request *req) { - struct qtnf_wmac *mac = wiphy_priv(wiphy); - struct qtnf_bus *bus; - struct qtnf_vif *vif; - struct qtnf_wmac *chan_mac; - int i; + struct qtnf_wmac *mac = wiphy_priv(wiphy_in); + struct qtnf_bus *bus = mac->bus; + struct wiphy *wiphy; + unsigned int mac_idx; enum nl80211_band band; - - bus = mac->bus; + int ret; pr_debug("MAC%u: initiator=%d alpha=%c%c\n", mac->macid, req->initiator, req->alpha2[0], req->alpha2[1]); - vif = qtnf_mac_get_base_vif(mac); - if (!vif) { - pr_err("MAC%u: primary VIF is not configured\n", mac->macid); - return; - } - - /* ignore non-ISO3166 country codes */ - for (i = 0; i < sizeof(req->alpha2); i++) { - if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { - pr_err("MAC%u: not an ISO3166 code\n", mac->macid); - return; - } - } - if (!strncasecmp(req->alpha2, bus->hw_info.alpha2_code, - sizeof(req->alpha2))) { - pr_warn("MAC%u: unchanged country code\n", mac->macid); - return; - } - - if (qtnf_cmd_send_regulatory_config(mac, req->alpha2)) { - pr_err("MAC%u: failed to configure regulatory\n", mac->macid); + ret = qtnf_cmd_reg_notify(bus, req); + if (ret) { + if (ret != -EOPNOTSUPP && ret != -EALREADY) + pr_err("failed to update reg domain to %c%c\n", + req->alpha2[0], req->alpha2[1]); return; } - for (i = 0; i < bus->hw_info.num_mac; i++) { - chan_mac = bus->mac[i]; - - if (!chan_mac) + for (mac_idx = 0; mac_idx < QTNF_MAX_MAC; ++mac_idx) { + if (!(bus->hw_info.mac_bitmap & (1 << mac_idx))) continue; - if (!(bus->hw_info.mac_bitmap & BIT(i))) - continue; + mac = bus->mac[mac_idx]; + wiphy = priv_to_wiphy(mac); for (band = 0; band < NUM_NL80211_BANDS; ++band) { if (!wiphy->bands[band]) continue; - if (qtnf_cmd_get_mac_chan_info(chan_mac, - wiphy->bands[band])) { - pr_err("MAC%u: can't get channel info\n", - chan_mac->macid); - qtnf_core_detach(bus); - - return; - } + ret = qtnf_cmd_get_mac_chan_info(mac, + wiphy->bands[band]); + if (ret) + pr_err("failed to get chan info for mac %u band %u\n", + mac_idx, band); } } } @@ -844,10 +1026,8 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) } iface_comb = kzalloc(sizeof(*iface_comb), GFP_KERNEL); - if (!iface_comb) { - ret = -ENOMEM; - goto out; - } + if (!iface_comb) + return -ENOMEM; ret = qtnf_wiphy_setup_if_comb(wiphy, iface_comb, &mac->macinfo); if (ret) @@ -869,6 +1049,7 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) wiphy->iface_combinations = iface_comb; wiphy->n_iface_combinations = 1; + wiphy->max_num_csa_counters = 2; /* Initialize cipher suits */ wiphy->cipher_suites = qtnf_cipher_suites; @@ -876,7 +1057,8 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | - WIPHY_FLAG_AP_UAPSD; + WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; @@ -889,21 +1071,26 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac) ether_addr_copy(wiphy->perm_addr, mac->macaddr); if (hw_info->hw_capab & QLINK_HW_SUPPORTS_REG_UPDATE) { - pr_debug("device supports REG_UPDATE\n"); + wiphy->regulatory_flags |= REGULATORY_STRICT_REG | + REGULATORY_CUSTOM_REG; wiphy->reg_notifier = qtnf_cfg80211_reg_notifier; - pr_debug("hint regulatory about EP region: %c%c\n", - hw_info->alpha2_code[0], - hw_info->alpha2_code[1]); - regulatory_hint(wiphy, hw_info->alpha2_code); + wiphy_apply_custom_regulatory(wiphy, hw_info->rd); } else { - pr_debug("device doesn't support REG_UPDATE\n"); wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; } ret = wiphy_register(wiphy); + if (ret < 0) + goto out; + + if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) + ret = regulatory_set_wiphy_regd(wiphy, hw_info->rd); + else if (isalpha(hw_info->rd->alpha2[0]) && + isalpha(hw_info->rd->alpha2[1])) + ret = regulatory_hint(wiphy, hw_info->rd->alpha2); out: - if (ret < 0) { + if (ret) { kfree(iface_comb); return ret; } diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h index 5bd33124a7c8..6a4af52522b8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.h @@ -34,10 +34,14 @@ static inline void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted) .aborted = aborted, }; + mutex_lock(&mac->mac_lock); + if (mac->scan_req) { cfg80211_scan_done(mac->scan_req, &info); mac->scan_req = NULL; } + + mutex_unlock(&mac->mac_lock); } #endif /* _QTN_FMAC_CFG80211_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index b39dbc3d3c1f..4206886b110c 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -181,43 +181,11 @@ out: return ret; } -int qtnf_cmd_send_regulatory_config(struct qtnf_wmac *mac, const char *alpha2) -{ - struct sk_buff *cmd_skb; - u16 res_code = QLINK_CMD_RESULT_OK; - int ret; - - cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, - QLINK_CMD_REG_REGION, - sizeof(struct qlink_cmd)); - if (unlikely(!cmd_skb)) - return -ENOMEM; - - qtnf_cmd_skb_put_tlv_arr(cmd_skb, WLAN_EID_COUNTRY, alpha2, - QTNF_MAX_ALPHA_LEN); - - ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); - - if (unlikely(ret)) - goto out; - - if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { - pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); - ret = -EFAULT; - goto out; - } - - memcpy(mac->bus->hw_info.alpha2_code, alpha2, - sizeof(mac->bus->hw_info.alpha2_code)); -out: - return ret; -} - int qtnf_cmd_send_config_ap(struct qtnf_vif *vif) { struct sk_buff *cmd_skb; struct qtnf_bss_config *bss_cfg = &vif->bss_cfg; - struct cfg80211_chan_def *chandef = &bss_cfg->chandef; + struct cfg80211_chan_def *chandef = &vif->mac->chandef; struct qlink_tlv_channel *qchan; struct qlink_auth_encr aen; u16 res_code = QLINK_CMD_RESULT_OK; @@ -848,25 +816,168 @@ out: return ret; } +static u32 qtnf_cmd_resp_reg_rule_flags_parse(u32 qflags) +{ + u32 flags = 0; + + if (qflags & QLINK_RRF_NO_OFDM) + flags |= NL80211_RRF_NO_OFDM; + + if (qflags & QLINK_RRF_NO_CCK) + flags |= NL80211_RRF_NO_CCK; + + if (qflags & QLINK_RRF_NO_INDOOR) + flags |= NL80211_RRF_NO_INDOOR; + + if (qflags & QLINK_RRF_NO_OUTDOOR) + flags |= NL80211_RRF_NO_OUTDOOR; + + if (qflags & QLINK_RRF_DFS) + flags |= NL80211_RRF_DFS; + + if (qflags & QLINK_RRF_PTP_ONLY) + flags |= NL80211_RRF_PTP_ONLY; + + if (qflags & QLINK_RRF_PTMP_ONLY) + flags |= NL80211_RRF_PTMP_ONLY; + + if (qflags & QLINK_RRF_NO_IR) + flags |= NL80211_RRF_NO_IR; + + if (qflags & QLINK_RRF_AUTO_BW) + flags |= NL80211_RRF_AUTO_BW; + + if (qflags & QLINK_RRF_IR_CONCURRENT) + flags |= NL80211_RRF_IR_CONCURRENT; + + if (qflags & QLINK_RRF_NO_HT40MINUS) + flags |= NL80211_RRF_NO_HT40MINUS; + + if (qflags & QLINK_RRF_NO_HT40PLUS) + flags |= NL80211_RRF_NO_HT40PLUS; + + if (qflags & QLINK_RRF_NO_80MHZ) + flags |= NL80211_RRF_NO_80MHZ; + + if (qflags & QLINK_RRF_NO_160MHZ) + flags |= NL80211_RRF_NO_160MHZ; + + return flags; +} + static int qtnf_cmd_resp_proc_hw_info(struct qtnf_bus *bus, - const struct qlink_resp_get_hw_info *resp) + const struct qlink_resp_get_hw_info *resp, + size_t info_len) { struct qtnf_hw_info *hwinfo = &bus->hw_info; + const struct qlink_tlv_hdr *tlv; + const struct qlink_tlv_reg_rule *tlv_rule; + struct ieee80211_reg_rule *rule; + u16 tlv_type; + u16 tlv_value_len; + unsigned int rule_idx = 0; + + if (WARN_ON(resp->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) + return -E2BIG; + + hwinfo->rd = kzalloc(sizeof(*hwinfo->rd) + + sizeof(struct ieee80211_reg_rule) + * resp->n_reg_rules, GFP_KERNEL); + + if (!hwinfo->rd) + return -ENOMEM; hwinfo->num_mac = resp->num_mac; hwinfo->mac_bitmap = resp->mac_bitmap; hwinfo->fw_ver = le32_to_cpu(resp->fw_ver); hwinfo->ql_proto_ver = le16_to_cpu(resp->ql_proto_ver); - memcpy(hwinfo->alpha2_code, resp->alpha2_code, - sizeof(hwinfo->alpha2_code)); hwinfo->total_tx_chain = resp->total_tx_chain; hwinfo->total_rx_chain = resp->total_rx_chain; hwinfo->hw_capab = le32_to_cpu(resp->hw_capab); + hwinfo->rd->n_reg_rules = resp->n_reg_rules; + hwinfo->rd->alpha2[0] = resp->alpha2[0]; + hwinfo->rd->alpha2[1] = resp->alpha2[1]; + + switch (resp->dfs_region) { + case QLINK_DFS_FCC: + hwinfo->rd->dfs_region = NL80211_DFS_FCC; + break; + case QLINK_DFS_ETSI: + hwinfo->rd->dfs_region = NL80211_DFS_ETSI; + break; + case QLINK_DFS_JP: + hwinfo->rd->dfs_region = NL80211_DFS_JP; + break; + case QLINK_DFS_UNSET: + default: + hwinfo->rd->dfs_region = NL80211_DFS_UNSET; + break; + } + + tlv = (const struct qlink_tlv_hdr *)resp->info; + + while (info_len >= sizeof(*tlv)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + + if (tlv_value_len + sizeof(*tlv) > info_len) { + pr_warn("malformed TLV 0x%.2X; LEN: %u\n", + tlv_type, tlv_value_len); + return -EINVAL; + } + + switch (tlv_type) { + case QTN_TLV_ID_REG_RULE: + if (rule_idx >= resp->n_reg_rules) { + pr_warn("unexpected number of rules: %u\n", + resp->n_reg_rules); + return -EINVAL; + } + + if (tlv_value_len != sizeof(*tlv_rule) - sizeof(*tlv)) { + pr_warn("malformed TLV 0x%.2X; LEN: %u\n", + tlv_type, tlv_value_len); + return -EINVAL; + } + + tlv_rule = (const struct qlink_tlv_reg_rule *)tlv; + rule = &hwinfo->rd->reg_rules[rule_idx++]; + + rule->freq_range.start_freq_khz = + le32_to_cpu(tlv_rule->start_freq_khz); + rule->freq_range.end_freq_khz = + le32_to_cpu(tlv_rule->end_freq_khz); + rule->freq_range.max_bandwidth_khz = + le32_to_cpu(tlv_rule->max_bandwidth_khz); + rule->power_rule.max_antenna_gain = + le32_to_cpu(tlv_rule->max_antenna_gain); + rule->power_rule.max_eirp = + le32_to_cpu(tlv_rule->max_eirp); + rule->dfs_cac_ms = + le32_to_cpu(tlv_rule->dfs_cac_ms); + rule->flags = qtnf_cmd_resp_reg_rule_flags_parse( + le32_to_cpu(tlv_rule->flags)); + break; + default: + break; + } + + info_len -= tlv_value_len + sizeof(*tlv); + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (rule_idx != resp->n_reg_rules) { + pr_warn("unexpected number of rules: expected %u got %u\n", + resp->n_reg_rules, rule_idx); + kfree(hwinfo->rd); + hwinfo->rd = NULL; + return -EINVAL; + } pr_info("fw_version=%d, MACs map %#x, alpha2=\"%c%c\", chains Tx=%u Rx=%u\n", hwinfo->fw_ver, hwinfo->mac_bitmap, - hwinfo->alpha2_code[0], hwinfo->alpha2_code[1], + hwinfo->rd->alpha2[0], hwinfo->rd->alpha2[1], hwinfo->total_tx_chain, hwinfo->total_rx_chain); return 0; @@ -878,7 +989,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, struct ieee80211_iface_limit *limits = NULL; const struct qlink_iface_limit *limit_record; size_t record_count = 0, rec = 0; - u16 tlv_type, tlv_value_len, mask; + u16 tlv_type, tlv_value_len; struct qlink_iface_comb_num *comb; size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; @@ -931,10 +1042,12 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, limit_record = (void *)tlv->val; limits[rec].max = le16_to_cpu(limit_record->max_num); - mask = le16_to_cpu(limit_record->type_mask); - limits[rec].types = qlink_iface_type_mask_to_nl(mask); - /* only AP and STA modes are supported */ + limits[rec].types = qlink_iface_type_to_nl_mask( + le16_to_cpu(limit_record->type)); + + /* supported modes: STA, AP */ limits[rec].types &= BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_AP_VLAN) | BIT(NL80211_IFTYPE_STATION); pr_debug("MAC%u: MAX: %u; TYPES: %.4X\n", mac->macid, @@ -946,6 +1059,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac, default: break; } + tlv_buf_size -= tlv_full_len; tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } @@ -1013,14 +1127,24 @@ qtnf_cmd_resp_fill_channels_info(struct ieee80211_supported_band *band, unsigned int chidx = 0; u32 qflags; - kfree(band->channels); - band->channels = NULL; + if (band->channels) { + if (band->n_channels == resp->num_chans) { + memset(band->channels, 0, + sizeof(*band->channels) * band->n_channels); + } else { + kfree(band->channels); + band->n_channels = 0; + band->channels = NULL; + } + } band->n_channels = resp->num_chans; if (band->n_channels == 0) return 0; - band->channels = kcalloc(band->n_channels, sizeof(*chan), GFP_KERNEL); + if (!band->channels) + band->channels = kcalloc(band->n_channels, sizeof(*chan), + GFP_KERNEL); if (!band->channels) { band->n_channels = 0; return -ENOMEM; @@ -1212,6 +1336,62 @@ static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac, return 0; } +static int +qtnf_cmd_resp_proc_chan_stat_info(struct qtnf_chan_stats *stats, + const u8 *payload, size_t payload_len) +{ + struct qlink_chan_stats *qlink_stats; + const struct qlink_tlv_hdr *tlv; + size_t tlv_full_len; + u16 tlv_value_len; + u16 tlv_type; + + tlv = (struct qlink_tlv_hdr *)payload; + while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); + if (tlv_full_len > payload_len) { + pr_warn("malformed TLV 0x%.2X; LEN: %u\n", + tlv_type, tlv_value_len); + return -EINVAL; + } + switch (tlv_type) { + case QTN_TLV_ID_CHANNEL_STATS: + if (unlikely(tlv_value_len != sizeof(*qlink_stats))) { + pr_err("invalid CHANNEL_STATS entry size\n"); + return -EINVAL; + } + + qlink_stats = (void *)tlv->val; + + stats->chan_num = le32_to_cpu(qlink_stats->chan_num); + stats->cca_tx = le32_to_cpu(qlink_stats->cca_tx); + stats->cca_rx = le32_to_cpu(qlink_stats->cca_rx); + stats->cca_busy = le32_to_cpu(qlink_stats->cca_busy); + stats->cca_try = le32_to_cpu(qlink_stats->cca_try); + stats->chan_noise = qlink_stats->chan_noise; + + pr_debug("chan(%u) try(%u) busy(%u) noise(%d)\n", + stats->chan_num, stats->cca_try, + stats->cca_busy, stats->chan_noise); + break; + default: + pr_warn("Unknown TLV type: %#x\n", + le16_to_cpu(tlv->type)); + } + payload_len -= tlv_full_len; + tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); + } + + if (payload_len) { + pr_warn("malformed TLV buf; bytes left: %zu\n", payload_len); + return -EINVAL; + } + + return 0; +} + int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac) { struct sk_buff *cmd_skb, *resp_skb = NULL; @@ -1256,6 +1436,7 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) const struct qlink_resp_get_hw_info *resp; u16 res_code = QLINK_CMD_RESULT_OK; int ret = 0; + size_t info_len; cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, QLINK_CMD_GET_HW_INFO, @@ -1266,7 +1447,7 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) qtnf_bus_lock(bus); ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, - sizeof(*resp), NULL); + sizeof(*resp), &info_len); if (unlikely(ret)) goto out; @@ -1278,7 +1459,7 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus) } resp = (const struct qlink_resp_get_hw_info *)resp_skb->data; - ret = qtnf_cmd_resp_proc_hw_info(bus, resp); + ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len); out: qtnf_bus_unlock(bus); @@ -1320,6 +1501,9 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, cmd = (struct qlink_cmd_chans_info_get *)cmd_skb->data; cmd->band = qband; + + qtnf_bus_lock(mac->bus); + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, sizeof(*resp), &info_len); @@ -1343,6 +1527,7 @@ int qtnf_cmd_get_mac_chan_info(struct qtnf_wmac *mac, ret = qtnf_cmd_resp_fill_channels_info(band, resp, info_len); out: + qtnf_bus_unlock(mac->bus); consume_skb(resp_skb); return ret; @@ -1676,10 +1861,27 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac, cmd = (struct qlink_cmd_change_sta *)cmd_skb->data; ether_addr_copy(cmd->sta_addr, mac); - cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags( - params->sta_flags_mask)); - cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags( - params->sta_flags_set)); + + switch (vif->wdev.iftype) { + case NL80211_IFTYPE_AP: + cmd->if_type = cpu_to_le16(QLINK_IFTYPE_AP); + cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_mask)); + cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_set)); + break; + case NL80211_IFTYPE_STATION: + cmd->if_type = cpu_to_le16(QLINK_IFTYPE_STATION); + cmd->sta_flags_mask = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_mask)); + cmd->sta_flags_set = cpu_to_le32(qtnf_encode_sta_flags( + params->sta_flags_set)); + break; + default: + pr_err("unsupported iftype %d\n", vif->wdev.iftype); + ret = -EINVAL; + goto out; + } ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); if (unlikely(ret)) @@ -1853,8 +2055,8 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, ether_addr_copy(cmd->bssid, bss_cfg->bssid); - if (bss_cfg->chandef.chan) - cmd->freq = cpu_to_le16(bss_cfg->chandef.chan->center_freq); + if (vif->mac->chandef.chan) + cmd->channel = cpu_to_le16(vif->mac->chandef.chan->hw_value); cmd->bg_scan_period = cpu_to_le16(bss_cfg->bg_scan_period); @@ -1976,3 +2178,183 @@ out: qtnf_bus_unlock(vif->mac->bus); return ret; } + +int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req) +{ + struct sk_buff *cmd_skb; + int ret; + u16 res_code; + struct qlink_cmd_reg_notify *cmd; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, + QLINK_CMD_REG_NOTIFY, + sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_reg_notify *)cmd_skb->data; + cmd->alpha2[0] = req->alpha2[0]; + cmd->alpha2[1] = req->alpha2[1]; + + switch (req->initiator) { + case NL80211_REGDOM_SET_BY_CORE: + cmd->initiator = QLINK_REGDOM_SET_BY_CORE; + break; + case NL80211_REGDOM_SET_BY_USER: + cmd->initiator = QLINK_REGDOM_SET_BY_USER; + break; + case NL80211_REGDOM_SET_BY_DRIVER: + cmd->initiator = QLINK_REGDOM_SET_BY_DRIVER; + break; + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + cmd->initiator = QLINK_REGDOM_SET_BY_COUNTRY_IE; + break; + } + + switch (req->user_reg_hint_type) { + case NL80211_USER_REG_HINT_USER: + cmd->user_reg_hint_type = QLINK_USER_REG_HINT_USER; + break; + case NL80211_USER_REG_HINT_CELL_BASE: + cmd->user_reg_hint_type = QLINK_USER_REG_HINT_CELL_BASE; + break; + case NL80211_USER_REG_HINT_INDOOR: + cmd->user_reg_hint_type = QLINK_USER_REG_HINT_INDOOR; + break; + } + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send(bus, cmd_skb, &res_code); + if (ret) + goto out; + + switch (res_code) { + case QLINK_CMD_RESULT_ENOTSUPP: + pr_warn("reg update not supported\n"); + ret = -EOPNOTSUPP; + break; + case QLINK_CMD_RESULT_EALREADY: + pr_info("regulatory domain is already set to %c%c", + req->alpha2[0], req->alpha2[1]); + ret = -EALREADY; + break; + case QLINK_CMD_RESULT_OK: + ret = 0; + break; + default: + ret = -EFAULT; + break; + } + +out: + qtnf_bus_unlock(bus); + + return ret; +} + +int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel, + struct qtnf_chan_stats *stats) +{ + struct sk_buff *cmd_skb, *resp_skb = NULL; + struct qlink_cmd_get_chan_stats *cmd; + struct qlink_resp_get_chan_stats *resp; + size_t var_data_len; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, + QLINK_CMD_CHAN_STATS, + sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data; + cmd->channel = cpu_to_le16(channel); + + ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, + sizeof(*resp), &var_data_len); + if (unlikely(ret)) { + qtnf_bus_unlock(mac->bus); + return ret; + } + + if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { + switch (res_code) { + case QLINK_CMD_RESULT_ENOTFOUND: + ret = -ENOENT; + break; + default: + pr_err("cmd exec failed: 0x%.4X\n", res_code); + ret = -EFAULT; + break; + } + goto out; + } + + resp = (struct qlink_resp_get_chan_stats *)resp_skb->data; + ret = qtnf_cmd_resp_proc_chan_stat_info(stats, resp->info, + var_data_len); + +out: + qtnf_bus_unlock(mac->bus); + consume_skb(resp_skb); + return ret; +} + +int qtnf_cmd_send_chan_switch(struct qtnf_wmac *mac, + struct cfg80211_csa_settings *params) +{ + struct qlink_cmd_chan_switch *cmd; + struct sk_buff *cmd_skb; + u16 res_code = QLINK_CMD_RESULT_OK; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0x0, + QLINK_CMD_CHAN_SWITCH, + sizeof(*cmd)); + + if (unlikely(!cmd_skb)) + return -ENOMEM; + + qtnf_bus_lock(mac->bus); + + cmd = (struct qlink_cmd_chan_switch *)cmd_skb->data; + cmd->channel = cpu_to_le16(params->chandef.chan->hw_value); + cmd->radar_required = params->radar_required; + cmd->block_tx = params->block_tx; + cmd->beacon_count = params->count; + + ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); + + if (unlikely(ret)) + goto out; + + switch (res_code) { + case QLINK_CMD_RESULT_OK: + memcpy(&mac->csa_chandef, ¶ms->chandef, + sizeof(mac->csa_chandef)); + mac->status |= QTNF_MAC_CSA_ACTIVE; + ret = 0; + break; + case QLINK_CMD_RESULT_ENOTFOUND: + ret = -ENOENT; + break; + case QLINK_CMD_RESULT_ENOTSUPP: + ret = -EOPNOTSUPP; + break; + case QLINK_CMD_RESULT_EALREADY: + ret = -EALREADY; + break; + case QLINK_CMD_RESULT_INVALID: + default: + ret = -EFAULT; + break; + } + +out: + qtnf_bus_unlock(mac->bus); + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index 6c51854ef5e7..783b20364296 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -70,5 +70,10 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code); int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up); +int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req); +int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel, + struct qtnf_chan_stats *stats); +int qtnf_cmd_send_chan_switch(struct qtnf_wmac *mac, + struct cfg80211_csa_settings *params); #endif /* QLINK_COMMANDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index f053532c0e87..5e60180482d1 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -288,6 +288,8 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus, mac->iflist[i].mac = mac; mac->iflist[i].vifid = i; qtnf_sta_list_init(&mac->iflist[i].sta_list); + mutex_init(&mac->mac_lock); + init_timer(&mac->scan_timeout); } qtnf_mac_init_primary_intf(mac); @@ -549,6 +551,9 @@ void qtnf_core_detach(struct qtnf_bus *bus) destroy_workqueue(bus->workqueue); } + kfree(bus->hw_info.rd); + bus->hw_info.rd = NULL; + qtnf_trans_free(bus); } EXPORT_SYMBOL_GPL(qtnf_core_detach); diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index a616434281cf..066fcd1095a0 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -42,11 +42,11 @@ #define QTNF_MAX_SSID_LIST_LENGTH 2 #define QTNF_MAX_VSIE_LEN 255 -#define QTNF_MAX_ALPHA_LEN 2 #define QTNF_MAX_INTF 8 #define QTNF_MAX_EVENT_QUEUE_LEN 255 #define QTNF_DEFAULT_BG_SCAN_PERIOD 300 #define QTNF_MAX_BG_SCAN_PERIOD 0xffff +#define QTNF_SCAN_TIMEOUT_SEC 15 #define QTNF_DEF_BSS_PRIORITY 0 #define QTNF_DEF_WDOG_TIMEOUT 5 @@ -68,7 +68,6 @@ struct qtnf_bss_config { u16 auth_type; bool privacy; enum nl80211_mfp mfp; - struct cfg80211_chan_def chandef; struct cfg80211_crypto_settings crypto; u16 bg_scan_period; u32 connect_flags; @@ -90,6 +89,10 @@ enum qtnf_sta_state { QTNF_STA_CONNECTED }; +enum qtnf_mac_status { + QTNF_MAC_CSA_ACTIVE = BIT(0) +}; + struct qtnf_vif { struct wireless_dev wdev; u8 vifid; @@ -125,25 +128,39 @@ struct qtnf_mac_info { size_t n_limits; }; +struct qtnf_chan_stats { + u32 chan_num; + u32 cca_tx; + u32 cca_rx; + u32 cca_busy; + u32 cca_try; + s8 chan_noise; +}; + struct qtnf_wmac { u8 macid; u8 wiphy_registered; u8 macaddr[ETH_ALEN]; + u32 status; struct qtnf_bus *bus; struct qtnf_mac_info macinfo; struct qtnf_vif iflist[QTNF_MAX_INTF]; struct cfg80211_scan_request *scan_req; + struct cfg80211_chan_def chandef; + struct cfg80211_chan_def csa_chandef; + struct mutex mac_lock; /* lock during wmac speicific ops */ + struct timer_list scan_timeout; }; struct qtnf_hw_info { + u16 ql_proto_ver; u8 num_mac; u8 mac_bitmap; - u8 alpha2_code[QTNF_MAX_ALPHA_LEN]; u32 fw_ver; - u16 ql_proto_ver; + u32 hw_capab; + struct ieee80211_regdomain *rd; u8 total_tx_chain; u8 total_rx_chain; - u32 hw_capab; }; struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac); diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 9b61e9a83670..0fc2814eafad 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -211,8 +211,8 @@ qtnf_event_handle_bss_leave(struct qtnf_vif *vif, pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); - cfg80211_disconnected(vif->netdev, leave_info->reason, NULL, 0, 0, - GFP_KERNEL); + cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason), + NULL, 0, 0, GFP_KERNEL); vif->sta_state = QTNF_STA_DISCONNECTED; netif_carrier_off(vif->netdev); @@ -345,11 +345,70 @@ qtnf_event_handle_scan_complete(struct qtnf_wmac *mac, return -EINVAL; } + if (timer_pending(&mac->scan_timeout)) + del_timer_sync(&mac->scan_timeout); qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED); return 0; } +static int +qtnf_event_handle_freq_change(struct qtnf_wmac *mac, + const struct qlink_event_freq_change *data, + u16 len) +{ + struct wiphy *wiphy = priv_to_wiphy(mac); + struct cfg80211_chan_def chandef; + struct ieee80211_channel *chan; + struct qtnf_vif *vif; + int freq; + int i; + + if (len < sizeof(*data)) { + pr_err("payload is too short\n"); + return -EINVAL; + } + + freq = le32_to_cpu(data->freq); + chan = ieee80211_get_channel(wiphy, freq); + if (!chan) { + pr_err("channel at %d MHz not found\n", freq); + return -EINVAL; + } + + pr_debug("MAC%d switch to new channel %u MHz\n", mac->macid, freq); + + if (mac->status & QTNF_MAC_CSA_ACTIVE) { + mac->status &= ~QTNF_MAC_CSA_ACTIVE; + if (chan->hw_value != mac->csa_chandef.chan->hw_value) + pr_warn("unexpected switch to %u during CSA to %u\n", + chan->hw_value, + mac->csa_chandef.chan->hw_value); + } + + /* FIXME: need to figure out proper nl80211_channel_type value */ + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); + /* fall-back to minimal safe chandef description */ + if (!cfg80211_chandef_valid(&chandef)) + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); + + memcpy(&mac->chandef, &chandef, sizeof(mac->chandef)); + + for (i = 0; i < QTNF_MAX_INTF; i++) { + vif = &mac->iflist[i]; + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) + continue; + + if (vif->netdev) { + mutex_lock(&vif->wdev.mtx); + cfg80211_ch_switch_notify(vif->netdev, &chandef); + mutex_unlock(&vif->wdev.mtx); + } + } + + return 0; +} + static int qtnf_event_parse(struct qtnf_wmac *mac, const struct sk_buff *event_skb) { @@ -400,6 +459,10 @@ static int qtnf_event_parse(struct qtnf_wmac *mac, ret = qtnf_event_handle_bss_leave(vif, (const void *)event, event_len); break; + case QLINK_EVENT_FREQ_CHANGE: + ret = qtnf_event_handle_freq_change(mac, (const void *)event, + event_len); + break; default: pr_warn("unknown event type: %x\n", event_id); break; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c index 7fc4f0d6a9ad..502e72b7cdcc 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c @@ -25,6 +25,8 @@ #include <linux/completion.h> #include <linux/crc32.h> #include <linux/spinlock.h> +#include <linux/circ_buf.h> +#include <linux/log2.h> #include "qtn_hw_ids.h" #include "pcie_bus_priv.h" @@ -36,17 +38,13 @@ static bool use_msi = true; module_param(use_msi, bool, 0644); MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt"); -static unsigned int tx_bd_size_param = 256; +static unsigned int tx_bd_size_param = 32; module_param(tx_bd_size_param, uint, 0644); -MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size"); +MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size, power of two"); static unsigned int rx_bd_size_param = 256; module_param(rx_bd_size_param, uint, 0644); -MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size"); - -static unsigned int rx_bd_reserved_param = 16; -module_param(rx_bd_reserved_param, uint, 0644); -MODULE_PARM_DESC(rx_bd_reserved_param, "Reserved RX descriptors"); +MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size, power of two"); static u8 flashboot = 1; module_param(flashboot, byte, 0644); @@ -186,8 +184,10 @@ static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) return IOMEM_ERR_PTR(ret); busaddr = pci_resource_start(priv->pdev, index); - vaddr = pcim_iomap_table(priv->pdev)[index]; len = pci_resource_len(priv->pdev, index); + vaddr = pcim_iomap_table(priv->pdev)[index]; + if (!vaddr) + return IOMEM_ERR_PTR(-ENOMEM); pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", index, vaddr, &busaddr, (int)len); @@ -250,19 +250,19 @@ static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) int ret = -ENOMEM; priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); - if (IS_ERR_OR_NULL(priv->sysctl_bar)) { + if (IS_ERR(priv->sysctl_bar)) { pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); return ret; } priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); - if (IS_ERR_OR_NULL(priv->dmareg_bar)) { + if (IS_ERR(priv->dmareg_bar)) { pr_err("failed to map BAR%u\n", QTN_DMA_BAR); return ret; } priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); - if (IS_ERR_OR_NULL(priv->epmem_bar)) { + if (IS_ERR(priv->epmem_bar)) { pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); return ret; } @@ -274,32 +274,6 @@ static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) return 0; } -static int -qtnf_pcie_init_dma_mask(struct qtnf_pcie_bus_priv *priv, u64 dma_mask) -{ - int ret; - - ret = dma_supported(&priv->pdev->dev, dma_mask); - if (!ret) { - pr_err("DMA mask %llu not supported\n", dma_mask); - return ret; - } - - ret = pci_set_dma_mask(priv->pdev, dma_mask); - if (ret) { - pr_err("failed to set DMA mask %llu\n", dma_mask); - return ret; - } - - ret = pci_set_consistent_dma_mask(priv->pdev, dma_mask); - if (ret) { - pr_err("failed to set consistent DMA mask %llu\n", dma_mask); - return ret; - } - - return ret; -} - static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) { struct pci_dev *pdev = priv->pdev; @@ -418,9 +392,8 @@ static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); - priv->tx_bd_reclaim_start = 0; - priv->tx_bd_index = 0; - priv->tx_queue_len = 0; + priv->tx_bd_r_index = 0; + priv->tx_bd_w_index = 0; /* rx bd */ @@ -430,43 +403,34 @@ static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) priv->rx_bd_vbase = vaddr; priv->rx_bd_pbase = paddr; - writel(QTN_HOST_LO32(paddr), - PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(paddr), PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base)); +#endif + writel(QTN_HOST_LO32(paddr), + PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16, PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base)); - priv->hw_txproc_wr_ptr = priv->rx_bd_num - rx_bd_reserved_param; - - writel(priv->hw_txproc_wr_ptr, - PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); - pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); - priv->rx_bd_index = 0; - return 0; } -static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 rx_bd_index) +static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 index) { struct qtnf_rx_bd *rxbd; struct sk_buff *skb; dma_addr_t paddr; - skb = __dev_alloc_skb(SKB_BUF_SIZE + NET_IP_ALIGN, - GFP_ATOMIC); + skb = __netdev_alloc_skb_ip_align(NULL, SKB_BUF_SIZE, GFP_ATOMIC); if (!skb) { - priv->rx_skb[rx_bd_index] = NULL; + priv->rx_skb[index] = NULL; return -ENOMEM; } - priv->rx_skb[rx_bd_index] = skb; - - skb_reserve(skb, NET_IP_ALIGN); - - rxbd = &priv->rx_bd_vbase[rx_bd_index]; + priv->rx_skb[index] = skb; + rxbd = &priv->rx_bd_vbase[index]; paddr = pci_map_single(priv->pdev, skb->data, SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); @@ -475,17 +439,24 @@ static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 rx_bd_index) return -ENOMEM; } - writel(QTN_HOST_LO32(paddr), - PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base)); - writel(QTN_HOST_HI32(paddr), - PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base)); - /* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */ rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr)); rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr)); - rxbd->info = 0x0; + priv->rx_bd_w_index = index; + + /* sync up all descriptor updates */ + wmb(); + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + writel(QTN_HOST_HI32(paddr), + PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base)); +#endif + writel(QTN_HOST_LO32(paddr), + PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base)); + + writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); return 0; } @@ -516,7 +487,7 @@ static void free_xfer_buffers(void *data) /* free rx buffers */ for (i = 0; i < priv->rx_bd_num; i++) { - if (priv->rx_skb[i]) { + if (priv->rx_skb && priv->rx_skb[i]) { rxbd = &priv->rx_bd_vbase[i]; paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); @@ -529,19 +500,72 @@ static void free_xfer_buffers(void *data) /* free tx buffers */ for (i = 0; i < priv->tx_bd_num; i++) { - if (priv->tx_skb[i]) { + if (priv->tx_skb && priv->tx_skb[i]) { dev_kfree_skb_any(priv->tx_skb[i]); priv->tx_skb[i] = NULL; } } } +static int qtnf_hhbm_init(struct qtnf_pcie_bus_priv *priv) +{ + u32 val; + + val = readl(PCIE_HHBM_CONFIG(priv->pcie_reg_base)); + val |= HHBM_CONFIG_SOFT_RESET; + writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base)); + usleep_range(50, 100); + val &= ~HHBM_CONFIG_SOFT_RESET; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + val |= HHBM_64BIT; +#endif + writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base)); + writel(priv->rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(priv->pcie_reg_base)); + + return 0; +} + static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) { int ret; + u32 val; priv->tx_bd_num = tx_bd_size_param; priv->rx_bd_num = rx_bd_size_param; + priv->rx_bd_w_index = 0; + priv->rx_bd_r_index = 0; + + if (!priv->tx_bd_num || !is_power_of_2(priv->tx_bd_num)) { + pr_err("tx_bd_size_param %u is not power of two\n", + priv->tx_bd_num); + return -EINVAL; + } + + val = priv->tx_bd_num * sizeof(struct qtnf_tx_bd); + if (val > PCIE_HHBM_MAX_SIZE) { + pr_err("tx_bd_size_param %u is too large\n", + priv->tx_bd_num); + return -EINVAL; + } + + if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) { + pr_err("rx_bd_size_param %u is not power of two\n", + priv->rx_bd_num); + return -EINVAL; + } + + val = priv->rx_bd_num * sizeof(dma_addr_t); + if (val > PCIE_HHBM_MAX_SIZE) { + pr_err("rx_bd_size_param %u is too large\n", + priv->rx_bd_num); + return -EINVAL; + } + + ret = qtnf_hhbm_init(priv); + if (ret) { + pr_err("failed to init h/w queues\n"); + return ret; + } ret = alloc_skb_array(priv); if (ret) { @@ -564,67 +588,72 @@ static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) return ret; } -static int qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) +static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) { struct qtnf_tx_bd *txbd; struct sk_buff *skb; + unsigned long flags; dma_addr_t paddr; - int last_sent; - int count; + u32 tx_done_index; + int count = 0; int i; - last_sent = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) - % priv->tx_bd_num; - i = priv->tx_bd_reclaim_start; - count = 0; + spin_lock_irqsave(&priv->tx_reclaim_lock, flags); - while (i != last_sent) { - skb = priv->tx_skb[i]; - if (!skb) - break; + tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + & (priv->tx_bd_num - 1); - txbd = &priv->tx_bd_vbase[i]; - paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), - le32_to_cpu(txbd->addr)); - pci_unmap_single(priv->pdev, paddr, skb->len, PCI_DMA_TODEVICE); + i = priv->tx_bd_r_index; - if (skb->dev) { - skb->dev->stats.tx_packets++; - skb->dev->stats.tx_bytes += skb->len; + while (CIRC_CNT(tx_done_index, i, priv->tx_bd_num)) { + skb = priv->tx_skb[i]; + if (likely(skb)) { + txbd = &priv->tx_bd_vbase[i]; + paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), + le32_to_cpu(txbd->addr)); + pci_unmap_single(priv->pdev, paddr, skb->len, + PCI_DMA_TODEVICE); + + if (skb->dev) { + skb->dev->stats.tx_packets++; + skb->dev->stats.tx_bytes += skb->len; + + if (netif_queue_stopped(skb->dev)) + netif_wake_queue(skb->dev); + } - if (netif_queue_stopped(skb->dev)) - netif_wake_queue(skb->dev); + dev_kfree_skb_any(skb); } - dev_kfree_skb_any(skb); priv->tx_skb[i] = NULL; - priv->tx_queue_len--; count++; if (++i >= priv->tx_bd_num) i = 0; } - priv->tx_bd_reclaim_start = i; priv->tx_reclaim_done += count; priv->tx_reclaim_req++; + priv->tx_bd_r_index = i; - return count; + spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags); } -static bool qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) +static int qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) { - if (priv->tx_queue_len >= priv->tx_bd_num - 1) { + if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, + priv->tx_bd_num)) { pr_err_ratelimited("reclaim full Tx queue\n"); qtnf_pcie_data_tx_reclaim(priv); - if (priv->tx_queue_len >= priv->tx_bd_num - 1) { + if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, + priv->tx_bd_num)) { priv->tx_full_count++; - return false; + return 0; } } - return true; + return 1; } static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) @@ -632,24 +661,18 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); dma_addr_t txbd_paddr, skb_paddr; struct qtnf_tx_bd *txbd; - unsigned long flags; int len, i; u32 info; int ret = 0; - spin_lock_irqsave(&priv->tx_lock, flags); - - priv->tx_done_count++; - if (!qtnf_tx_queue_ready(priv)) { if (skb->dev) netif_stop_queue(skb->dev); - spin_unlock_irqrestore(&priv->tx_lock, flags); return NETDEV_TX_BUSY; } - i = priv->tx_bd_index; + i = priv->tx_bd_w_index; priv->tx_skb[i] = skb; len = skb->len; @@ -673,16 +696,18 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) /* write new TX descriptor to PCIE_RX_FIFO on EP */ txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_tx_bd); - writel(QTN_HOST_LO32(txbd_paddr), - PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base)); + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(txbd_paddr), PCIE_HDP_HOST_WR_DESC0_H(priv->pcie_reg_base)); +#endif + writel(QTN_HOST_LO32(txbd_paddr), + PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base)); if (++i >= priv->tx_bd_num) i = 0; - priv->tx_bd_index = i; - priv->tx_queue_len++; + priv->tx_bd_w_index = i; tx_done: if (ret && skb) { @@ -692,7 +717,8 @@ tx_done: dev_kfree_skb_any(skb); } - spin_unlock_irqrestore(&priv->tx_lock, flags); + qtnf_pcie_data_tx_reclaim(priv); + priv->tx_done_count++; return NETDEV_TX_OK; } @@ -719,14 +745,21 @@ static irqreturn_t qtnf_interrupt(int irq, void *data) if (!(status & priv->pcie_irq_mask)) goto irq_done; - if (status & PCIE_HDP_INT_RX_BITS) { + if (status & PCIE_HDP_INT_RX_BITS) priv->pcie_irq_rx_count++; + + if (status & PCIE_HDP_INT_TX_BITS) + priv->pcie_irq_tx_count++; + + if (status & PCIE_HDP_INT_HHBM_UF) + priv->pcie_irq_uf_count++; + + if (status & PCIE_HDP_INT_RX_BITS) { qtnf_dis_rxdone_irq(priv); napi_schedule(&bus->mux_napi); } if (status & PCIE_HDP_INT_TX_BITS) { - priv->pcie_irq_tx_count++; qtnf_dis_txdone_irq(priv); tasklet_hi_schedule(&priv->reclaim_tq); } @@ -741,16 +774,19 @@ irq_done: return IRQ_HANDLED; } -static inline void hw_txproc_wr_ptr_inc(struct qtnf_pcie_bus_priv *priv) +static int qtnf_rx_data_ready(struct qtnf_pcie_bus_priv *priv) { - u32 index; + u16 index = priv->rx_bd_r_index; + struct qtnf_rx_bd *rxbd; + u32 descw; - index = priv->hw_txproc_wr_ptr; + rxbd = &priv->rx_bd_vbase[index]; + descw = le32_to_cpu(rxbd->info); - if (++index >= priv->rx_bd_num) - index = 0; + if (descw & QTN_TXDONE_MASK) + return 1; - priv->hw_txproc_wr_ptr = index; + return 0; } static int qtnf_rx_poll(struct napi_struct *napi, int budget) @@ -762,64 +798,96 @@ static int qtnf_rx_poll(struct napi_struct *napi, int budget) int processed = 0; struct qtnf_rx_bd *rxbd; dma_addr_t skb_paddr; + int consume; u32 descw; - u16 index; + u32 psize; + u16 r_idx; + u16 w_idx; int ret; - index = priv->rx_bd_index; - rxbd = &priv->rx_bd_vbase[index]; + while (processed < budget) { - descw = le32_to_cpu(rxbd->info); - while ((descw & QTN_TXDONE_MASK) && (processed < budget)) { - skb = priv->rx_skb[index]; + if (!qtnf_rx_data_ready(priv)) + goto rx_out; - if (likely(skb)) { - skb_put(skb, QTN_GET_LEN(descw)); + r_idx = priv->rx_bd_r_index; + rxbd = &priv->rx_bd_vbase[r_idx]; + descw = le32_to_cpu(rxbd->info); + + skb = priv->rx_skb[r_idx]; + psize = QTN_GET_LEN(descw); + consume = 1; + + if (!(descw & QTN_TXDONE_MASK)) { + pr_warn("skip invalid rxbd[%d]\n", r_idx); + consume = 0; + } + + if (!skb) { + pr_warn("skip missing rx_skb[%d]\n", r_idx); + consume = 0; + } + if (skb && (skb_tailroom(skb) < psize)) { + pr_err("skip packet with invalid length: %u > %u\n", + psize, skb_tailroom(skb)); + consume = 0; + } + + if (skb) { skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); + } + if (consume) { + skb_put(skb, psize); ndev = qtnf_classify_skb(bus, skb); if (likely(ndev)) { ndev->stats.rx_packets++; ndev->stats.rx_bytes += skb->len; skb->protocol = eth_type_trans(skb, ndev); - netif_receive_skb(skb); + napi_gro_receive(napi, skb); } else { pr_debug("drop untagged skb\n"); bus->mux_dev.stats.rx_dropped++; dev_kfree_skb_any(skb); } - - processed++; } else { - pr_err("missing rx_skb[%d]\n", index); + if (skb) { + bus->mux_dev.stats.rx_dropped++; + dev_kfree_skb_any(skb); + } } - /* attached rx buffer is passed upstream: map a new one */ - ret = skb2rbd_attach(priv, index); - if (likely(!ret)) { - if (++index >= priv->rx_bd_num) - index = 0; + priv->rx_skb[r_idx] = NULL; + if (++r_idx >= priv->rx_bd_num) + r_idx = 0; - priv->rx_bd_index = index; - hw_txproc_wr_ptr_inc(priv); + priv->rx_bd_r_index = r_idx; - rxbd = &priv->rx_bd_vbase[index]; - descw = le32_to_cpu(rxbd->info); - } else { - pr_err("failed to allocate new rx_skb[%d]\n", index); - break; + /* repalce processed buffer by a new one */ + w_idx = priv->rx_bd_w_index; + while (CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, + priv->rx_bd_num) > 0) { + if (++w_idx >= priv->rx_bd_num) + w_idx = 0; + + ret = skb2rbd_attach(priv, w_idx); + if (ret) { + pr_err("failed to allocate new rx_skb[%d]\n", + w_idx); + break; + } } - writel(priv->hw_txproc_wr_ptr, - PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); + processed++; } +rx_out: if (processed < budget) { napi_complete(napi); qtnf_en_rxdone_irq(priv); @@ -1058,11 +1126,8 @@ static int qtnf_bringup_fw(struct qtnf_bus *bus) static void qtnf_reclaim_tasklet_fn(unsigned long data) { struct qtnf_pcie_bus_priv *priv = (void *)data; - unsigned long flags; - spin_lock_irqsave(&priv->tx_lock, flags); qtnf_pcie_data_tx_reclaim(priv); - spin_unlock_irqrestore(&priv->tx_lock, flags); qtnf_en_txdone_irq(priv); } @@ -1090,10 +1155,22 @@ static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base)); + u32 status; seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); + status = reg & PCIE_HDP_INT_TX_BITS; + seq_printf(s, "pcie_irq_tx_status(%s)\n", + (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); + status = reg & PCIE_HDP_INT_RX_BITS; + seq_printf(s, "pcie_irq_rx_status(%s)\n", + (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); + seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count); + status = reg & PCIE_HDP_INT_HHBM_UF; + seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", + (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); return 0; } @@ -1107,10 +1184,24 @@ static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); - seq_printf(s, "tx_bd_reclaim_start(%u)\n", priv->tx_bd_reclaim_start); - seq_printf(s, "tx_bd_index(%u)\n", priv->tx_bd_index); - seq_printf(s, "rx_bd_index(%u)\n", priv->rx_bd_index); - seq_printf(s, "tx_queue_len(%u)\n", priv->tx_queue_len); + + seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); + seq_printf(s, "tx_bd_p_index(%u)\n", + readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) + & (priv->tx_bd_num - 1)); + seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); + seq_printf(s, "tx queue len(%u)\n", + CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index, + priv->tx_bd_num)); + + seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); + seq_printf(s, "rx_bd_p_index(%u)\n", + readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base)) + & (priv->rx_bd_num - 1)); + seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); + seq_printf(s, "rx alloc queue len(%u)\n", + CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, + priv->rx_bd_num)); return 0; } @@ -1157,7 +1248,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) init_completion(&bus->request_firmware_complete); mutex_init(&bus->bus_lock); spin_lock_init(&pcie_priv->irq_lock); - spin_lock_init(&pcie_priv->tx_lock); + spin_lock_init(&pcie_priv->tx_reclaim_lock); /* init stats */ pcie_priv->tx_full_count = 0; @@ -1165,6 +1256,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pcie_priv->pcie_irq_count = 0; pcie_priv->pcie_irq_rx_count = 0; pcie_priv->pcie_irq_tx_count = 0; + pcie_priv->pcie_irq_uf_count = 0; pcie_priv->tx_reclaim_done = 0; pcie_priv->tx_reclaim_req = 0; @@ -1191,6 +1283,16 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pr_debug("successful init of PCI device %x\n", pdev->device); } +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); +#else + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +#endif + if (ret) { + pr_err("PCIE DMA coherent mask init failed\n"); + goto err_base; + } + pcim_pin_device(pdev); pci_set_master(pdev); @@ -1212,12 +1314,6 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_base; } - ret = qtnf_pcie_init_dma_mask(pcie_priv, DMA_BIT_MASK(32)); - if (ret) { - pr_err("PCIE DMA mask init failed\n"); - goto err_base; - } - ret = devm_add_action(&pdev->dev, free_xfer_buffers, (void *)pcie_priv); if (ret) { pr_err("custom release callback init failed\n"); @@ -1336,7 +1432,7 @@ static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend, qtnf_pcie_resume); #endif -static struct pci_device_id qtnf_pcie_devid_table[] = { +static const struct pci_device_id qtnf_pcie_devid_table[] = { { PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h index 2a897db2bd79..e76a23716ee0 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h @@ -32,8 +32,8 @@ struct qtnf_pcie_bus_priv { /* lock for irq configuration changes */ spinlock_t irq_lock; - /* lock for tx operations */ - spinlock_t tx_lock; + /* lock for tx reclaim operations */ + spinlock_t tx_reclaim_lock; u8 msi_enabled; int mps; @@ -66,13 +66,11 @@ struct qtnf_pcie_bus_priv { void *bd_table_vaddr; u32 bd_table_len; - u32 hw_txproc_wr_ptr; + u32 rx_bd_w_index; + u32 rx_bd_r_index; - u16 tx_bd_reclaim_start; - u16 tx_bd_index; - u32 tx_queue_len; - - u16 rx_bd_index; + u32 tx_bd_w_index; + u32 tx_bd_r_index; u32 pcie_irq_mask; @@ -80,6 +78,7 @@ struct qtnf_pcie_bus_priv { u32 pcie_irq_count; u32 pcie_irq_rx_count; u32 pcie_irq_tx_count; + u32 pcie_irq_uf_count; u32 tx_full_count; u32 tx_done_count; u32 tx_reclaim_done; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h index e00d508fbcf0..c5a4e46d26ef 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h @@ -50,22 +50,21 @@ #define PCIE_HDP_INT_RX_BITS (0 \ | PCIE_HDP_INT_EP_TXDMA \ | PCIE_HDP_INT_EP_TXEMPTY \ + | PCIE_HDP_INT_HHBM_UF \ ) #define PCIE_HDP_INT_TX_BITS (0 \ | PCIE_HDP_INT_EP_RXDMA \ ) -#if BITS_PER_LONG == 64 +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT #define QTN_HOST_HI32(a) ((u32)(((u64)a) >> 32)) #define QTN_HOST_LO32(a) ((u32)(((u64)a) & 0xffffffffUL)) #define QTN_HOST_ADDR(h, l) ((((u64)h) << 32) | ((u64)l)) -#elif BITS_PER_LONG == 32 +#else #define QTN_HOST_HI32(a) 0 #define QTN_HOST_LO32(a) ((u32)(((u32)a) & 0xffffffffUL)) #define QTN_HOST_ADDR(h, l) ((u32)l) -#else -#error Unexpected BITS_PER_LONG value #endif #define QTN_SYSCTL_BAR 0 @@ -75,7 +74,7 @@ #define QTN_PCIE_BDA_VERSION 0x1002 #define PCIE_BDA_NAMELEN 32 -#define PCIE_HHBM_MAX_SIZE 512 +#define PCIE_HHBM_MAX_SIZE 2048 #define SKB_BUF_SIZE 2048 @@ -112,7 +111,7 @@ struct qtnf_pcie_bda { __le32 bda_flashsz; u8 bda_boardname[PCIE_BDA_NAMELEN]; __le32 bda_rc_msi_enabled; - __le32 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; + u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; __le32 bda_dsbw_start_index; __le32 bda_dsbw_end_index; __le32 bda_dsbw_total_bytes; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h index 78715b8a8ef9..5b48b425fa7f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h @@ -109,6 +109,7 @@ #define HHBM_WR_REQ (BIT(0)) #define HHBM_RD_REQ (BIT(1)) #define HHBM_DONE (BIT(31)) +#define HHBM_64BIT (BIT(10)) /* offsets for dual PCIE */ #define PCIE_PORT_LINK_CTL(base) ((base) + 0x0710) @@ -333,6 +334,7 @@ #define PCIE_HDP_INT_RX_LEN_ERR (BIT(2)) #define PCIE_HDP_INT_RX_HDR_LEN_ERR (BIT(3)) #define PCIE_HDP_INT_EP_TXDMA (BIT(12)) +#define PCIE_HDP_INT_HHBM_UF (BIT(13)) #define PCIE_HDP_INT_EP_TXEMPTY (BIT(15)) #define PCIE_HDP_INT_IPC (BIT(29)) diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 6eafc15e0065..a8242f678496 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -19,7 +19,7 @@ #include <linux/ieee80211.h> -#define QLINK_PROTO_VER 3 +#define QLINK_PROTO_VER 5 #define QLINK_MACID_RSVD 0xFF #define QLINK_VIFID_RSVD 0xFF @@ -77,6 +77,7 @@ enum qlink_iface_type { QLINK_IFTYPE_ADHOC = 3, QLINK_IFTYPE_MONITOR = 4, QLINK_IFTYPE_WDS = 5, + QLINK_IFTYPE_AP_VLAN = 6, }; /** @@ -85,12 +86,12 @@ enum qlink_iface_type { * Data describing a single virtual interface. * * @if_type: Mode of interface operation, one of &enum qlink_iface_type - * @flags: interface flagsmap. + * @vlanid: VLAN ID for AP_VLAN interface type * @mac_addr: MAC address of virtual interface. */ struct qlink_intf_info { __le16 if_type; - __le16 flags; + __le16 vlanid; u8 mac_addr[ETH_ALEN]; u8 rsvd[2]; } __packed; @@ -133,6 +134,9 @@ enum qlink_channel_width { * number of operational channels and information on each of the channel. * This command is generic to a specified MAC, interface index must be set * to QLINK_VIFID_RSVD in command header. + * @QLINK_CMD_REG_NOTIFY: notify device about regulatory domain change. This + * command is supported only if device reports QLINK_HW_SUPPORTS_REG_UPDATE + * capability. */ enum qlink_cmd_type { QLINK_CMD_FW_INIT = 0x0001, @@ -148,8 +152,9 @@ enum qlink_cmd_type { QLINK_CMD_DEL_INTF = 0x0016, QLINK_CMD_CHANGE_INTF = 0x0017, QLINK_CMD_UPDOWN_INTF = 0x0018, - QLINK_CMD_REG_REGION = 0x0019, + QLINK_CMD_REG_NOTIFY = 0x0019, QLINK_CMD_CHANS_INFO_GET = 0x001A, + QLINK_CMD_CHAN_SWITCH = 0x001B, QLINK_CMD_CONFIG_AP = 0x0020, QLINK_CMD_START_AP = 0x0021, QLINK_CMD_STOP_AP = 0x0022, @@ -161,6 +166,7 @@ enum qlink_cmd_type { QLINK_CMD_CHANGE_STA = 0x0051, QLINK_CMD_DEL_STA = 0x0052, QLINK_CMD_SCAN = 0x0053, + QLINK_CMD_CHAN_STATS = 0x0054, QLINK_CMD_CONNECT = 0x0060, QLINK_CMD_DISCONNECT = 0x0061, }; @@ -287,6 +293,7 @@ struct qlink_cmd_get_sta_info { * @pairwise: whether to use pairwise key. * @addr: MAC address of a STA key is being installed to. * @cipher: cipher suite. + * @vlanid: VLAN ID for AP_VLAN interface type * @key_data: key data itself. */ struct qlink_cmd_add_key { @@ -295,6 +302,7 @@ struct qlink_cmd_add_key { u8 pairwise; u8 addr[ETH_ALEN]; __le32 cipher; + __le16 vlanid; u8 key_data[0]; } __packed; @@ -341,12 +349,16 @@ struct qlink_cmd_set_def_mgmt_key { * * @sta_flags_mask: STA flags mask, bitmap of &enum qlink_sta_flags * @sta_flags_set: STA flags values, bitmap of &enum qlink_sta_flags + * @if_type: Mode of interface operation, one of &enum qlink_iface_type + * @vlanid: VLAN ID to assign to specific STA * @sta_addr: address of the STA for which parameters are set. */ struct qlink_cmd_change_sta { struct qlink_cmd chdr; __le32 sta_flags_mask; __le32 sta_flags_set; + __le16 if_type; + __le16 vlanid; u8 sta_addr[ETH_ALEN]; } __packed; @@ -380,7 +392,7 @@ enum qlink_sta_connect_flags { struct qlink_cmd_connect { struct qlink_cmd chdr; __le32 flags; - __le16 freq; + __le16 channel; __le16 bg_scan_period; u8 bssid[ETH_ALEN]; u8 payload[0]; @@ -430,6 +442,70 @@ struct qlink_cmd_chans_info_get { u8 band; } __packed; +/** + * struct qlink_cmd_get_chan_stats - data for QLINK_CMD_CHAN_STATS command + * + * @channel: channel number according to 802.11 17.3.8.3.2 and Annex J + */ +struct qlink_cmd_get_chan_stats { + struct qlink_cmd chdr; + __le16 channel; +} __packed; + +/** + * enum qlink_reg_initiator - Indicates the initiator of a reg domain request + * + * See &enum nl80211_reg_initiator for more info. + */ +enum qlink_reg_initiator { + QLINK_REGDOM_SET_BY_CORE, + QLINK_REGDOM_SET_BY_USER, + QLINK_REGDOM_SET_BY_DRIVER, + QLINK_REGDOM_SET_BY_COUNTRY_IE, +}; + +/** + * enum qlink_user_reg_hint_type - type of user regulatory hint + * + * See &enum nl80211_user_reg_hint_type for more info. + */ +enum qlink_user_reg_hint_type { + QLINK_USER_REG_HINT_USER = 0, + QLINK_USER_REG_HINT_CELL_BASE = 1, + QLINK_USER_REG_HINT_INDOOR = 2, +}; + +/** + * struct qlink_cmd_reg_notify - data for QLINK_CMD_REG_NOTIFY command + * + * @alpha2: the ISO / IEC 3166 alpha2 country code. + * @initiator: which entity sent the request, one of &enum qlink_reg_initiator. + * @user_reg_hint_type: type of hint for QLINK_REGDOM_SET_BY_USER request, one + * of &enum qlink_user_reg_hint_type. + */ +struct qlink_cmd_reg_notify { + struct qlink_cmd chdr; + u8 alpha2[2]; + u8 initiator; + u8 user_reg_hint_type; +} __packed; + +/** + * struct qlink_cmd_chan_switch - data for QLINK_CMD_CHAN_SWITCH command + * + * @channel: channel number according to 802.11 17.3.8.3.2 and Annex J + * @radar_required: whether radar detection is required on the new channel + * @block_tx: whether transmissions should be blocked while changing + * @beacon_count: number of beacons until switch + */ +struct qlink_cmd_chan_switch { + struct qlink_cmd chdr; + __le16 channel; + u8 radar_required; + u8 block_tx; + u8 beacon_count; +} __packed; + /* QLINK Command Responses messages related definitions */ @@ -438,6 +514,7 @@ enum qlink_cmd_result { QLINK_CMD_RESULT_INVALID, QLINK_CMD_RESULT_ENOTSUPP, QLINK_CMD_RESULT_ENOTFOUND, + QLINK_CMD_RESULT_EALREADY, }; /** @@ -497,6 +574,18 @@ struct qlink_resp_get_mac_info { } __packed; /** + * enum qlink_dfs_regions - regulatory DFS regions + * + * Corresponds to &enum nl80211_dfs_regions. + */ +enum qlink_dfs_regions { + QLINK_DFS_UNSET = 0, + QLINK_DFS_FCC = 1, + QLINK_DFS_ETSI = 2, + QLINK_DFS_JP = 3, +}; + +/** * struct qlink_resp_get_hw_info - response for QLINK_CMD_GET_HW_INFO command * * Description of wireless hardware capabilities and features. @@ -504,22 +593,29 @@ struct qlink_resp_get_mac_info { * @fw_ver: wireless hardware firmware version. * @hw_capab: Bitmap of capabilities supported by firmware. * @ql_proto_ver: Version of QLINK protocol used by firmware. - * @country_code: country code ID firmware is configured to. * @num_mac: Number of separate physical radio devices provided by hardware. * @mac_bitmap: Bitmap of MAC IDs that are active and can be used in firmware. * @total_tx_chains: total number of transmit chains used by device. * @total_rx_chains: total number of receive chains. + * @alpha2: country code ID firmware is configured to. + * @n_reg_rules: number of regulatory rules TLVs in variable portion of the + * message. + * @dfs_region: regulatory DFS region, one of @enum qlink_dfs_region. + * @info: variable-length HW info, can contain QTN_TLV_ID_REG_RULE. */ struct qlink_resp_get_hw_info { struct qlink_resp rhdr; __le32 fw_ver; __le32 hw_capab; __le16 ql_proto_ver; - u8 alpha2_code[2]; u8 num_mac; u8 mac_bitmap; u8 total_tx_chain; u8 total_rx_chain; + u8 alpha2[2]; + u8 n_reg_rules; + u8 dfs_region; + u8 info[0]; } __packed; /** @@ -574,6 +670,16 @@ struct qlink_resp_phy_params { u8 info[0]; } __packed; +/** + * struct qlink_resp_get_chan_stats - response for QLINK_CMD_CHAN_STATS cmd + * + * @info: variable-length channel info. + */ +struct qlink_resp_get_chan_stats { + struct qlink_cmd rhdr; + u8 info[0]; +} __packed; + /* QLINK Events messages related definitions */ @@ -585,6 +691,7 @@ enum qlink_event_type { QLINK_EVENT_SCAN_COMPLETE = 0x0025, QLINK_EVENT_BSS_JOIN = 0x0026, QLINK_EVENT_BSS_LEAVE = 0x0027, + QLINK_EVENT_FREQ_CHANGE = 0x0028, }; /** @@ -651,7 +758,17 @@ struct qlink_event_bss_join { */ struct qlink_event_bss_leave { struct qlink_event ehdr; - u16 reason; + __le16 reason; +} __packed; + +/** + * struct qlink_event_freq_change - data for QLINK_EVENT_FREQ_CHANGE event + * + * @freq: new operating frequency in MHz + */ +struct qlink_event_freq_change { + struct qlink_event ehdr; + __le32 freq; } __packed; enum qlink_rxmgmt_flags { @@ -741,10 +858,12 @@ enum qlink_tlv_id { QTN_TLV_ID_LRETRY_LIMIT = 0x0204, QTN_TLV_ID_BCN_PERIOD = 0x0205, QTN_TLV_ID_DTIM = 0x0206, + QTN_TLV_ID_REG_RULE = 0x0207, QTN_TLV_ID_CHANNEL = 0x020F, QTN_TLV_ID_COVERAGE_CLASS = 0x0213, QTN_TLV_ID_IFACE_LIMIT = 0x0214, QTN_TLV_ID_NUM_IFACE_COMB = 0x0215, + QTN_TLV_ID_CHANNEL_STATS = 0x0216, QTN_TLV_ID_STA_BASIC_COUNTERS = 0x0300, QTN_TLV_ID_STA_GENERIC_INFO = 0x0301, QTN_TLV_ID_KEY = 0x0302, @@ -761,7 +880,7 @@ struct qlink_tlv_hdr { struct qlink_iface_limit { __le16 max_num; - __le16 type_mask; + __le16 type; } __packed; struct qlink_iface_comb_num { @@ -844,12 +963,54 @@ struct qlink_tlv_cclass { u8 cclass; } __packed; -enum qlink_dfs_state { - QLINK_DFS_USABLE, - QLINK_DFS_UNAVAILABLE, - QLINK_DFS_AVAILABLE, +/** + * enum qlink_reg_rule_flags - regulatory rule flags + * + * See description of &enum nl80211_reg_rule_flags + */ +enum qlink_reg_rule_flags { + QLINK_RRF_NO_OFDM = BIT(0), + QLINK_RRF_NO_CCK = BIT(1), + QLINK_RRF_NO_INDOOR = BIT(2), + QLINK_RRF_NO_OUTDOOR = BIT(3), + QLINK_RRF_DFS = BIT(4), + QLINK_RRF_PTP_ONLY = BIT(5), + QLINK_RRF_PTMP_ONLY = BIT(6), + QLINK_RRF_NO_IR = BIT(7), + QLINK_RRF_AUTO_BW = BIT(8), + QLINK_RRF_IR_CONCURRENT = BIT(9), + QLINK_RRF_NO_HT40MINUS = BIT(10), + QLINK_RRF_NO_HT40PLUS = BIT(11), + QLINK_RRF_NO_80MHZ = BIT(12), + QLINK_RRF_NO_160MHZ = BIT(13), }; +/** + * struct qlink_tlv_reg_rule - data for QTN_TLV_ID_REG_RULE TLV + * + * Regulatory rule description. + * + * @start_freq_khz: start frequency of the range the rule is attributed to. + * @end_freq_khz: end frequency of the range the rule is attributed to. + * @max_bandwidth_khz: max bandwidth that channels in specified range can be + * configured to. + * @max_antenna_gain: max antenna gain that can be used in the specified + * frequency range, dBi. + * @max_eirp: maximum EIRP. + * @flags: regulatory rule flags in &enum qlink_reg_rule_flags. + * @dfs_cac_ms: DFS CAC period. + */ +struct qlink_tlv_reg_rule { + struct qlink_tlv_hdr hdr; + __le32 start_freq_khz; + __le32 end_freq_khz; + __le32 max_bandwidth_khz; + __le32 max_antenna_gain; + __le32 max_eirp; + __le32 flags; + __le32 dfs_cac_ms; +} __packed; + enum qlink_channel_flags { QLINK_CHAN_DISABLED = BIT(0), QLINK_CHAN_NO_IR = BIT(1), @@ -865,6 +1026,12 @@ enum qlink_channel_flags { QLINK_CHAN_NO_10MHZ = BIT(12), }; +enum qlink_dfs_state { + QLINK_DFS_USABLE, + QLINK_DFS_UNAVAILABLE, + QLINK_DFS_AVAILABLE, +}; + struct qlink_tlv_channel { struct qlink_tlv_hdr hdr; __le16 hw_value; @@ -898,4 +1065,13 @@ struct qlink_auth_encr { u8 control_port_no_encrypt; } __packed; +struct qlink_chan_stats { + __le32 chan_num; + __le32 cca_tx; + __le32 cca_rx; + __le32 cca_busy; + __le32 cca_try; + s8 chan_noise; +} __packed; + #endif /* _QTN_QLINK_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c index 49ae652ad9a3..cf024c995fd6 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.c @@ -17,24 +17,30 @@ #include "qlink_util.h" -u16 qlink_iface_type_mask_to_nl(u16 qlink_mask) +u16 qlink_iface_type_to_nl_mask(u16 qlink_type) { u16 result = 0; - if (qlink_mask & QLINK_IFTYPE_AP) + switch (qlink_type) { + case QLINK_IFTYPE_AP: result |= BIT(NL80211_IFTYPE_AP); - - if (qlink_mask & QLINK_IFTYPE_STATION) + break; + case QLINK_IFTYPE_STATION: result |= BIT(NL80211_IFTYPE_STATION); - - if (qlink_mask & QLINK_IFTYPE_ADHOC) + break; + case QLINK_IFTYPE_ADHOC: result |= BIT(NL80211_IFTYPE_ADHOC); - - if (qlink_mask & QLINK_IFTYPE_MONITOR) + break; + case QLINK_IFTYPE_MONITOR: result |= BIT(NL80211_IFTYPE_MONITOR); - - if (qlink_mask & QLINK_IFTYPE_WDS) + break; + case QLINK_IFTYPE_WDS: result |= BIT(NL80211_IFTYPE_WDS); + break; + case QLINK_IFTYPE_AP_VLAN: + result |= BIT(NL80211_IFTYPE_AP_VLAN); + break; + } return result; } diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index 90d7d09a6c63..de06c1e20b5b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -22,14 +22,6 @@ #include "qlink.h" -static inline void qtnf_cmd_skb_put_action(struct sk_buff *skb, u16 action) -{ - __le16 *buf_ptr; - - buf_ptr = skb_put(skb, sizeof(action)); - *buf_ptr = cpu_to_le16(action); -} - static inline void qtnf_cmd_skb_put_buffer(struct sk_buff *skb, const u8 *buf_src, size_t len) { @@ -68,7 +60,7 @@ static inline void qtnf_cmd_skb_put_tlv_u16(struct sk_buff *skb, memcpy(hdr->val, &tmp, sizeof(tmp)); } -u16 qlink_iface_type_mask_to_nl(u16 qlink_mask); +u16 qlink_iface_type_to_nl_mask(u16 qlink_type); u8 qlink_chan_width_mask_to_nl(u16 qlink_mask); #endif /* _QTN_FMAC_QLINK_UTIL_H_ */ diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index 529e05999abb..f4b48b77c491 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -1911,7 +1911,7 @@ static const struct rt2x00_ops rt2500usb_ops = { /* * rt2500usb module information. */ -static struct usb_device_id rt2500usb_device_table[] = { +static const struct usb_device_id rt2500usb_device_table[] = { /* ASUS */ { USB_DEVICE(0x0b05, 0x1706) }, { USB_DEVICE(0x0b05, 0x1707) }, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 0b75def39c6c..d2c289446c00 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -3702,7 +3702,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, if (rt2x00_rt(rt2x00dev, RT3572)) rt2800_rfcsr_write(rt2x00dev, 8, 0); - tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); + if (rt2x00_rt(rt2x00dev, RT6352)) + tx_pin = rt2800_register_read(rt2x00dev, TX_PIN_CFG); + else + tx_pin = 0; switch (rt2x00dev->default_ant.tx_chain_num) { case 3: diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c index ee5276e233fa..1123e2bed803 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800mmio.c @@ -136,10 +136,19 @@ void rt2800mmio_fill_rxdone(struct queue_entry *entry, */ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; - if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) { rxdesc->flags |= RX_FLAG_DECRYPTED; - else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + } else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) { + /* + * In order to check the Michael Mic, the packet must have + * been decrypted. Mac80211 doesnt check the MMIC failure + * flag to initiate MMIC countermeasures if the decoded flag + * has not been set. + */ + rxdesc->flags |= RX_FLAG_DECRYPTED; + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } } if (rt2x00_get_field32(word, RXD_W3_MY_BSS)) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 685b8e0cd67d..24fc6d2045ef 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -697,11 +697,20 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry, * stripped it from the frame. Signal this to mac80211. */ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; - - if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) { + rxdesc->flags |= RX_FLAG_DECRYPTED; + } else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) { + /* + * In order to check the Michael Mic, the packet must have + * been decrypted. Mac80211 doesnt check the MMIC failure + * flag to initiate MMIC countermeasures if the decoded flag + * has not been set. + */ rxdesc->flags |= RX_FLAG_DECRYPTED; - else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } } if (rt2x00_get_field32(word, RXD_W0_MY_BSS)) @@ -915,7 +924,7 @@ static const struct rt2x00_ops rt2800usb_ops = { /* * rt2800usb module information. */ -static struct usb_device_id rt2800usb_device_table[] = { +static const struct usb_device_id rt2800usb_device_table[] = { /* Abocom */ { USB_DEVICE(0x07b8, 0x2870) }, { USB_DEVICE(0x07b8, 0x2770) }, diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index fd913222abd1..9a212823f42c 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -2408,7 +2408,7 @@ static const struct rt2x00_ops rt73usb_ops = { /* * rt73usb module information. */ -static struct usb_device_id rt73usb_device_table[] = { +static const struct usb_device_id rt73usb_device_table[] = { /* AboCom */ { USB_DEVICE(0x07b8, 0xb21b) }, { USB_DEVICE(0x07b8, 0xb21c) }, diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 55198ac2b755..121b94f09714 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -43,7 +43,7 @@ MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); -static struct usb_device_id rtl8187_table[] = { +static const struct usb_device_id rtl8187_table[] = { /* Asus */ {USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187}, /* Belkin */ diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 21e5ef021260..7806a4d2b1fc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6190,7 +6190,7 @@ static void rtl8xxxu_disconnect(struct usb_interface *interface) ieee80211_free_hw(hw); } -static struct usb_device_id dev_table[] = { +static const struct usb_device_id dev_table[] = { {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8723au_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1724, 0xff, 0xff, 0xff), diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index e36ee592c660..ea18aa7afecb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -426,9 +426,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) hw->extra_tx_headroom = RTL_TX_HEADER_SIZE; /* TODO: Correct this value for our hw */ - /* TODO: define these hard code value */ - hw->max_listen_interval = 10; - hw->max_rate_tries = 4; + hw->max_listen_interval = MAX_LISTEN_INTERVAL; + hw->max_rate_tries = MAX_RATE_TRIES; /* hw->max_rates = 1; */ hw->sta_data_size = sizeof(struct rtl_sta_info); @@ -1166,9 +1165,9 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, } } - if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) + if (is_multicast_ether_addr(hdr->addr1)) tcb_desc->multicast = 1; - else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + else if (is_broadcast_ether_addr(hdr->addr1)) tcb_desc->broadcast = 1; _rtl_txrate_selectmode(hw, sta, tcb_desc); @@ -1408,6 +1407,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, return true; } else if (ETH_P_PAE == ether_type) { + /* EAPOL is seens as in-4way */ + rtlpriv->btcoexist.btc_info.in_4way = true; + rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies; + rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies; + RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, "802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"); @@ -1735,12 +1739,12 @@ void rtl_scan_list_expire(struct ieee80211_hw *hw) continue; list_del(&entry->list); - kfree(entry); rtlpriv->scan_list.num--; RT_TRACE(rtlpriv, COMP_SCAN, DBG_LOUD, "BSSID=%pM is expire in scan list (total=%d)\n", entry->bssid, rtlpriv->scan_list.num); + kfree(entry); } spin_unlock_irqrestore(&rtlpriv->locks.scan_list_lock, flags); @@ -1959,6 +1963,12 @@ label_lps_done: if (rtlpriv->cfg->ops->get_btc_status()) rtlpriv->btcoexist.btc_ops->btc_periodical(rtlpriv); + if (rtlpriv->btcoexist.btc_info.in_4way) { + if (time_after(jiffies, rtlpriv->btcoexist.btc_info.in_4way_ts + + msecs_to_jiffies(IN_4WAY_TIMEOUT_TIME))) + rtlpriv->btcoexist.btc_info.in_4way = false; + } + rtlpriv->link_info.bcn_rx_inperiod = 0; /* <6> scan list */ diff --git a/drivers/net/wireless/realtek/rtlwifi/base.h b/drivers/net/wireless/realtek/rtlwifi/base.h index ab7d81904d25..b56d1b7f5567 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.h +++ b/drivers/net/wireless/realtek/rtlwifi/base.h @@ -65,6 +65,8 @@ enum ap_peer { #define FRAME_OFFSET_ADDRESS3 16 #define FRAME_OFFSET_SEQUENCE 22 #define FRAME_OFFSET_ADDRESS4 24 +#define MAX_LISTEN_INTERVAL 10 +#define MAX_RATE_TRIES 4 #define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ WRITEEF2BYTE(_hdr, _val) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h index 2ac989a4b2bb..02dff4c3f664 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h @@ -43,22 +43,6 @@ #define RT_SDIO_INTERFACE 3 #define DEV_BUS_TYPE RT_PCI_INTERFACE -/* IC type */ -#define RTL_HW_TYPE(adapter) (rtl_hal((struct rtl_priv *)adapter)->hw_type) - -#define IS_NEW_GENERATION_IC(adapter) \ - (RTL_HW_TYPE(adapter) >= HARDWARE_TYPE_RTL8192EE) -#define IS_HARDWARE_TYPE_8812(adapter) \ - (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8812AE) -#define IS_HARDWARE_TYPE_8821(adapter) \ - (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8821AE) -#define IS_HARDWARE_TYPE_8723A(adapter) \ - (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8723AE) -#define IS_HARDWARE_TYPE_8723B(adapter) \ - (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8723BE) -#define IS_HARDWARE_TYPE_8192E(adapter) \ - (RTL_HW_TYPE(adapter) == HARDWARE_TYPE_RTL8192EE) - #include "halbtc8192e2ant.h" #include "halbtc8723b1ant.h" #include "halbtc8723b2ant.h" diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 03998d2e9eb8..c04425236ce4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -600,14 +600,8 @@ static void halbtc8723b1ant_coex_table_with_type(struct btc_coexist *btcoexist, 0xffffff, 0x3); break; case 5: - if ((coex_sta->cck_ever_lock) && (coex_sta->scan_ap_num <= 5)) - halbtc8723b1ant_coex_table(btcoexist, force_exec, - 0x5a5a5a5a, 0x5aaa5a5a, - 0xffffff, 0x3); - else - halbtc8723b1ant_coex_table(btcoexist, force_exec, - 0x5a5a5a5a, 0x5aaa5a5a, - 0xffffff, 0x3); + halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x5a5a5a5a, + 0x5aaa5a5a, 0xffffff, 0x3); break; case 6: halbtc8723b1ant_coex_table(btcoexist, force_exec, 0x55555555, diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index e6024b013ca5..c1eacd8352a2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -327,7 +327,22 @@ static void halbtc_aggregation_check(struct btc_coexist *btcoexist) static u32 halbtc_get_bt_patch_version(struct btc_coexist *btcoexist) { - return 0; + struct rtl_priv *rtlpriv = btcoexist->adapter; + u8 cmd_buffer[4] = {0}; + u8 oper_ver = 0; + u8 req_num = 0x0E; + + if (btcoexist->bt_info.bt_real_fw_ver) + goto label_done; + + cmd_buffer[0] |= (oper_ver & 0x0f); /* Set OperVer */ + cmd_buffer[0] |= ((req_num << 4) & 0xf0); /* Set ReqNum */ + cmd_buffer[1] = 0; /* BT_OP_GET_BT_VERSION = 0 */ + rtlpriv->cfg->ops->fill_h2c_cmd(rtlpriv->mac80211.hw, 0x67, 4, + &cmd_buffer[0]); + +label_done: + return btcoexist->bt_info.bt_real_fw_ver; } u32 halbtc_get_wifi_link_status(struct btc_coexist *btcoexist) diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c index 4366c9817e1e..7d296a401b6f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c @@ -41,6 +41,7 @@ static struct rtl_btc_ops rtl_btc_operation = { .btc_periodical = rtl_btc_periodical, .btc_halt_notify = rtl_btc_halt_notify, .btc_btinfo_notify = rtl_btc_btinfo_notify, + .btc_btmpinfo_notify = rtl_btc_btmpinfo_notify, .btc_is_limited_dig = rtl_btc_is_limited_dig, .btc_is_disable_edca_turbo = rtl_btc_is_disable_edca_turbo, .btc_is_bt_disabled = rtl_btc_is_bt_disabled, @@ -165,6 +166,33 @@ void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) exhalbtc_bt_info_notify(&gl_bt_coexist, tmp_buf, length); } +void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length) +{ + u8 extid, seq, len; + u16 bt_real_fw_ver; + u8 bt_fw_ver; + + if ((length < 4) || (!tmp_buf)) + return; + + extid = tmp_buf[0]; + /* not response from BT FW then exit*/ + if (extid != 1) /* C2H_TRIG_BY_BT_FW = 1 */ + return; + + len = tmp_buf[1] >> 4; + seq = tmp_buf[2] >> 4; + + /* BT Firmware version response */ + if (seq == 0x0E) { + bt_real_fw_ver = tmp_buf[3] | (tmp_buf[4] << 8); + bt_fw_ver = tmp_buf[5]; + + gl_bt_coexist.bt_info.bt_real_fw_ver = bt_real_fw_ver; + gl_bt_coexist.bt_info.bt_fw_ver = bt_fw_ver; + } +} + bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv) { return gl_bt_coexist.bt_info.limited_dig; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h index 6fe521cbe7f0..ac1253c46f44 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h @@ -39,6 +39,7 @@ void rtl_btc_mediastatus_notify(struct rtl_priv *rtlpriv, void rtl_btc_periodical(struct rtl_priv *rtlpriv); void rtl_btc_halt_notify(void); void rtl_btc_btinfo_notify(struct rtl_priv *rtlpriv, u8 *tmpbuf, u8 length); +void rtl_btc_btmpinfo_notify(struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length); bool rtl_btc_is_limited_dig(struct rtl_priv *rtlpriv); bool rtl_btc_is_disable_edca_turbo(struct rtl_priv *rtlpriv); bool rtl_btc_is_bt_disabled(struct rtl_priv *rtlpriv); diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index b0ad061048c5..c53cbf3d52bd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1505,6 +1505,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 mac_addr[ETH_ALEN]; u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + rtlpriv->btcoexist.btc_info.in_4way = false; + if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "not open hw encryption\n"); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 032b6317690d..08dc8919ef60 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -2257,7 +2257,7 @@ int rtl_pci_probe(struct pci_dev *pdev, /* find adapter */ if (!_rtl_pci_find_adapter(pdev, hw)) { err = -ENODEV; - goto fail3; + goto fail2; } /* Init IO handler */ @@ -2318,10 +2318,10 @@ fail3: pci_set_drvdata(pdev, NULL); rtl_deinit_core(hw); +fail2: if (rtlpriv->io.pci_mem_start != 0) pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); -fail2: pci_release_regions(pdev); complete(&rtlpriv->firmware_loading_complete); diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c index 951d257cd4c0..02811eda57cd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rc.c +++ b/drivers/net/wireless/realtek/rtlwifi/rc.c @@ -283,7 +283,7 @@ static void rtl_rate_free_sta(void *rtlpriv, kfree(rate_priv); } -static struct rate_control_ops rtl_rate_ops = { +static const struct rate_control_ops rtl_rate_ops = { .name = "rtl_rc", .alloc = rtl_rate_alloc, .free = rtl_rate_free, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 774e72058d24..57e5d5c1d24b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -175,6 +175,8 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) rtl_fw_cb); if (err) { pr_info("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } @@ -376,7 +378,7 @@ static const struct rtl_hal_cfg rtl88ee_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl88ee_pci_ids[] = { +static const struct pci_device_id rtl88ee_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8179, rtl88ee_hal_cfg)}, {}, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index bcbb0c60f1f1..38f85bfdf0c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -176,6 +176,8 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtl_fw_cb); if (err) { pr_err("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index f95a64507f17..530e80f0ef0b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -777,10 +777,6 @@ static void _rtl92cu_init_queue_priority(struct ieee80211_hw *hw, queue_sel); } -static void _rtl92cu_init_usb_aggregation(struct ieee80211_hw *hw) -{ -} - static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) { u16 value16; @@ -870,7 +866,6 @@ static int _rtl92cu_init_mac(struct ieee80211_hw *hw) rtl92c_init_edca(hw); rtl92c_init_rate_fallback(hw); rtl92c_init_retry_function(hw); - _rtl92cu_init_usb_aggregation(hw); rtlpriv->cfg->ops->set_bw_mode(hw, NL80211_CHAN_HT20); rtl92c_set_min_space(hw, IS_92C_SERIAL(rtlhal->version)); _rtl92cu_init_beacon_parameters(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c index 1b124eade846..5657b1e34ad0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c @@ -352,11 +352,10 @@ u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw) void rtl92c_enable_interrupt(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); - if (IS_HARDWARE_TYPE_8192CE(rtlhal)) { + if (IS_HARDWARE_TYPE_8192CE(rtlpriv)) { rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 96c923b3feb4..43e021b49260 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -85,6 +85,10 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) err = request_firmware_nowait(THIS_MODULE, 1, fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); + if (err) { + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + } return err; } @@ -173,7 +177,7 @@ static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { .rx_urb_num = RTL92C_NUM_RX_URBS, .rx_max_size = RTL92C_SIZE_MAX_RX_BUFFER, .usb_rx_hdl = rtl8192cu_rx_hdl, - .usb_rx_segregate_hdl = NULL, /* rtl8192c_rx_segregate_hdl; */ + .usb_rx_segregate_hdl = NULL, /* tx */ .usb_tx_cleanup = rtl8192c_tx_cleanup, .usb_tx_post_hdl = rtl8192c_tx_post_hdl, @@ -275,7 +279,7 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = { #define USB_VENDER_ID_REALTEK 0x0bda /* 2010-10-19 DID_USB_V3.4 */ -static struct usb_device_id rtl8192c_usb_ids[] = { +static const struct usb_device_id rtl8192c_usb_ids[] = { /*=== Realtek demoboard ===*/ /* Default ID */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index de6c3428f7c6..ac4a82de40c7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -436,13 +436,6 @@ void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb) _rtl_rx_process(hw, skb); } -void rtl8192c_rx_segregate_hdl( - struct ieee80211_hw *hw, - struct sk_buff *skb, - struct sk_buff_head *skb_list) -{ -} - /*---------------------------------------------------------------------- * * Tx handler @@ -675,8 +668,3 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD, "H2C Tx Cmd Content", pdesc, RTL_TX_DESC_SIZE); } - -bool rtl92cu_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - return true; -} diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h index 487eec89bc29..15a66c547287 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h @@ -385,8 +385,6 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, struct ieee80211_rx_status *rx_status, u8 *p_desc, struct sk_buff *skb); void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb); -void rtl8192c_rx_segregate_hdl(struct ieee80211_hw *, struct sk_buff *, - struct sk_buff_head *); void rtl8192c_tx_cleanup(struct ieee80211_hw *hw, struct sk_buff *skb); int rtl8192c_tx_post_hdl(struct ieee80211_hw *hw, struct urb *urb, struct sk_buff *skb); @@ -404,6 +402,5 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool b_firstseg, bool b_lastseg, struct sk_buff *skb); -bool rtl92cu_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index 16132c66e5e1..a6549f5f6c59 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -183,6 +183,8 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) rtl_fw_cb); if (err) { pr_err("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } @@ -347,7 +349,7 @@ static const struct rtl_hal_cfg rtl92de_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; -static struct pci_device_id rtl92de_pci_ids[] = { +static const struct pci_device_id rtl92de_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8193, rtl92de_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x002B, rtl92de_hal_cfg)}, {}, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index f5d4df985c37..7eae27f8e173 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -887,6 +887,7 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, u8 c2h_cmd_len, u8 *tmp_buf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { case C2H_8192E_DBG: @@ -905,12 +906,16 @@ void rtl92ee_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_id, case C2H_8192E_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_INFO!!\n"); - rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); break; case C2H_8192E_BT_MP: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_MP!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); break; case C2H_8192E_RA_RPT: _rtl92ee_c2h_ra_report_handler(hw, tmp_buf, c2h_cmd_len); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index d84ac7adfd82..ef9394be7016 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -2133,7 +2133,12 @@ static void _rtl92ee_read_adapter_info(struct ieee80211_hw *hw) if ((*(u8 *)&hwinfo[EEPROM_RF_BOARD_OPTION_92E]) == 0xFF) rtlefuse->board_type = 0; + if (rtlpriv->btcoexist.btc_info.btcoexist == 1) + rtlefuse->board_type |= BIT(2); /* ODM_BOARD_BT */ + rtlhal->board_type = rtlefuse->board_type; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "board_type = 0x%x\n", rtlefuse->board_type); /*parse xtal*/ rtlefuse->crystalcap = hwinfo[EEPROM_XTAL_92E]; if (hwinfo[EEPROM_XTAL_92E] == 0xFF) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index eaa503b7c4b4..a3490080d066 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -177,6 +177,8 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw) rtl_fw_cb); if (err) { pr_err("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } @@ -354,7 +356,7 @@ static const struct rtl_hal_cfg rtl92ee_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl92ee_pci_ids[] = { +static const struct pci_device_id rtl92ee_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x818B, rtl92ee_hal_cfg)}, {}, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 55f238a2a310..c58393eab6a1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -478,7 +478,6 @@ u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index) struct rtl_priv *rtlpriv = rtl_priv(hw); u16 read_point = 0, write_point = 0, remind_cnt = 0; u32 tmp_4byte = 0; - static u16 last_read_point; static bool start_rx; tmp_4byte = rtl_read_dword(rtlpriv, REG_RXQ_TXBD_IDX); @@ -506,7 +505,6 @@ u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index) rtlpci->rx_ring[queue_index].next_rx_rp = write_point; - last_read_point = read_point; return remind_cnt; } @@ -917,7 +915,6 @@ void rtl92ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, struct rtl_priv *rtlpriv = rtl_priv(hw); u16 cur_tx_rp = 0; u16 cur_tx_wp = 0; - static u16 last_txw_point; static bool over_run; u32 tmp = 0; u8 q_idx = *val; @@ -951,9 +948,6 @@ void rtl92ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, rtl_write_word(rtlpriv, get_desc_addr_fr_q_idx(q_idx), ring->cur_tx_wp); - - if (q_idx == 1) - last_txw_point = cur_tx_wp; } if (ring->avl_desc < (max_tx_desc - 15)) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index 2006b09ea74f..d7945b9db493 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -216,6 +216,8 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) rtl92se_fw_cb); if (err) { pr_err("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } @@ -396,7 +398,7 @@ static const struct rtl_hal_cfg rtl92se_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15, }; -static struct pci_device_id rtl92se_pci_ids[] = { +static const struct pci_device_id rtl92se_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)}, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 7bf9f2557920..97b8bd294aa8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -184,6 +184,8 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw) rtl_fw_cb); if (err) { pr_err("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } return 0; @@ -367,7 +369,7 @@ static const struct rtl_hal_cfg rtl8723e_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl8723e_pci_ids[] = { +static const struct pci_device_id rtl8723e_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8723, rtl8723e_hal_cfg)}, {}, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c index 131c0d1d633e..15c117e95a99 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c @@ -883,12 +883,8 @@ static void rtl8723be_dm_txpower_tracking_callback_thermalmeter( if ((rtldm->power_index_offset[RF90_PATH_A] != 0) && (rtldm->txpower_track_control)) { rtldm->done_txpower = true; - if (thermalvalue > rtlefuse->eeprom_thermalmeter) - rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0, - index_for_channel); - else - rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0, - index_for_channel); + rtl8723be_dm_tx_power_track_set_power(hw, BBSWING, 0, + index_for_channel); rtldm->swing_idx_cck_base = rtldm->swing_idx_cck; rtldm->swing_idx_ofdm_base[RF90_PATH_A] = diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c index dd6f95cfaec9..4b963fd27d64 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c @@ -709,6 +709,7 @@ void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, u8 c2h_cmd_len, u8 *tmp_buf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { case C2H_8723B_DBG: @@ -723,12 +724,16 @@ void rtl8723be_c2h_content_parsing(struct ieee80211_hw *hw, case C2H_8723B_BT_INFO: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_INFO!!\n"); - rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, - c2h_cmd_len); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); break; case C2H_8723B_BT_MP: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "[C2H], C2H_8723BE_BT_MP!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); break; default: RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index cd5dc6dcb19f..4d47b97adfed 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -2111,6 +2111,13 @@ static void _rtl8723be_read_adapter_info(struct ieee80211_hw *hw, rtlefuse->autoload_failflag, hwinfo); + if (rtlpriv->btcoexist.btc_info.btcoexist == 1) + rtlefuse->board_type |= BIT(2); /* ODM_BOARD_BT */ + + rtlhal->board_type = rtlefuse->board_type; + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + "board_type = 0x%x\n", rtlefuse->board_type); + rtlhal->package_type = _rtl8723be_read_package_type(hw); /* set channel plan from efuse */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index 9752175cc466..9606641519e7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -152,33 +152,86 @@ bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw) return rtl8723be_phy_rf6052_config(hw); } -static bool _rtl8723be_check_condition(struct ieee80211_hw *hw, - const u32 condition) +static bool _rtl8723be_check_positive(struct ieee80211_hw *hw, + const u32 condition1, + const u32 condition2) { - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u32 _board = rtlefuse->board_type; /*need efuse define*/ - u32 _interface = rtlhal->interface; - u32 _platform = 0x08;/*SupportPlatform */ - u32 cond = condition; + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + u32 cut_ver = ((rtlhal->version & CHIP_VER_RTL_MASK) + >> CHIP_VER_RTL_SHIFT); + u32 intf = (rtlhal->interface == INTF_USB ? BIT(1) : BIT(0)); + + u8 board_type = ((rtlhal->board_type & BIT(4)) >> 4) << 0 | /* _GLNA */ + ((rtlhal->board_type & BIT(3)) >> 3) << 1 | /* _GPA */ + ((rtlhal->board_type & BIT(7)) >> 7) << 2 | /* _ALNA */ + ((rtlhal->board_type & BIT(6)) >> 6) << 3 | /* _APA */ + ((rtlhal->board_type & BIT(2)) >> 2) << 4; /* _BT */ + + u32 cond1 = condition1, cond2 = condition2; + u32 driver1 = cut_ver << 24 | /* CUT ver */ + 0 << 20 | /* interface 2/2 */ + 0x04 << 16 | /* platform */ + rtlhal->package_type << 12 | + intf << 8 | /* interface 1/2 */ + board_type; + + u32 driver2 = rtlhal->type_glna << 0 | + rtlhal->type_gpa << 8 | + rtlhal->type_alna << 16 | + rtlhal->type_apa << 24; - if (condition == 0xCDCDCDCD) - return true; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "===> [8812A] CheckPositive (cond1, cond2) = (0x%X 0x%X)\n", + cond1, cond2); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + "===> [8812A] CheckPositive (driver1, driver2) = (0x%X 0x%X)\n", + driver1, driver2); - cond = condition & 0xFF; - if ((_board & cond) == 0 && cond != 0x1F) - return false; + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + " (Platform, Interface) = (0x%X, 0x%X)\n", 0x04, intf); + RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, + " (Board, Package) = (0x%X, 0x%X)\n", + rtlhal->board_type, rtlhal->package_type); - cond = condition & 0xFF00; - cond = cond >> 8; - if ((_interface & cond) == 0 && cond != 0x07) - return false; + /*============== Value Defined Check ===============*/ + /*QFN Type [15:12] and Cut Version [27:24] need to do value check*/ - cond = condition & 0xFF0000; - cond = cond >> 16; - if ((_platform & cond) == 0 && cond != 0x0F) + if (((cond1 & 0x0000F000) != 0) && ((cond1 & 0x0000F000) != + (driver1 & 0x0000F000))) return false; - return true; + if (((cond1 & 0x0F000000) != 0) && ((cond1 & 0x0F000000) != + (driver1 & 0x0F000000))) + return false; + + /*=============== Bit Defined Check ================*/ + /* We don't care [31:28] */ + + cond1 &= 0x00FF0FFF; + driver1 &= 0x00FF0FFF; + + if ((cond1 & driver1) == cond1) { + u32 mask = 0; + + if ((cond1 & 0x0F) == 0) /* BoardType is DONTCARE*/ + return true; + + if ((cond1 & BIT(0)) != 0) /*GLNA*/ + mask |= 0x000000FF; + if ((cond1 & BIT(1)) != 0) /*GPA*/ + mask |= 0x0000FF00; + if ((cond1 & BIT(2)) != 0) /*ALNA*/ + mask |= 0x00FF0000; + if ((cond1 & BIT(3)) != 0) /*APA*/ + mask |= 0xFF000000; + + /* BoardType of each RF path is matched*/ + if ((cond2 & mask) == (driver2 & mask)) + return true; + else + return false; + } + return false; } static void _rtl8723be_config_rf_reg(struct ieee80211_hw *hw, u32 addr, @@ -464,6 +517,16 @@ static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); bool rtstatus; + /* switch ant to BT */ + if (rtlpriv->rtlhal.interface == INTF_USB) { + rtl_write_dword(rtlpriv, 0x948, 0x0); + } else { + if (rtlpriv->btcoexist.btc_info.single_ant_path == 0) + rtl_write_dword(rtlpriv, 0x948, 0x280); + else + rtl_write_dword(rtlpriv, 0x948, 0x0); + } + rtstatus = _rtl8723be_phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG); if (!rtstatus) { @@ -493,142 +556,84 @@ static bool _rtl8723be_phy_bb8723b_config_parafile(struct ieee80211_hw *hw) return true; } +static bool rtl8723be_phy_config_with_headerfile(struct ieee80211_hw *hw, + u32 *array_table, + u16 arraylen, + void (*set_reg)(struct ieee80211_hw *hw, u32 regaddr, u32 data)) +{ + #define COND_ELSE 2 + #define COND_ENDIF 3 + + int i = 0; + u8 cond; + bool matched = true, skipped = false; + + while ((i + 1) < arraylen) { + u32 v1 = array_table[i]; + u32 v2 = array_table[i + 1]; + + if (v1 & (BIT(31) | BIT(30))) {/*positive & negative condition*/ + if (v1 & BIT(31)) {/* positive condition*/ + cond = (u8)((v1 & (BIT(29) | BIT(28))) >> 28); + if (cond == COND_ENDIF) { /*end*/ + matched = true; + skipped = false; + } else if (cond == COND_ELSE) { /*else*/ + matched = skipped ? false : true; + } else {/*if , else if*/ + if (skipped) { + matched = false; + } else { + if (_rtl8723be_check_positive( + hw, v1, v2)) { + matched = true; + skipped = true; + } else { + matched = false; + skipped = false; + } + } + } + } else if (v1 & BIT(30)) { /*negative condition*/ + /*do nothing*/ + } + } else { + if (matched) + set_reg(hw, v1, v2); + } + i = i + 2; + } + + return true; +} + static bool _rtl8723be_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 i; - u32 arraylength; - u32 *ptrarray; RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read rtl8723beMACPHY_Array\n"); - arraylength = RTL8723BEMAC_1T_ARRAYLEN; - ptrarray = RTL8723BEMAC_1T_ARRAY; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "Img:RTL8723bEMAC_1T_ARRAY LEN %d\n", arraylength); - for (i = 0; i < arraylength; i = i + 2) - rtl_write_byte(rtlpriv, ptrarray[i], (u8)ptrarray[i + 1]); - return true; + + return rtl8723be_phy_config_with_headerfile(hw, + RTL8723BEMAC_1T_ARRAY, RTL8723BEMAC_1T_ARRAYLEN, + rtl_write_byte_with_val32); } static bool _rtl8723be_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, u8 configtype) { - #define READ_NEXT_PAIR(v1, v2, i) \ - do { \ - i += 2; \ - v1 = array_table[i];\ - v2 = array_table[i+1]; \ - } while (0) - - int i; - u32 *array_table; - u16 arraylen; - struct rtl_priv *rtlpriv = rtl_priv(hw); - u32 v1 = 0, v2 = 0; - - if (configtype == BASEBAND_CONFIG_PHY_REG) { - arraylen = RTL8723BEPHY_REG_1TARRAYLEN; - array_table = RTL8723BEPHY_REG_1TARRAY; - - for (i = 0; i < arraylen; i = i + 2) { - v1 = array_table[i]; - v2 = array_table[i+1]; - if (v1 < 0xcdcdcdcd) { - _rtl8723be_config_bb_reg(hw, v1, v2); - } else {/*This line is the start line of branch.*/ - /* to protect READ_NEXT_PAIR not overrun */ - if (i >= arraylen - 2) - break; - - if (!_rtl8723be_check_condition(hw, - array_table[i])) { - /*Discard the following - *(offset, data) pairs - */ - READ_NEXT_PAIR(v1, v2, i); - while (v2 != 0xDEAD && - v2 != 0xCDEF && - v2 != 0xCDCD && - i < arraylen - 2) { - READ_NEXT_PAIR(v1, v2, i); - } - i -= 2; /* prevent from for-loop += 2*/ - /*Configure matched pairs and - *skip to end of if-else. - */ - } else { - READ_NEXT_PAIR(v1, v2, i); - while (v2 != 0xDEAD && - v2 != 0xCDEF && - v2 != 0xCDCD && - i < arraylen - 2) { - _rtl8723be_config_bb_reg(hw, - v1, v2); - READ_NEXT_PAIR(v1, v2, i); - } - while (v2 != 0xDEAD && i < arraylen - 2) - READ_NEXT_PAIR(v1, v2, i); - } - } - } - } else if (configtype == BASEBAND_CONFIG_AGC_TAB) { - arraylen = RTL8723BEAGCTAB_1TARRAYLEN; - array_table = RTL8723BEAGCTAB_1TARRAY; - - for (i = 0; i < arraylen; i = i + 2) { - v1 = array_table[i]; - v2 = array_table[i+1]; - if (v1 < 0xCDCDCDCD) { - rtl_set_bbreg(hw, array_table[i], - MASKDWORD, - array_table[i + 1]); - udelay(1); - continue; - } else {/*This line is the start line of branch.*/ - /* to protect READ_NEXT_PAIR not overrun */ - if (i >= arraylen - 2) - break; - - if (!_rtl8723be_check_condition(hw, - array_table[i])) { - /*Discard the following - *(offset, data) pairs - */ - READ_NEXT_PAIR(v1, v2, i); - while (v2 != 0xDEAD && - v2 != 0xCDEF && - v2 != 0xCDCD && - i < arraylen - 2) { - READ_NEXT_PAIR(v1, v2, i); - } - i -= 2; /* prevent from for-loop += 2*/ - /*Configure matched pairs and - *skip to end of if-else. - */ - } else { - READ_NEXT_PAIR(v1, v2, i); - while (v2 != 0xDEAD && - v2 != 0xCDEF && - v2 != 0xCDCD && - i < arraylen - 2) { - rtl_set_bbreg(hw, array_table[i], - MASKDWORD, - array_table[i + 1]); - udelay(1); - READ_NEXT_PAIR(v1, v2, i); - } + if (configtype == BASEBAND_CONFIG_PHY_REG) + return rtl8723be_phy_config_with_headerfile(hw, + RTL8723BEPHY_REG_1TARRAY, + RTL8723BEPHY_REG_1TARRAYLEN, + _rtl8723be_config_bb_reg); + else if (configtype == BASEBAND_CONFIG_AGC_TAB) + return rtl8723be_phy_config_with_headerfile(hw, + RTL8723BEAGCTAB_1TARRAY, + RTL8723BEAGCTAB_1TARRAYLEN, + rtl_set_bbreg_with_dwmask); - while (v2 != 0xDEAD && i < arraylen - 2) - READ_NEXT_PAIR(v1, v2, i); - } - } - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, - "The agctab_array_table[0] is %x Rtl818EEPHY_REGArray[1] is %x\n", - array_table[i], array_table[i + 1]); - } - } - return true; + return false; } static u8 _rtl8723be_get_rate_section_index(u32 regaddr) @@ -761,73 +766,17 @@ static bool _rtl8723be_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { - #define READ_NEXT_RF_PAIR(v1, v2, i) \ - do { \ - i += 2; \ - v1 = radioa_array_table[i]; \ - v2 = radioa_array_table[i+1]; \ - } while (0) - - int i; - bool rtstatus = true; - u32 *radioa_array_table; - u16 radioa_arraylen; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u32 v1 = 0, v2 = 0; + bool ret = true; - radioa_arraylen = RTL8723BE_RADIOA_1TARRAYLEN; - radioa_array_table = RTL8723BE_RADIOA_1TARRAY; - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, - "Radio_A:RTL8723BE_RADIOA_1TARRAY %d\n", radioa_arraylen); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: - for (i = 0; i < radioa_arraylen; i = i + 2) { - v1 = radioa_array_table[i]; - v2 = radioa_array_table[i+1]; - if (v1 < 0xcdcdcdcd) { - _rtl8723be_config_rf_radio_a(hw, v1, v2); - } else {/*This line is the start line of branch.*/ - /* to protect READ_NEXT_PAIR not overrun */ - if (i >= radioa_arraylen - 2) - break; - - if (!_rtl8723be_check_condition(hw, - radioa_array_table[i])) { - /*Discard the following - *(offset, data) pairs - */ - READ_NEXT_RF_PAIR(v1, v2, i); - while (v2 != 0xDEAD && - v2 != 0xCDEF && - v2 != 0xCDCD && - i < radioa_arraylen - 2) { - READ_NEXT_RF_PAIR(v1, v2, i); - } - i -= 2; /* prevent from for-loop += 2*/ - } else { - /*Configure matched pairs - *and skip to end of if-else. - */ - READ_NEXT_RF_PAIR(v1, v2, i); - while (v2 != 0xDEAD && - v2 != 0xCDEF && - v2 != 0xCDCD && - i < radioa_arraylen - 2) { - _rtl8723be_config_rf_radio_a(hw, - v1, v2); - READ_NEXT_RF_PAIR(v1, v2, i); - } - - while (v2 != 0xDEAD && - i < radioa_arraylen - 2) { - READ_NEXT_RF_PAIR(v1, v2, i); - } - } - } - } + ret = rtl8723be_phy_config_with_headerfile(hw, + RTL8723BE_RADIOA_1TARRAY, + RTL8723BE_RADIOA_1TARRAYLEN, + _rtl8723be_config_rf_radio_a); if (rtlhal->oem_id == RT_CID_819X_HP) _rtl8723be_config_rf_radio_a(hw, 0x52, 0x7E4BD); @@ -840,7 +789,7 @@ bool rtl8723be_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, "switch case %#x not processed\n", rfpath); break; } - return true; + return ret; } void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw) @@ -1350,7 +1299,7 @@ void rtl8723be_phy_sw_chnl_callback(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_phy *rtlphy = &rtlpriv->phy; - u32 delay; + u32 delay = 0; RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "switch to channel%d\n", rtlphy->current_channel); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index f9d10f1e7cf8..2b16a1467e78 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -187,16 +187,10 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { - /* Failed to get firmware. Check if old version available */ - fw_name = "rtlwifi/rtl8723befw.bin"; - pr_info("Using firmware %s\n", fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, fw_name, - rtlpriv->io.dev, GFP_KERNEL, hw, - rtl_fw_cb); - if (err) { - pr_err("Failed to request firmware!\n"); - return 1; - } + pr_err("Failed to request firmware!\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; + return 1; } return 0; } @@ -287,6 +281,7 @@ static const struct rtl_hal_cfg rtl8723be_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl8723be_pci", + .alt_fw_name = "rtlwifi/rtl8723befw.bin", .ops = &rtl8723be_hal_ops, .mod_params = &rtl8723be_mod_params, .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, @@ -380,7 +375,7 @@ static const struct rtl_hal_cfg rtl8723be_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl8723be_pci_ids[] = { +static const struct pci_device_id rtl8723be_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0xB723, rtl8723be_hal_cfg)}, {}, }; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.c index a180761e8810..381c16b9b3a9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.c @@ -26,6 +26,7 @@ *****************************************************************************/ #include "table.h" + u32 RTL8723BEPHY_REG_1TARRAY[] = { 0x800, 0x80040000, 0x804, 0x00000003, @@ -36,7 +37,7 @@ u32 RTL8723BEPHY_REG_1TARRAY[] = { 0x818, 0x02200385, 0x81C, 0x00000000, 0x820, 0x01000100, - 0x824, 0x00390204, + 0x824, 0x00190204, 0x828, 0x00000000, 0x82C, 0x00000000, 0x830, 0x00000000, @@ -73,9 +74,8 @@ u32 RTL8723BEPHY_REG_1TARRAY[] = { 0x90C, 0x81121111, 0x910, 0x00000002, 0x914, 0x00000201, - 0x948, 0x00000280, 0xA00, 0x00D047C8, - 0xA04, 0x80FF000C, + 0xA04, 0x80FF800C, 0xA08, 0x8C838300, 0xA0C, 0x2E7F120F, 0xA10, 0x9500BB78, @@ -114,7 +114,7 @@ u32 RTL8723BEPHY_REG_1TARRAY[] = { 0xC4C, 0x007F037F, 0xC50, 0x69553420, 0xC54, 0x43BC0094, - 0xC58, 0x00023169, + 0xC58, 0x00013147, 0xC5C, 0x00250492, 0xC60, 0x00000000, 0xC64, 0x7112848B, @@ -125,7 +125,7 @@ u32 RTL8723BEPHY_REG_1TARRAY[] = { 0xC78, 0x0000001F, 0xC7C, 0x00B91612, 0xC80, 0x390000E4, - 0xC84, 0x20F60000, + 0xC84, 0x21F60000, 0xC88, 0x40000100, 0xC8C, 0x20200000, 0xC90, 0x00020E1A, @@ -224,15 +224,21 @@ u32 RTL8723BEPHY_REG_1TARRAY[] = { }; +u32 RTL8723BEPHY_REG_1TARRAYLEN = + sizeof(RTL8723BEPHY_REG_1TARRAY) / sizeof(u32); + u32 RTL8723BEPHY_REG_ARRAY_PG[] = { - 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00004000, - 0, 0, 0, 0x0000086c, 0xffffff00, 0x34363800, - 0, 0, 0, 0x00000e00, 0xffffffff, 0x42444646, - 0, 0, 0, 0x00000e04, 0xffffffff, 0x30343840, + 0, 0, 0, 0x00000e08, 0x0000ff00, 0x00003800, + 0, 0, 0, 0x0000086c, 0xffffff00, 0x32343600, + 0, 0, 0, 0x00000e00, 0xffffffff, 0x40424444, + 0, 0, 0, 0x00000e04, 0xffffffff, 0x28323638, 0, 0, 0, 0x00000e10, 0xffffffff, 0x38404244, 0, 0, 0, 0x00000e14, 0xffffffff, 0x26303436 }; +u32 RTL8723BEPHY_REG_ARRAY_PGLEN = + sizeof(RTL8723BEPHY_REG_ARRAY_PG) / sizeof(u32); + u32 RTL8723BE_RADIOA_1TARRAY[] = { 0x000, 0x00010000, 0x0B0, 0x000DFFE0, @@ -257,15 +263,37 @@ u32 RTL8723BE_RADIOA_1TARRAY[] = { 0x01E, 0x00000000, 0x0DF, 0x00000780, 0x050, 0x00067435, + 0x80002000, 0x00000000, 0x40000000, 0x00000000, + 0x051, 0x0006F10E, + 0x052, 0x000007D3, + 0x90003000, 0x00000000, 0x40000000, 0x00000000, + 0x051, 0x0006F10E, + 0x052, 0x000007D3, + 0x90004000, 0x00000000, 0x40000000, 0x00000000, + 0x051, 0x0006F10E, + 0x052, 0x000007D3, + 0xA0000000, 0x00000000, 0x051, 0x0006B04E, 0x052, 0x000007D2, + 0xB0000000, 0x00000000, 0x053, 0x00000000, 0x054, 0x00050400, 0x055, 0x0004026E, 0x0DD, 0x0000004C, 0x070, 0x00067435, + 0x80002000, 0x00000000, 0x40000000, 0x00000000, + 0x071, 0x0006F10E, + 0x072, 0x000007D3, + 0x90003000, 0x00000000, 0x40000000, 0x00000000, + 0x071, 0x0006F10E, + 0x072, 0x000007D3, + 0x90004000, 0x00000000, 0x40000000, 0x00000000, + 0x071, 0x0006F10E, + 0x072, 0x000007D3, + 0xA0000000, 0x00000000, 0x071, 0x0006B04E, 0x072, 0x000007D2, + 0xB0000000, 0x00000000, 0x073, 0x00000000, 0x074, 0x00050400, 0x075, 0x0004026E, @@ -308,6 +336,7 @@ u32 RTL8723BE_RADIOA_1TARRAY[] = { 0x044, 0x00000051, 0x0EF, 0x00000000, 0x0ED, 0x00000000, + 0x07F, 0x00020080, 0x0EF, 0x00002000, 0x03B, 0x000380EF, 0x03B, 0x000302FE, @@ -336,14 +365,24 @@ u32 RTL8723BE_RADIOA_1TARRAY[] = { 0x0A3, 0x00008000, 0x0A4, 0x00048D80, 0x0A5, 0x00068000, - 0x000, 0x00033D80, + 0x0ED, 0x00000002, + 0x0EF, 0x00000002, + 0x056, 0x00000032, + 0x076, 0x00000032, + 0x001, 0x00000780, }; +u32 RTL8723BE_RADIOA_1TARRAYLEN = + sizeof(RTL8723BE_RADIOA_1TARRAY) / sizeof(u32); + u32 RTL8723BEMAC_1T_ARRAY[] = { 0x02F, 0x00000030, 0x035, 0x00000000, + 0x039, 0x00000008, + 0x064, 0x00000000, 0x067, 0x00000020, + 0x421, 0x0000000F, 0x428, 0x0000000A, 0x429, 0x00000010, 0x430, 0x00000000, @@ -439,9 +478,13 @@ u32 RTL8723BEMAC_1T_ARRAY[] = { 0x709, 0x00000043, 0x70A, 0x00000065, 0x70B, 0x00000087, + 0x765, 0x00000018, + 0x76E, 0x00000004, }; +u32 RTL8723BEMAC_1T_ARRAYLEN = sizeof(RTL8723BEMAC_1T_ARRAY) / sizeof(u32); + u32 RTL8723BEAGCTAB_1TARRAY[] = { 0xC78, 0xFD000001, 0xC78, 0xFC010001, @@ -466,21 +509,21 @@ u32 RTL8723BEAGCTAB_1TARRAY[] = { 0xC78, 0xE9140001, 0xC78, 0xE8150001, 0xC78, 0xE7160001, - 0xC78, 0xAA170001, - 0xC78, 0xA9180001, - 0xC78, 0xA8190001, - 0xC78, 0xA71A0001, - 0xC78, 0xA61B0001, - 0xC78, 0xA51C0001, - 0xC78, 0xA41D0001, - 0xC78, 0xA31E0001, - 0xC78, 0x671F0001, - 0xC78, 0x66200001, - 0xC78, 0x65210001, - 0xC78, 0x64220001, - 0xC78, 0x63230001, - 0xC78, 0x62240001, - 0xC78, 0x61250001, + 0xC78, 0xE6170001, + 0xC78, 0xE5180001, + 0xC78, 0xE4190001, + 0xC78, 0xE31A0001, + 0xC78, 0xA51B0001, + 0xC78, 0xA41C0001, + 0xC78, 0xA31D0001, + 0xC78, 0x671E0001, + 0xC78, 0x661F0001, + 0xC78, 0x65200001, + 0xC78, 0x64210001, + 0xC78, 0x63220001, + 0xC78, 0x4A230001, + 0xC78, 0x49240001, + 0xC78, 0x48250001, 0xC78, 0x47260001, 0xC78, 0x46270001, 0xC78, 0x45280001, @@ -491,22 +534,22 @@ u32 RTL8723BEAGCTAB_1TARRAY[] = { 0xC78, 0x282D0001, 0xC78, 0x272E0001, 0xC78, 0x262F0001, - 0xC78, 0x25300001, - 0xC78, 0x24310001, - 0xC78, 0x09320001, - 0xC78, 0x08330001, - 0xC78, 0x07340001, - 0xC78, 0x06350001, - 0xC78, 0x05360001, - 0xC78, 0x04370001, - 0xC78, 0x03380001, - 0xC78, 0x02390001, + 0xC78, 0x0A300001, + 0xC78, 0x09310001, + 0xC78, 0x08320001, + 0xC78, 0x07330001, + 0xC78, 0x06340001, + 0xC78, 0x05350001, + 0xC78, 0x04360001, + 0xC78, 0x03370001, + 0xC78, 0x02380001, + 0xC78, 0x01390001, 0xC78, 0x013A0001, - 0xC78, 0x003B0001, - 0xC78, 0x003C0001, - 0xC78, 0x003D0001, - 0xC78, 0x003E0001, - 0xC78, 0x003F0001, + 0xC78, 0x013B0001, + 0xC78, 0x013C0001, + 0xC78, 0x013D0001, + 0xC78, 0x013E0001, + 0xC78, 0x013F0001, 0xC78, 0xFC400001, 0xC78, 0xFB410001, 0xC78, 0xFA420001, @@ -531,47 +574,50 @@ u32 RTL8723BEAGCTAB_1TARRAY[] = { 0xC78, 0xE7550001, 0xC78, 0xE6560001, 0xC78, 0xE5570001, - 0xC78, 0xAA580001, - 0xC78, 0xA9590001, - 0xC78, 0xA85A0001, - 0xC78, 0xA75B0001, - 0xC78, 0xA65C0001, - 0xC78, 0xA55D0001, - 0xC78, 0xA45E0001, - 0xC78, 0x675F0001, - 0xC78, 0x66600001, - 0xC78, 0x65610001, - 0xC78, 0x64620001, - 0xC78, 0x63630001, - 0xC78, 0x62640001, - 0xC78, 0x61650001, + 0xC78, 0xE4580001, + 0xC78, 0xE3590001, + 0xC78, 0xA65A0001, + 0xC78, 0xA55B0001, + 0xC78, 0xA45C0001, + 0xC78, 0xA35D0001, + 0xC78, 0x675E0001, + 0xC78, 0x665F0001, + 0xC78, 0x65600001, + 0xC78, 0x64610001, + 0xC78, 0x63620001, + 0xC78, 0x62630001, + 0xC78, 0x61640001, + 0xC78, 0x48650001, 0xC78, 0x47660001, 0xC78, 0x46670001, 0xC78, 0x45680001, 0xC78, 0x44690001, 0xC78, 0x436A0001, 0xC78, 0x426B0001, - 0xC78, 0x296C0001, - 0xC78, 0x286D0001, - 0xC78, 0x276E0001, - 0xC78, 0x266F0001, - 0xC78, 0x25700001, - 0xC78, 0x24710001, - 0xC78, 0x09720001, - 0xC78, 0x08730001, - 0xC78, 0x07740001, - 0xC78, 0x06750001, - 0xC78, 0x05760001, - 0xC78, 0x04770001, - 0xC78, 0x03780001, - 0xC78, 0x02790001, + 0xC78, 0x286C0001, + 0xC78, 0x276D0001, + 0xC78, 0x266E0001, + 0xC78, 0x256F0001, + 0xC78, 0x24700001, + 0xC78, 0x09710001, + 0xC78, 0x08720001, + 0xC78, 0x07730001, + 0xC78, 0x06740001, + 0xC78, 0x05750001, + 0xC78, 0x04760001, + 0xC78, 0x03770001, + 0xC78, 0x02780001, + 0xC78, 0x01790001, 0xC78, 0x017A0001, - 0xC78, 0x007B0001, - 0xC78, 0x007C0001, - 0xC78, 0x007D0001, - 0xC78, 0x007E0001, - 0xC78, 0x007F0001, + 0xC78, 0x017B0001, + 0xC78, 0x017C0001, + 0xC78, 0x017D0001, + 0xC78, 0x017E0001, + 0xC78, 0x017F0001, 0xC50, 0x69553422, 0xC50, 0x69553420, + 0x824, 0x00390204, }; + +u32 RTL8723BEAGCTAB_1TARRAYLEN = sizeof(RTL8723BEAGCTAB_1TARRAY) / sizeof(u32); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.h index dc17001632f7..1deaffe22251 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.h @@ -29,15 +29,15 @@ #define __RTL8723BE_TABLE__H_ #include <linux/types.h> -#define RTL8723BEPHY_REG_1TARRAYLEN 388 +extern u32 RTL8723BEPHY_REG_1TARRAYLEN; extern u32 RTL8723BEPHY_REG_1TARRAY[]; -#define RTL8723BEPHY_REG_ARRAY_PGLEN 36 +extern u32 RTL8723BEPHY_REG_ARRAY_PGLEN; extern u32 RTL8723BEPHY_REG_ARRAY_PG[]; -#define RTL8723BE_RADIOA_1TARRAYLEN 206 +extern u32 RTL8723BE_RADIOA_1TARRAYLEN; extern u32 RTL8723BE_RADIOA_1TARRAY[]; -#define RTL8723BEMAC_1T_ARRAYLEN 196 +extern u32 RTL8723BEMAC_1T_ARRAYLEN; extern u32 RTL8723BEMAC_1T_ARRAY[]; -#define RTL8723BEAGCTAB_1TARRAYLEN 260 +extern u32 RTL8723BEAGCTAB_1TARRAYLEN; extern u32 RTL8723BEAGCTAB_1TARRAY[]; #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c index 03259aa150fd..f2b2c549e5b2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c @@ -98,7 +98,7 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw) if (counter >= FW_8821AE_POLLING_TIMEOUT_COUNT) { RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD, - "chksum report faill ! REG_MCUFWDL:0x%08x .\n", + "chksum report fail! REG_MCUFWDL:0x%08x .\n", value32); goto exit; } @@ -1923,6 +1923,7 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, u8 *tmp_buf) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_btc_ops *btc_ops = rtlpriv->btcoexist.btc_ops; switch (c2h_cmd_id) { case C2H_8812_DBG: @@ -1938,9 +1939,15 @@ void rtl8821ae_c2h_content_parsing(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD, "[C2H], C2H_8812_BT_INFO!!\n"); if (rtlpriv->cfg->ops->get_btc_status()) - rtlpriv->btcoexist.btc_ops->btc_btinfo_notify(rtlpriv, - tmp_buf, - c2h_cmd_len); + btc_ops->btc_btinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); + break; + case C2H_8812_BT_MP: + RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, + "[C2H], C2H_8812_BT_MP!!\n"); + if (rtlpriv->cfg->ops->get_btc_status()) + btc_ops->btc_btmpinfo_notify(rtlpriv, tmp_buf, + c2h_cmd_len); break; default: break; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index 2bc6bace069c..4f73012978e9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -779,7 +779,7 @@ void rtl8821ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) _rtl8821ae_resume_tx_beacon(hw); break; } case HW_VAR_NAV_UPPER: { - u32 us_nav_upper = ((u32)*val); + u32 us_nav_upper = *(u32 *)val; if (us_nav_upper > HAL_92C_NAV_UPPER_UNIT * 0xFF) { RT_TRACE(rtlpriv, COMP_INIT , DBG_WARNING, @@ -2966,6 +2966,44 @@ static void _rtl8812ae_read_pa_type(struct ieee80211_hw *hw, u8 *hwinfo, } } +static void _rtl8812ae_read_amplifier_type(struct ieee80211_hw *hw, u8 *hwinfo, + bool autoload_fail) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + + u8 ext_type_pa_2g_a = (hwinfo[0xBD] & BIT(2)) >> 2; /* 0xBD[2] */ + u8 ext_type_pa_2g_b = (hwinfo[0xBD] & BIT(6)) >> 6; /* 0xBD[6] */ + u8 ext_type_pa_5g_a = (hwinfo[0xBF] & BIT(2)) >> 2; /* 0xBF[2] */ + u8 ext_type_pa_5g_b = (hwinfo[0xBF] & BIT(6)) >> 6; /* 0xBF[6] */ + /* 0xBD[1:0] */ + u8 ext_type_lna_2g_a = (hwinfo[0xBD] & (BIT(1) | BIT(0))) >> 0; + /* 0xBD[5:4] */ + u8 ext_type_lna_2g_b = (hwinfo[0xBD] & (BIT(5) | BIT(4))) >> 4; + /* 0xBF[1:0] */ + u8 ext_type_lna_5g_a = (hwinfo[0xBF] & (BIT(1) | BIT(0))) >> 0; + /* 0xBF[5:4] */ + u8 ext_type_lna_5g_b = (hwinfo[0xBF] & (BIT(5) | BIT(4))) >> 4; + + _rtl8812ae_read_pa_type(hw, hwinfo, autoload_fail); + + /* [2.4G] Path A and B are both extPA */ + if ((rtlhal->pa_type_2g & (BIT(5) | BIT(4))) == (BIT(5) | BIT(4))) + rtlhal->type_gpa = ext_type_pa_2g_b << 2 | ext_type_pa_2g_a; + + /* [5G] Path A and B are both extPA */ + if ((rtlhal->pa_type_5g & (BIT(1) | BIT(0))) == (BIT(1) | BIT(0))) + rtlhal->type_apa = ext_type_pa_5g_b << 2 | ext_type_pa_5g_a; + + /* [2.4G] Path A and B are both extLNA */ + if ((rtlhal->lna_type_2g & (BIT(7) | BIT(3))) == (BIT(7) | BIT(3))) + rtlhal->type_glna = ext_type_lna_2g_b << 2 | ext_type_lna_2g_a; + + /* [5G] Path A and B are both extLNA */ + if ((rtlhal->lna_type_5g & (BIT(7) | BIT(3))) == (BIT(7) | BIT(3))) + rtlhal->type_alna = ext_type_lna_5g_b << 2 | ext_type_lna_5g_a; +} + static void _rtl8821ae_read_pa_type(struct ieee80211_hw *hw, u8 *hwinfo, bool autoload_fail) { @@ -3114,7 +3152,8 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ hwinfo); if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { - _rtl8812ae_read_pa_type(hw, hwinfo, rtlefuse->autoload_failflag); + _rtl8812ae_read_amplifier_type(hw, hwinfo, + rtlefuse->autoload_failflag); _rtl8812ae_read_bt_coexist_info_from_hwpg(hw, rtlefuse->autoload_failflag, hwinfo); } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index aa3ccc740521..176deb2b5386 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -3773,10 +3773,11 @@ static void _rtl8821ae_iqk_tx(struct ieee80211_hw *hw, enum radio_path path) u32 tx_fail, rx_fail, delay_count, iqk_ready, cal_retry, cal = 0, temp_reg65; int tx_x = 0, tx_y = 0, rx_x = 0, rx_y = 0, tx_average = 0, rx_average = 0; int tx_x0[cal_num], tx_y0[cal_num], tx_x0_rxk[cal_num], - tx_y0_rxk[cal_num], rx_x0[cal_num], rx_y0[cal_num]; + tx_y0_rxk[cal_num], rx_x0[cal_num], rx_y0[cal_num], + tx_dt[cal_num], rx_dt[cal_num]; bool tx0iqkok = false, rx0iqkok = false; bool vdf_enable = false; - int i, k, vdf_y[3], vdf_x[3], tx_dt[3], rx_dt[3], + int i, k, vdf_y[3], vdf_x[3], ii, dx = 0, dy = 0, tx_finish = 0, rx_finish = 0; RT_TRACE(rtlpriv, COMP_IQK, DBG_LOUD, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index d71d2776ca03..0894ef48ab87 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -196,6 +196,8 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000); if (!rtlpriv->rtlhal.wowlan_firmware) { pr_err("Can't alloc buffer for wowlan fw.\n"); + vfree(rtlpriv->rtlhal.pfirmware); + rtlpriv->rtlhal.pfirmware = NULL; return 1; } @@ -214,16 +216,10 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { - /* Failed to get firmware. Check if old version available */ - fw_name = "rtlwifi/rtl8821aefw.bin"; - pr_info("Using firmware %s\n", fw_name); - err = request_firmware_nowait(THIS_MODULE, 1, fw_name, - rtlpriv->io.dev, GFP_KERNEL, hw, - rtl_fw_cb); - if (err) { - pr_err("Failed to request normal firmware!\n"); - return 1; - } + pr_err("Failed to request normal firmware!\n"); + vfree(rtlpriv->rtlhal.wowlan_firmware); + vfree(rtlpriv->rtlhal.pfirmware); + return 1; } /*load wowlan firmware*/ pr_info("Using firmware %s\n", wowlan_fw_name); @@ -233,6 +229,8 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw) rtl_wowlan_fw_cb); if (err) { pr_err("Failed to request wowlan firmware!\n"); + vfree(rtlpriv->rtlhal.wowlan_firmware); + vfree(rtlpriv->rtlhal.pfirmware); return 1; } return 0; @@ -325,6 +323,7 @@ static const struct rtl_hal_cfg rtl8821ae_hal_cfg = { .bar_id = 2, .write_readback = true, .name = "rtl8821ae_pci", + .alt_fw_name = "rtlwifi/rtl8821aefw.bin", .ops = &rtl8821ae_hal_ops, .mod_params = &rtl8821ae_mod_params, .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL, @@ -424,7 +423,7 @@ static const struct rtl_hal_cfg rtl8821ae_hal_cfg = { .maps[RTL_RC_VHT_RATE_2SS_MCS9] = DESC_RATEVHT2SS_MCS9, }; -static struct pci_device_id rtl8821ae_pci_ids[] = { +static const struct pci_device_id rtl8821ae_pci_ids[] = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8812, rtl8821ae_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8821, rtl8821ae_hal_cfg)}, {}, diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 70723e67b7d7..1ab1024330fb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -314,35 +314,29 @@ enum hardware_type { HARDWARE_TYPE_RTL8192EE, HARDWARE_TYPE_RTL8821AE, HARDWARE_TYPE_RTL8812AE, + HARDWARE_TYPE_RTL8822BE, /* keep it last */ HARDWARE_TYPE_NUM }; -#define IS_HARDWARE_TYPE_8192SU(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SU) -#define IS_HARDWARE_TYPE_8192SE(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) -#define IS_HARDWARE_TYPE_8192CE(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CE) -#define IS_HARDWARE_TYPE_8192CU(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU) -#define IS_HARDWARE_TYPE_8192DE(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) -#define IS_HARDWARE_TYPE_8192DU(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DU) -#define IS_HARDWARE_TYPE_8723E(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8723E) -#define IS_HARDWARE_TYPE_8723U(rtlhal) \ - (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) -#define IS_HARDWARE_TYPE_8192S(rtlhal) \ -(IS_HARDWARE_TYPE_8192SE(rtlhal) || IS_HARDWARE_TYPE_8192SU(rtlhal)) -#define IS_HARDWARE_TYPE_8192C(rtlhal) \ -(IS_HARDWARE_TYPE_8192CE(rtlhal) || IS_HARDWARE_TYPE_8192CU(rtlhal)) -#define IS_HARDWARE_TYPE_8192D(rtlhal) \ -(IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal)) -#define IS_HARDWARE_TYPE_8723(rtlhal) \ -(IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) +#define RTL_HW_TYPE(rtlpriv) (rtl_hal((struct rtl_priv *)rtlpriv)->hw_type) +#define IS_NEW_GENERATION_IC(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) >= HARDWARE_TYPE_RTL8192EE) +#define IS_HARDWARE_TYPE_8192CE(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8192CE) +#define IS_HARDWARE_TYPE_8812(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8812AE) +#define IS_HARDWARE_TYPE_8821(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8821AE) +#define IS_HARDWARE_TYPE_8723A(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8723AE) +#define IS_HARDWARE_TYPE_8723B(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8723BE) +#define IS_HARDWARE_TYPE_8192E(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8192EE) +#define IS_HARDWARE_TYPE_8822B(rtlpriv) \ + (RTL_HW_TYPE(rtlpriv) == HARDWARE_TYPE_RTL8822BE) #define RX_HAL_IS_CCK_RATE(rxmcs) \ ((rxmcs) == DESC_RATE1M || \ @@ -592,7 +586,7 @@ enum rtl_hal_state { _HAL_STATE_START = 1, }; -enum rtl_desc92_rate { +enum rtl_desc_rate { DESC_RATE1M = 0x00, DESC_RATE2M = 0x01, DESC_RATE5_5M = 0x02, @@ -2477,6 +2471,8 @@ struct rtl_global_var { spinlock_t glb_list_lock; }; +#define IN_4WAY_TIMEOUT_TIME (30 * MSEC_PER_SEC) /* 30 seconds */ + struct rtl_btc_info { u8 bt_type; u8 btcoexist; @@ -2485,6 +2481,7 @@ struct rtl_btc_info { u8 ap_num; bool in_4way; + unsigned long in_4way_ts; }; struct bt_coexist_info { @@ -2558,6 +2555,8 @@ struct rtl_btc_ops { void (*btc_halt_notify) (void); void (*btc_btinfo_notify) (struct rtl_priv *rtlpriv, u8 *tmp_buf, u8 length); + void (*btc_btmpinfo_notify)(struct rtl_priv *rtlpriv, + u8 *tmp_buf, u8 length); bool (*btc_is_limited_dig) (struct rtl_priv *rtlpriv); bool (*btc_is_disable_edca_turbo) (struct rtl_priv *rtlpriv); bool (*btc_is_bt_disabled) (struct rtl_priv *rtlpriv); diff --git a/drivers/net/wireless/rsi/Makefile b/drivers/net/wireless/rsi/Makefile index a475c813674a..ebb89965997a 100644 --- a/drivers/net/wireless/rsi/Makefile +++ b/drivers/net/wireless/rsi/Makefile @@ -3,6 +3,7 @@ rsi_91x-y += rsi_91x_core.o rsi_91x-y += rsi_91x_mac80211.o rsi_91x-y += rsi_91x_mgmt.o rsi_91x-y += rsi_91x_hal.o +rsi_91x-y += rsi_91x_ps.o rsi_91x-$(CONFIG_RSI_DEBUGFS) += rsi_91x_debugfs.o rsi_usb-y += rsi_91x_usb.o rsi_91x_usb_ops.o diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 68f04a76769e..2b0516d2f63d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -16,6 +16,7 @@ #include "rsi_mgmt.h" #include "rsi_common.h" +#include "rsi_hal.h" /** * rsi_determine_min_weight_queue() - This function determines the queue with @@ -136,6 +137,10 @@ static u8 rsi_core_determine_hal_queue(struct rsi_common *common) u8 q_num = INVALID_QUEUE; u8 ii = 0; + if (skb_queue_len(&common->tx_queue[MGMT_BEACON_Q])) { + q_num = MGMT_BEACON_Q; + return q_num; + } if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { if (!common->mgmt_q_block) q_num = MGMT_SOFT_Q; @@ -268,11 +273,11 @@ void rsi_core_qos_processor(struct rsi_common *common) break; } - mutex_lock(&common->tx_rxlock); + mutex_lock(&common->tx_lock); status = adapter->check_hw_queue_status(adapter, q_num); if ((status <= 0)) { - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); break; } @@ -287,30 +292,48 @@ void rsi_core_qos_processor(struct rsi_common *common) skb = rsi_core_dequeue_pkt(common, q_num); if (skb == NULL) { rsi_dbg(ERR_ZONE, "skb null\n"); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); break; } - if (q_num == MGMT_SOFT_Q) + if (q_num == MGMT_SOFT_Q) { status = rsi_send_mgmt_pkt(common, skb); - else + } else if (q_num == MGMT_BEACON_Q) { + status = rsi_send_pkt_to_bus(common, skb); + dev_kfree_skb(skb); + } else { status = rsi_send_data_pkt(common, skb); + } if (status) { - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); break; } common->tx_stats.total_tx_pkt_send[q_num]++; tstamp_2 = jiffies; - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->tx_lock); if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) schedule(); } } +struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr) +{ + int i; + + for (i = 0; i < common->max_stations; i++) { + if (!common->stations[i].sta) + continue; + if (!(memcmp(common->stations[i].sta->addr, + mac_addr, ETH_ALEN))) + return &common->stations[i]; + } + return NULL; +} + /** * rsi_core_xmit() - This function transmits the packets received from mac80211 * @common: Pointer to the driver private structure. @@ -323,42 +346,63 @@ void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; struct skb_info *tx_params; - struct ieee80211_hdr *tmp_hdr = NULL; + struct ieee80211_hdr *wh; + struct ieee80211_vif *vif = adapter->vifs[0]; u8 q_num, tid = 0; + struct rsi_sta *rsta = NULL; if ((!skb) || (!skb->len)) { rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", __func__); goto xmit_fail; } - info = IEEE80211_SKB_CB(skb); - tx_params = (struct skb_info *)info->driver_data; - tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; - if (common->fsm_state != FSM_MAC_INIT_DONE) { rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); goto xmit_fail; } - if ((ieee80211_is_mgmt(tmp_hdr->frame_control)) || - (ieee80211_is_ctl(tmp_hdr->frame_control)) || - (ieee80211_is_qos_nullfunc(tmp_hdr->frame_control))) { + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + wh = (struct ieee80211_hdr *)&skb->data[0]; + tx_params->sta_id = 0; + + if ((ieee80211_is_mgmt(wh->frame_control)) || + (ieee80211_is_ctl(wh->frame_control)) || + (ieee80211_is_qos_nullfunc(wh->frame_control))) { q_num = MGMT_SOFT_Q; skb->priority = q_num; } else { - if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { + if (ieee80211_is_data_qos(wh->frame_control)) { tid = (skb->data[24] & IEEE80211_QOS_TID); skb->priority = TID_TO_WME_AC(tid); } else { tid = IEEE80211_NONQOS_TID; skb->priority = BE_Q; } + q_num = skb->priority; tx_params->tid = tid; - tx_params->sta_id = 0; + + if ((vif->type == NL80211_IFTYPE_AP) && + (!is_broadcast_ether_addr(wh->addr1)) && + (!is_multicast_ether_addr(wh->addr1))) { + rsta = rsi_find_sta(common, wh->addr1); + if (!rsta) + goto xmit_fail; + tx_params->sta_id = rsta->sta_id; + } + + if (rsta) { + /* Start aggregation if not done for this tid */ + if (!rsta->start_tx_aggr[tid]) { + rsta->start_tx_aggr[tid] = true; + ieee80211_start_tx_ba_session(rsta->sta, + tid, 0); + } + } } - if ((q_num != MGMT_SOFT_Q) && + if ((q_num < MGMT_SOFT_Q) && ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= DATA_QUEUE_WATER_MARK)) { rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); diff --git a/drivers/net/wireless/rsi/rsi_91x_debugfs.c b/drivers/net/wireless/rsi/rsi_91x_debugfs.c index 4c0a493bd44e..e98eb55c26cc 100644 --- a/drivers/net/wireless/rsi/rsi_91x_debugfs.c +++ b/drivers/net/wireless/rsi/rsi_91x_debugfs.c @@ -130,6 +130,7 @@ static int rsi_stats_read(struct seq_file *seq, void *data) "FSM_COMMON_DEV_PARAMS_SENT", "FSM_BOOT_PARAMS_SENT", "FSM_EEPROM_READ_MAC_ADDR", + "FSM_EEPROM_READ_RF_TYPE", "FSM_RESET_MAC_SENT", "FSM_RADIO_CAPS_SENT", "FSM_BB_RF_PROG_SENT", @@ -138,6 +139,8 @@ static int rsi_stats_read(struct seq_file *seq, void *data) seq_puts(seq, "==> RSI STA DRIVER STATUS <==\n"); seq_puts(seq, "DRIVER_FSM_STATE: "); + BUILD_BUG_ON(ARRAY_SIZE(fsm_state) != NUM_FSM_STATES); + if (common->fsm_state <= FSM_MAC_INIT_DONE) seq_printf(seq, "%s", fsm_state[common->fsm_state]); diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index c2303599c12e..070dfd68bb83 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -18,6 +18,7 @@ #include "rsi_mgmt.h" #include "rsi_hal.h" #include "rsi_sdio.h" +#include "rsi_common.h" /* FLASH Firmware */ static struct ta_metadata metadata_flash_content[] = { @@ -25,99 +26,268 @@ static struct ta_metadata metadata_flash_content[] = { {"rsi/rs9113_wlan_qspi.rps", 0x00010000}, }; -/** - * rsi_send_data_pkt() - This function sends the recieved data packet from - * driver to device. - * @common: Pointer to the driver private structure. - * @skb: Pointer to the socket buffer structure. - * - * Return: status: 0 on success, -1 on failure. - */ -int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) +int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + int status; + + status = adapter->host_intf_ops->write_pkt(common->priv, + skb->data, skb->len); + return status; +} + +static int rsi_prepare_mgmt_desc(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *tmp_hdr; + struct ieee80211_hdr *wh = NULL; + struct ieee80211_tx_info *info; + struct ieee80211_conf *conf = &adapter->hw->conf; + struct ieee80211_vif *vif = adapter->vifs[0]; + struct rsi_mgmt_desc *mgmt_desc; + struct skb_info *tx_params; + struct ieee80211_bss_conf *bss = NULL; + struct xtended_desc *xtend_desc = NULL; + u8 header_size; + u32 dword_align_bytes = 0; + + if (skb->len > MAX_MGMT_PKT_SIZE) { + rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); + return -EINVAL; + } + + info = IEEE80211_SKB_CB(skb); + tx_params = (struct skb_info *)info->driver_data; + + /* Update header size */ + header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); + if (header_size > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to add extended descriptor\n", + __func__); + return -ENOSPC; + } + skb_push(skb, header_size); + dword_align_bytes = ((unsigned long)skb->data & 0x3f); + if (dword_align_bytes > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to add dword align\n", __func__); + return -ENOSPC; + } + skb_push(skb, dword_align_bytes); + header_size += dword_align_bytes; + + tx_params->internal_hdr_size = header_size; + memset(&skb->data[0], 0, header_size); + bss = &info->control.vif->bss_conf; + wh = (struct ieee80211_hdr *)&skb->data[header_size]; + + mgmt_desc = (struct rsi_mgmt_desc *)skb->data; + xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ]; + + rsi_set_len_qno(&mgmt_desc->len_qno, (skb->len - FRAME_DESC_SZ), + RSI_WIFI_MGMT_Q); + mgmt_desc->frame_type = TX_DOT11_MGMT; + mgmt_desc->header_len = MIN_802_11_HDR_LEN; + mgmt_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; + mgmt_desc->frame_info |= cpu_to_le16(RATE_INFO_ENABLE); + if (is_broadcast_ether_addr(wh->addr1)) + mgmt_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); + + mgmt_desc->seq_ctrl = + cpu_to_le16(IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl))); + if (common->band == NL80211_BAND_2GHZ) + mgmt_desc->rate_info = RSI_RATE_1; + else + mgmt_desc->rate_info = RSI_RATE_6; + + if (conf_is_ht40(conf)) + mgmt_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); + + if (ieee80211_is_probe_req(wh->frame_control)) { + if (!bss->assoc) { + rsi_dbg(INFO_ZONE, + "%s: blocking mgmt queue\n", __func__); + mgmt_desc->misc_flags = RSI_DESC_REQUIRE_CFM_TO_HOST; + xtend_desc->confirm_frame_type = PROBEREQ_CONFIRM; + common->mgmt_q_block = true; + rsi_dbg(INFO_ZONE, "Mgmt queue blocked\n"); + } + } + + if (ieee80211_is_probe_resp(wh->frame_control)) { + mgmt_desc->misc_flags |= (RSI_ADD_DELTA_TSF_VAP_ID | + RSI_FETCH_RETRY_CNT_FRM_HST); +#define PROBE_RESP_RETRY_CNT 3 + xtend_desc->retry_cnt = PROBE_RESP_RETRY_CNT; + } + + if ((vif->type == NL80211_IFTYPE_AP) && + (ieee80211_is_action(wh->frame_control))) { + struct rsi_sta *rsta = rsi_find_sta(common, wh->addr1); + + if (rsta) + mgmt_desc->sta_id = tx_params->sta_id; + else + return -EINVAL; + } + return 0; +} + +/* This function prepares descriptor for given data packet */ +static int rsi_prepare_data_desc(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_vif *vif; + struct ieee80211_hdr *wh = NULL; struct ieee80211_tx_info *info; struct skb_info *tx_params; struct ieee80211_bss_conf *bss; - int status; + struct rsi_data_desc *data_desc; + struct xtended_desc *xtend_desc; u8 ieee80211_size = MIN_802_11_HDR_LEN; - u8 extnd_size; - __le16 *frame_desc; + u8 header_size; + u8 vap_id = 0; + u8 dword_align_bytes; u16 seq_num; info = IEEE80211_SKB_CB(skb); bss = &info->control.vif->bss_conf; tx_params = (struct skb_info *)info->driver_data; - if (!bss->assoc) { - status = -EINVAL; - goto err; + header_size = FRAME_DESC_SZ + sizeof(struct xtended_desc); + if (header_size > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); + return -ENOSPC; } + skb_push(skb, header_size); + dword_align_bytes = ((unsigned long)skb->data & 0x3f); + if (header_size > skb_headroom(skb)) { + rsi_dbg(ERR_ZONE, "%s: Not enough headroom\n", __func__); + return -ENOSPC; + } + skb_push(skb, dword_align_bytes); + header_size += dword_align_bytes; - tmp_hdr = (struct ieee80211_hdr *)&skb->data[0]; - seq_num = (le16_to_cpu(tmp_hdr->seq_ctrl) >> 4); + tx_params->internal_hdr_size = header_size; + data_desc = (struct rsi_data_desc *)skb->data; + memset(data_desc, 0, header_size); - extnd_size = ((uintptr_t)skb->data & 0x3); + xtend_desc = (struct xtended_desc *)&skb->data[FRAME_DESC_SZ]; + wh = (struct ieee80211_hdr *)&skb->data[header_size]; + seq_num = IEEE80211_SEQ_TO_SN(le16_to_cpu(wh->seq_ctrl)); + vif = adapter->vifs[0]; - if ((FRAME_DESC_SZ + extnd_size) > skb_headroom(skb)) { - rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); - status = -ENOSPC; - goto err; - } + data_desc->xtend_desc_size = header_size - FRAME_DESC_SZ; - skb_push(skb, (FRAME_DESC_SZ + extnd_size)); - frame_desc = (__le16 *)&skb->data[0]; - memset((u8 *)frame_desc, 0, FRAME_DESC_SZ); - - if (ieee80211_is_data_qos(tmp_hdr->frame_control)) { + if (ieee80211_is_data_qos(wh->frame_control)) { ieee80211_size += 2; - frame_desc[6] |= cpu_to_le16(BIT(12)); + data_desc->mac_flags |= cpu_to_le16(RSI_QOS_ENABLE); } + if ((vif->type == NL80211_IFTYPE_STATION) && + (adapter->ps_state == PS_ENABLED)) + wh->frame_control |= cpu_to_le16(RSI_SET_PS_ENABLE); + if ((!(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) && (common->secinfo.security_enable)) { if (rsi_is_cipher_wep(common)) ieee80211_size += 4; else ieee80211_size += 8; - frame_desc[6] |= cpu_to_le16(BIT(15)); + data_desc->mac_flags |= cpu_to_le16(RSI_ENCRYPT_PKT); } + rsi_set_len_qno(&data_desc->len_qno, (skb->len - FRAME_DESC_SZ), + RSI_WIFI_DATA_Q); + data_desc->header_len = ieee80211_size; - frame_desc[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | - (RSI_WIFI_DATA_Q << 12)); - frame_desc[2] = cpu_to_le16((extnd_size) | (ieee80211_size) << 8); - - if (common->min_rate != 0xffff) { + if (common->min_rate != RSI_RATE_AUTO) { /* Send fixed rate */ - frame_desc[3] = cpu_to_le16(RATE_INFO_ENABLE); - frame_desc[4] = cpu_to_le16(common->min_rate); + data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); + data_desc->rate_info = cpu_to_le16(common->min_rate); if (conf_is_ht40(&common->priv->hw->conf)) - frame_desc[5] = cpu_to_le16(FULL40M_ENABLE); + data_desc->bbp_info = cpu_to_le16(FULL40M_ENABLE); - if (common->vif_info[0].sgi) { - if (common->min_rate & 0x100) /* Only MCS rates */ - frame_desc[4] |= - cpu_to_le16(ENABLE_SHORTGI_RATE); + if ((common->vif_info[0].sgi) && (common->min_rate & 0x100)) { + /* Only MCS rates */ + data_desc->rate_info |= + cpu_to_le16(ENABLE_SHORTGI_RATE); } + } + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { + rsi_dbg(INFO_ZONE, "*** Tx EAPOL ***\n"); + + data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); + if (common->band == NL80211_BAND_5GHZ) + data_desc->rate_info = cpu_to_le16(RSI_RATE_6); + else + data_desc->rate_info = cpu_to_le16(RSI_RATE_1); + data_desc->mac_flags |= cpu_to_le16(RSI_REKEY_PURPOSE); + data_desc->misc_flags |= RSI_FETCH_RETRY_CNT_FRM_HST; +#define EAPOL_RETRY_CNT 15 + xtend_desc->retry_cnt = EAPOL_RETRY_CNT; + } + + data_desc->mac_flags = cpu_to_le16(seq_num & 0xfff); + data_desc->qid_tid = ((skb->priority & 0xf) | + ((tx_params->tid & 0xf) << 4)); + data_desc->sta_id = tx_params->sta_id; + + if ((is_broadcast_ether_addr(wh->addr1)) || + (is_multicast_ether_addr(wh->addr1))) { + data_desc->frame_info = cpu_to_le16(RATE_INFO_ENABLE); + data_desc->frame_info |= cpu_to_le16(RSI_BROADCAST_PKT); + data_desc->sta_id = vap_id; + + if (vif->type == NL80211_IFTYPE_AP) { + if (common->band == NL80211_BAND_5GHZ) + data_desc->rate_info = cpu_to_le16(RSI_RATE_6); + else + data_desc->rate_info = cpu_to_le16(RSI_RATE_1); + } } + if ((vif->type == NL80211_IFTYPE_AP) && + (ieee80211_has_moredata(wh->frame_control))) + data_desc->frame_info |= cpu_to_le16(MORE_DATA_PRESENT); + + return 0; +} + +/* This function sends received data packet from driver to device */ +int rsi_send_data_pkt(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = common->priv; + struct ieee80211_vif *vif = adapter->vifs[0]; + struct ieee80211_tx_info *info; + struct ieee80211_bss_conf *bss; + int status = -EINVAL; + + if (!skb) + return 0; + if (common->iface_down) + goto err; - frame_desc[6] |= cpu_to_le16(seq_num & 0xfff); - frame_desc[7] = cpu_to_le16(((tx_params->tid & 0xf) << 4) | - (skb->priority & 0xf) | - (tx_params->sta_id << 8)); + info = IEEE80211_SKB_CB(skb); + if (!info->control.vif) + goto err; + bss = &info->control.vif->bss_conf; + + if ((vif->type == NL80211_IFTYPE_STATION) && (!bss->assoc)) + goto err; + + status = rsi_prepare_data_desc(common, skb); + if (status) + goto err; status = adapter->host_intf_ops->write_pkt(common->priv, skb->data, skb->len); if (status) - rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", - __func__); + rsi_dbg(ERR_ZONE, "%s: Failed to write pkt\n", __func__); err: ++common->tx_stats.total_tx_pkt_freed[skb->priority]; - rsi_indicate_tx_status(common->priv, skb, status); + rsi_indicate_tx_status(adapter, skb, status); return status; } @@ -133,22 +303,17 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, struct sk_buff *skb) { struct rsi_hw *adapter = common->priv; - struct ieee80211_hdr *wh; struct ieee80211_tx_info *info; - struct ieee80211_bss_conf *bss; - struct ieee80211_hw *hw = adapter->hw; - struct ieee80211_conf *conf = &hw->conf; struct skb_info *tx_params; int status = -E2BIG; - __le16 *msg; u8 extnd_size; - u8 vap_id = 0; info = IEEE80211_SKB_CB(skb); tx_params = (struct skb_info *)info->driver_data; extnd_size = ((uintptr_t)skb->data & 0x3); if (tx_params->flags & INTERNAL_MGMT_PKT) { + skb->data[1] |= BIT(7); /* Immediate Wakeup bit*/ if ((extnd_size) > skb_headroom(skb)) { rsi_dbg(ERR_ZONE, "%s: Unable to send pkt\n", __func__); dev_kfree_skb(skb); @@ -167,58 +332,73 @@ int rsi_send_mgmt_pkt(struct rsi_common *common, return status; } - bss = &info->control.vif->bss_conf; - wh = (struct ieee80211_hdr *)&skb->data[0]; - if (FRAME_DESC_SZ > skb_headroom(skb)) goto err; - skb_push(skb, FRAME_DESC_SZ); - memset(skb->data, 0, FRAME_DESC_SZ); - msg = (__le16 *)skb->data; + rsi_prepare_mgmt_desc(common, skb); + status = adapter->host_intf_ops->write_pkt(common->priv, + (u8 *)skb->data, skb->len); + if (status) + rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); - if (skb->len > MAX_MGMT_PKT_SIZE) { - rsi_dbg(INFO_ZONE, "%s: Dropping mgmt pkt > 512\n", __func__); - goto err; +err: + rsi_indicate_tx_status(common->priv, skb, status); + return status; +} + +int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb) +{ + struct rsi_hw *adapter = (struct rsi_hw *)common->priv; + struct rsi_data_desc *bcn_frm; + struct ieee80211_hw *hw = common->priv->hw; + struct ieee80211_conf *conf = &hw->conf; + struct sk_buff *mac_bcn; + u8 vap_id = 0; + u16 tim_offset; + + mac_bcn = ieee80211_beacon_get_tim(adapter->hw, + adapter->vifs[adapter->sc_nvifs - 1], + &tim_offset, NULL); + if (!mac_bcn) { + rsi_dbg(ERR_ZONE, "Failed to get beacon from mac80211\n"); + return -EINVAL; } - msg[0] = cpu_to_le16((skb->len - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - msg[1] = cpu_to_le16(TX_DOT11_MGMT); - msg[2] = cpu_to_le16(MIN_802_11_HDR_LEN << 8); - msg[3] = cpu_to_le16(RATE_INFO_ENABLE); - msg[6] = cpu_to_le16(le16_to_cpu(wh->seq_ctrl) >> 4); + common->beacon_cnt++; + bcn_frm = (struct rsi_data_desc *)skb->data; + rsi_set_len_qno(&bcn_frm->len_qno, mac_bcn->len, RSI_WIFI_DATA_Q); + bcn_frm->header_len = MIN_802_11_HDR_LEN; + bcn_frm->frame_info = cpu_to_le16(RSI_DATA_DESC_MAC_BBP_INFO | + RSI_DATA_DESC_NO_ACK_IND | + RSI_DATA_DESC_BEACON_FRAME | + RSI_DATA_DESC_INSERT_TSF | + RSI_DATA_DESC_INSERT_SEQ_NO | + RATE_INFO_ENABLE); + bcn_frm->rate_info = cpu_to_le16(vap_id << 14); + bcn_frm->qid_tid = BEACON_HW_Q; - if (wh->addr1[0] & BIT(0)) - msg[3] |= cpu_to_le16(RSI_BROADCAST_PKT); + if (conf_is_ht40_plus(conf)) { + bcn_frm->bbp_info = cpu_to_le16(LOWER_20_ENABLE); + bcn_frm->bbp_info |= cpu_to_le16(LOWER_20_ENABLE >> 12); + } else if (conf_is_ht40_minus(conf)) { + bcn_frm->bbp_info = cpu_to_le16(UPPER_20_ENABLE); + bcn_frm->bbp_info |= cpu_to_le16(UPPER_20_ENABLE >> 12); + } if (common->band == NL80211_BAND_2GHZ) - msg[4] = cpu_to_le16(RSI_11B_MODE); + bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_1); else - msg[4] = cpu_to_le16((RSI_RATE_6 & 0x0f) | RSI_11G_MODE); + bcn_frm->bbp_info |= cpu_to_le16(RSI_RATE_6); - if (conf_is_ht40(conf)) { - msg[4] = cpu_to_le16(0xB | RSI_11G_MODE); - msg[5] = cpu_to_le16(0x6); - } + if (mac_bcn->data[tim_offset + 2] == 0) + bcn_frm->frame_info |= cpu_to_le16(RSI_DATA_DESC_DTIM_BEACON); - /* Indicate to firmware to give cfm */ - if ((skb->data[16] == IEEE80211_STYPE_PROBE_REQ) && (!bss->assoc)) { - msg[1] |= cpu_to_le16(BIT(10)); - msg[7] = cpu_to_le16(PROBEREQ_CONFIRM); - common->mgmt_q_block = true; - } + memcpy(&skb->data[FRAME_DESC_SZ], mac_bcn->data, mac_bcn->len); + skb_put(skb, mac_bcn->len + FRAME_DESC_SZ); - msg[7] |= cpu_to_le16(vap_id << 8); + dev_kfree_skb(mac_bcn); - status = adapter->host_intf_ops->write_pkt(common->priv, (u8 *)msg, - skb->len); - if (status) - rsi_dbg(ERR_ZONE, "%s: Failed to write the packet\n", __func__); - -err: - rsi_indicate_tx_status(common->priv, skb, status); - return status; + return 0; } static void bl_cmd_timeout(unsigned long priv) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 021e5ac5f107..fa12c05d9e23 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -18,6 +18,7 @@ #include "rsi_debugfs.h" #include "rsi_mgmt.h" #include "rsi_common.h" +#include "rsi_ps.h" static const struct ieee80211_channel rsi_2ghz_channels[] = { { .band = NL80211_BAND_2GHZ, .center_freq = 2412, @@ -121,6 +122,23 @@ const u16 rsi_mcsrates[8] = { RSI_RATE_MCS4, RSI_RATE_MCS5, RSI_RATE_MCS6, RSI_RATE_MCS7 }; +static const u32 rsi_max_ap_stas[16] = { + 32, /* 1 - Wi-Fi alone */ + 0, /* 2 */ + 0, /* 3 */ + 0, /* 4 - BT EDR alone */ + 4, /* 5 - STA + BT EDR */ + 32, /* 6 - AP + BT EDR */ + 0, /* 7 */ + 0, /* 8 - BT LE alone */ + 4, /* 9 - STA + BE LE */ + 0, /* 10 */ + 0, /* 11 */ + 0, /* 12 */ + 1, /* 13 - STA + BT Dual */ + 4, /* 14 - AP + BT Dual */ +}; + /** * rsi_is_cipher_wep() - This function determines if the cipher is WEP or not. * @common: Pointer to the driver private structure. @@ -229,12 +247,20 @@ void rsi_indicate_tx_status(struct rsi_hw *adapter, int status) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct skb_info *tx_params; - memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + if (!adapter->hw) { + rsi_dbg(ERR_ZONE, "##### No MAC #####\n"); + return; + } if (!status) info->flags |= IEEE80211_TX_STAT_ACK; + tx_params = (struct skb_info *)info->driver_data; + skb_pull(skb, tx_params->internal_hdr_size); + memset(info->driver_data, 0, IEEE80211_TX_INFO_DRIVER_DATA_SIZE); + ieee80211_tx_status_irqsafe(adapter->hw, skb); } @@ -271,11 +297,12 @@ static int rsi_mac80211_start(struct ieee80211_hw *hw) struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + rsi_dbg(ERR_ZONE, "===> Interface UP <===\n"); mutex_lock(&common->mutex); common->iface_down = false; - mutex_unlock(&common->mutex); - + wiphy_rfkill_start_polling(hw->wiphy); rsi_send_rx_filter_frame(common, 0); + mutex_unlock(&common->mutex); return 0; } @@ -291,8 +318,14 @@ static void rsi_mac80211_stop(struct ieee80211_hw *hw) struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + rsi_dbg(ERR_ZONE, "===> Interface DOWN <===\n"); mutex_lock(&common->mutex); common->iface_down = true; + wiphy_rfkill_stop_polling(hw->wiphy); + + /* Block all rx frames */ + rsi_send_rx_filter_frame(common, 0xffff); + mutex_unlock(&common->mutex); } @@ -309,24 +342,51 @@ static int rsi_mac80211_add_interface(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + enum opmode intf_mode; int ret = -EOPNOTSUPP; + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; mutex_lock(&common->mutex); + + if (adapter->sc_nvifs > 1) { + mutex_unlock(&common->mutex); + return -EOPNOTSUPP; + } + switch (vif->type) { case NL80211_IFTYPE_STATION: - if (!adapter->sc_nvifs) { - ++adapter->sc_nvifs; - adapter->vifs[0] = vif; - ret = rsi_set_vap_capabilities(common, - STA_OPMODE, - VAP_ADD); - } + rsi_dbg(INFO_ZONE, "Station Mode"); + intf_mode = STA_OPMODE; + break; + case NL80211_IFTYPE_AP: + rsi_dbg(INFO_ZONE, "AP Mode"); + intf_mode = AP_OPMODE; break; default: rsi_dbg(ERR_ZONE, "%s: Interface type %d not supported\n", __func__, vif->type); + goto out; + } + + adapter->vifs[adapter->sc_nvifs++] = vif; + ret = rsi_set_vap_capabilities(common, intf_mode, common->mac_addr, + 0, VAP_ADD); + if (ret) { + rsi_dbg(ERR_ZONE, "Failed to set VAP capabilities\n"); + goto out; + } + + if (vif->type == NL80211_IFTYPE_AP) { + int i; + + rsi_send_rx_filter_frame(common, DISALLOW_BEACONS); + common->min_rate = RSI_RATE_AUTO; + for (i = 0; i < common->max_stations; i++) + common->stations[i].sta = NULL; } + +out: mutex_unlock(&common->mutex); return ret; @@ -345,13 +405,32 @@ static void rsi_mac80211_remove_interface(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + enum opmode opmode; + + rsi_dbg(INFO_ZONE, "Remove Interface Called\n"); mutex_lock(&common->mutex); - if (vif->type == NL80211_IFTYPE_STATION) { - adapter->sc_nvifs--; - rsi_set_vap_capabilities(common, STA_OPMODE, VAP_DELETE); + + if (adapter->sc_nvifs <= 0) { + mutex_unlock(&common->mutex); + return; } + switch (vif->type) { + case NL80211_IFTYPE_STATION: + opmode = STA_OPMODE; + break; + case NL80211_IFTYPE_AP: + opmode = AP_OPMODE; + break; + default: + mutex_unlock(&common->mutex); + return; + } + rsi_set_vap_capabilities(common, opmode, vif->addr, + 0, VAP_DELETE); + adapter->sc_nvifs--; + if (!memcmp(adapter->vifs[0], vif, sizeof(struct ieee80211_vif))) adapter->vifs[0] = NULL; mutex_unlock(&common->mutex); @@ -452,6 +531,8 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + struct ieee80211_vif *vif = adapter->vifs[0]; + struct ieee80211_conf *conf = &hw->conf; int status = -EOPNOTSUPP; mutex_lock(&common->mutex); @@ -465,6 +546,28 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw, status = rsi_config_power(hw); } + /* Power save parameters */ + if ((changed & IEEE80211_CONF_CHANGE_PS) && + (vif->type == NL80211_IFTYPE_STATION)) { + unsigned long flags; + + spin_lock_irqsave(&adapter->ps_lock, flags); + if (conf->flags & IEEE80211_CONF_PS) + rsi_enable_ps(adapter); + else + rsi_disable_ps(adapter); + spin_unlock_irqrestore(&adapter->ps_lock, flags); + } + + /* RTS threshold */ + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + rsi_dbg(INFO_ZONE, "RTS threshold\n"); + if ((common->rts_threshold) <= IEEE80211_MAX_RTS_THRESHOLD) { + rsi_dbg(INFO_ZONE, + "%s: Sending vap updates....\n", __func__); + status = rsi_send_vap_dynamic_update(common); + } + } mutex_unlock(&common->mutex); return status; @@ -507,6 +610,8 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + struct ieee80211_bss_conf *bss = &vif->bss_conf; + struct ieee80211_conf *conf = &hw->conf; u16 rx_filter_word = 0; mutex_lock(&common->mutex); @@ -521,10 +626,24 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, rsi_send_rx_filter_frame(common, rx_filter_word); } rsi_inform_bss_status(common, + STA_OPMODE, bss_conf->assoc, bss_conf->bssid, bss_conf->qos, - bss_conf->aid); + bss_conf->aid, + NULL, 0); + adapter->ps_info.dtim_interval_duration = bss->dtim_period; + adapter->ps_info.listen_interval = conf->listen_interval; + + /* If U-APSD is updated, send ps parameters to firmware */ + if (bss->assoc) { + if (common->uapsd_bitmap) { + rsi_dbg(INFO_ZONE, "Configuring UAPSD\n"); + rsi_conf_uapsd(adapter); + } + } else { + common->uapsd_bitmap = 0; + } } if (changed & BSS_CHANGED_CQM) { @@ -535,6 +654,18 @@ static void rsi_mac80211_bss_info_changed(struct ieee80211_hw *hw, common->cqm_info.rssi_thold, common->cqm_info.rssi_hyst); } + + if ((changed & BSS_CHANGED_BEACON_ENABLED) && + (vif->type == NL80211_IFTYPE_AP)) { + if (bss->enable_beacon) { + rsi_dbg(INFO_ZONE, "===> BEACON ENABLED <===\n"); + common->beacon_enabled = 1; + } else { + rsi_dbg(INFO_ZONE, "===> BEACON DISABLED <===\n"); + common->beacon_enabled = 0; + } + } + mutex_unlock(&common->mutex); } @@ -606,6 +737,12 @@ static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, memcpy(&common->edca_params[idx], params, sizeof(struct ieee80211_tx_queue_params)); + + if (params->uapsd) + common->uapsd_bitmap |= idx; + else + common->uapsd_bitmap &= (~idx); + mutex_unlock(&common->mutex); return 0; @@ -617,15 +754,18 @@ static int rsi_mac80211_conf_tx(struct ieee80211_hw *hw, * @vif: Pointer to the ieee80211_vif structure. * @key: Pointer to the ieee80211_key_conf structure. * - * Return: status: 0 on success, -1 on failure. + * Return: status: 0 on success, negative error codes on failure. */ static int rsi_hal_key_config(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_key_conf *key) + struct ieee80211_key_conf *key, + struct ieee80211_sta *sta) { struct rsi_hw *adapter = hw->priv; + struct rsi_sta *rsta = NULL; int status; u8 key_type; + s16 sta_id = 0; if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) key_type = RSI_PAIRWISE_KEY; @@ -635,23 +775,35 @@ static int rsi_hal_key_config(struct ieee80211_hw *hw, rsi_dbg(ERR_ZONE, "%s: Cipher 0x%x key_type: %d key_len: %d\n", __func__, key->cipher, key_type, key->keylen); - if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || - (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { - status = rsi_hal_load_key(adapter->priv, - key->key, - key->keylen, - RSI_PAIRWISE_KEY, - key->keyidx, - key->cipher); - if (status) - return status; + if (vif->type == NL80211_IFTYPE_AP) { + if (sta) { + rsta = rsi_find_sta(adapter->priv, sta->addr); + if (rsta) + sta_id = rsta->sta_id; + } + adapter->priv->key = key; + } else { + if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || + (key->cipher == WLAN_CIPHER_SUITE_WEP40)) { + status = rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + RSI_PAIRWISE_KEY, + key->keyidx, + key->cipher, + sta_id); + if (status) + return status; + } } + return rsi_hal_load_key(adapter->priv, key->key, key->keylen, key_type, key->keyidx, - key->cipher); + key->cipher, + sta_id); } /** @@ -679,7 +831,7 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, switch (cmd) { case SET_KEY: secinfo->security_enable = true; - status = rsi_hal_key_config(hw, vif, key); + status = rsi_hal_key_config(hw, vif, key, sta); if (status) { mutex_unlock(&common->mutex); return status; @@ -697,10 +849,11 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw, break; case DISABLE_KEY: - secinfo->security_enable = false; + if (vif->type == NL80211_IFTYPE_STATION) + secinfo->security_enable = false; rsi_dbg(ERR_ZONE, "%s: RSI del key\n", __func__); memset(key, 0, sizeof(struct ieee80211_key_conf)); - status = rsi_hal_key_config(hw, vif, key); + status = rsi_hal_key_config(hw, vif, key, sta); break; default: @@ -729,9 +882,11 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, int status = -EOPNOTSUPP; struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; - u16 seq_no = 0; + struct rsi_sta *rsta = NULL; + u16 seq_no = 0, seq_start = 0; u8 ii = 0; struct ieee80211_sta *sta = params->sta; + u8 sta_id = 0; enum ieee80211_ampdu_mlme_action action = params->action; u16 tid = params->tid; u16 *ssn = ¶ms->ssn; @@ -743,17 +898,32 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, } mutex_lock(&common->mutex); - rsi_dbg(INFO_ZONE, "%s: AMPDU action %d called\n", __func__, action); + if (ssn != NULL) seq_no = *ssn; + if (vif->type == NL80211_IFTYPE_AP) { + rsta = rsi_find_sta(common, sta->addr); + if (!rsta) { + rsi_dbg(ERR_ZONE, "No station mapped\n"); + status = 0; + goto unlock; + } + sta_id = rsta->sta_id; + } + + rsi_dbg(INFO_ZONE, + "%s: AMPDU action tid=%d ssn=0x%x, buf_size=%d sta_id=%d\n", + __func__, tid, seq_no, buf_size, sta_id); + switch (action) { case IEEE80211_AMPDU_RX_START: status = rsi_send_aggregation_params_frame(common, tid, seq_no, buf_size, - STA_RX_ADDBA_DONE); + STA_RX_ADDBA_DONE, + sta_id); break; case IEEE80211_AMPDU_RX_STOP: @@ -761,11 +931,15 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, tid, 0, buf_size, - STA_RX_DELBA); + STA_RX_DELBA, + sta_id); break; case IEEE80211_AMPDU_TX_START: - common->vif_info[ii].seq_start = seq_no; + if (vif->type == NL80211_IFTYPE_STATION) + common->vif_info[ii].seq_start = seq_no; + else if (vif->type == NL80211_IFTYPE_AP) + rsta->seq_start[tid] = seq_no; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); status = 0; break; @@ -777,18 +951,23 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, tid, seq_no, buf_size, - STA_TX_DELBA); + STA_TX_DELBA, + sta_id); if (!status) ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + if (vif->type == NL80211_IFTYPE_STATION) + seq_start = common->vif_info[ii].seq_start; + else if (vif->type == NL80211_IFTYPE_AP) + seq_start = rsta->seq_start[tid]; status = rsi_send_aggregation_params_frame(common, tid, - common->vif_info[ii] - .seq_start, + seq_start, buf_size, - STA_TX_ADDBA_DONE); + STA_TX_ADDBA_DONE, + sta_id); break; default: @@ -796,6 +975,7 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, break; } +unlock: mutex_unlock(&common->mutex); return status; } @@ -1014,7 +1194,7 @@ static void rsi_set_min_rate(struct ieee80211_hw *hw, * @vif: Pointer to the ieee80211_vif structure. * @sta: Pointer to the ieee80211_sta structure. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, negative error codes on failure. */ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1022,22 +1202,101 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + bool sta_exist = false; + struct rsi_sta *rsta; + int status = 0; + + rsi_dbg(INFO_ZONE, "Station Add: %pM\n", sta->addr); mutex_lock(&common->mutex); - rsi_set_min_rate(hw, sta, common); + if (vif->type == NL80211_IFTYPE_AP) { + u8 cnt; + int sta_idx = -1; + int free_index = -1; + + /* Check if max stations reached */ + if (common->num_stations >= common->max_stations) { + rsi_dbg(ERR_ZONE, "Reject: Max Stations exists\n"); + status = -EOPNOTSUPP; + goto unlock; + } + for (cnt = 0; cnt < common->max_stations; cnt++) { + rsta = &common->stations[cnt]; - if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || - (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) { - common->vif_info[0].sgi = true; + if (!rsta->sta) { + if (free_index < 0) + free_index = cnt; + continue; + } + if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { + rsi_dbg(INFO_ZONE, "Station exists\n"); + sta_idx = cnt; + sta_exist = true; + break; + } + } + if (!sta_exist) { + if (free_index >= 0) + sta_idx = free_index; + } + if (sta_idx < 0) { + rsi_dbg(ERR_ZONE, + "%s: Some problem reaching here...\n", + __func__); + status = -EINVAL; + goto unlock; + } + rsta = &common->stations[sta_idx]; + rsta->sta = sta; + rsta->sta_id = sta_idx; + for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) + rsta->start_tx_aggr[cnt] = false; + for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) + rsta->seq_start[cnt] = 0; + if (!sta_exist) { + rsi_dbg(INFO_ZONE, "New Station\n"); + + /* Send peer notify to device */ + rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); + rsi_inform_bss_status(common, AP_OPMODE, 1, sta->addr, + sta->wme, sta->aid, sta, sta_idx); + + if (common->key) { + struct ieee80211_key_conf *key = common->key; + + if ((key->cipher == WLAN_CIPHER_SUITE_WEP104) || + (key->cipher == WLAN_CIPHER_SUITE_WEP40)) + rsi_hal_load_key(adapter->priv, + key->key, + key->keylen, + RSI_PAIRWISE_KEY, + key->keyidx, + key->cipher, + sta_idx); + } + + common->num_stations++; + } } - if (sta->ht_cap.ht_supported) - ieee80211_start_tx_ba_session(sta, 0, 0); + if (vif->type == NL80211_IFTYPE_STATION) { + rsi_set_min_rate(hw, sta, common); + if (sta->ht_cap.ht_supported) { + common->vif_info[0].is_ht = true; + common->bitrate_mask[NL80211_BAND_2GHZ] = + sta->supp_rates[NL80211_BAND_2GHZ]; + if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) + common->vif_info[0].sgi = true; + ieee80211_start_tx_ba_session(sta, 0, 0); + } + } +unlock: mutex_unlock(&common->mutex); - return 0; + return status; } /** @@ -1047,7 +1306,7 @@ static int rsi_mac80211_sta_add(struct ieee80211_hw *hw, * @vif: Pointer to the ieee80211_vif structure. * @sta: Pointer to the ieee80211_sta structure. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, negative error codes on failure. */ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -1055,21 +1314,55 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; + struct ieee80211_bss_conf *bss = &vif->bss_conf; + struct rsi_sta *rsta; + + rsi_dbg(INFO_ZONE, "Station Remove: %pM\n", sta->addr); mutex_lock(&common->mutex); - /* Resetting all the fields to default values */ - common->bitrate_mask[NL80211_BAND_2GHZ] = 0; - common->bitrate_mask[NL80211_BAND_5GHZ] = 0; - common->min_rate = 0xffff; - common->vif_info[0].is_ht = false; - common->vif_info[0].sgi = false; - common->vif_info[0].seq_start = 0; - common->secinfo.ptk_cipher = 0; - common->secinfo.gtk_cipher = 0; + if (vif->type == NL80211_IFTYPE_AP) { + u8 sta_idx, cnt; + + /* Send peer notify to device */ + rsi_dbg(INFO_ZONE, "Indicate bss status to device\n"); + for (sta_idx = 0; sta_idx < common->max_stations; sta_idx++) { + rsta = &common->stations[sta_idx]; + + if (!rsta->sta) + continue; + if (!memcmp(rsta->sta->addr, sta->addr, ETH_ALEN)) { + rsi_inform_bss_status(common, AP_OPMODE, 0, + sta->addr, sta->wme, + sta->aid, sta, sta_idx); + rsta->sta = NULL; + rsta->sta_id = -1; + for (cnt = 0; cnt < IEEE80211_NUM_TIDS; cnt++) + rsta->start_tx_aggr[cnt] = false; + if (common->num_stations > 0) + common->num_stations--; + break; + } + } + if (sta_idx >= common->max_stations) + rsi_dbg(ERR_ZONE, "%s: No station found\n", __func__); + } - rsi_send_rx_filter_frame(common, 0); - + if (vif->type == NL80211_IFTYPE_STATION) { + /* Resetting all the fields to default values */ + memcpy((u8 *)bss->bssid, (u8 *)sta->addr, ETH_ALEN); + bss->qos = sta->wme; + common->bitrate_mask[NL80211_BAND_2GHZ] = 0; + common->bitrate_mask[NL80211_BAND_5GHZ] = 0; + common->min_rate = 0xffff; + common->vif_info[0].is_ht = false; + common->vif_info[0].sgi = false; + common->vif_info[0].seq_start = 0; + common->secinfo.ptk_cipher = 0; + common->secinfo.gtk_cipher = 0; + if (!common->iface_down) + rsi_send_rx_filter_frame(common, 0); + } mutex_unlock(&common->mutex); return 0; @@ -1133,7 +1426,7 @@ fail_set_antenna: * @tx_ant: Bitmap for tx antenna * @rx_ant: Bitmap for rx antenna * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, negative error codes on failure. */ static int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) @@ -1151,6 +1444,21 @@ static int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, return 0; } +static int rsi_map_region_code(enum nl80211_dfs_regions region_code) +{ + switch (region_code) { + case NL80211_DFS_FCC: + return RSI_REGION_FCC; + case NL80211_DFS_ETSI: + return RSI_REGION_ETSI; + case NL80211_DFS_JP: + return RSI_REGION_TELEC; + case NL80211_DFS_UNSET: + return RSI_REGION_WORLD; + } + return RSI_REGION_WORLD; +} + static void rsi_reg_notify(struct wiphy *wiphy, struct regulatory_request *request) { @@ -1158,26 +1466,49 @@ static void rsi_reg_notify(struct wiphy *wiphy, struct ieee80211_channel *ch; struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct rsi_hw * adapter = hw->priv; + struct rsi_common *common = adapter->priv; int i; - - sband = wiphy->bands[NL80211_BAND_5GHZ]; - for (i = 0; i < sband->n_channels; i++) { - ch = &sband->channels[i]; - if (ch->flags & IEEE80211_CHAN_DISABLED) - continue; + mutex_lock(&common->mutex); + + rsi_dbg(INFO_ZONE, "country = %s dfs_region = %d\n", + request->alpha2, request->dfs_region); + + if (common->num_supp_bands > 1) { + sband = wiphy->bands[NL80211_BAND_5GHZ]; - if (ch->flags & IEEE80211_CHAN_RADAR) - ch->flags |= IEEE80211_CHAN_NO_IR; + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (ch->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (ch->flags & IEEE80211_CHAN_RADAR) + ch->flags |= IEEE80211_CHAN_NO_IR; + } } + adapter->dfs_region = rsi_map_region_code(request->dfs_region); + rsi_dbg(INFO_ZONE, "RSI region code = %d\n", adapter->dfs_region); - rsi_dbg(INFO_ZONE, - "country = %s dfs_region = %d\n", - request->alpha2, request->dfs_region); - adapter->dfs_region = request->dfs_region; + adapter->country[0] = request->alpha2[0]; + adapter->country[1] = request->alpha2[1]; + + mutex_unlock(&common->mutex); +} + +static void rsi_mac80211_rfkill_poll(struct ieee80211_hw *hw) +{ + struct rsi_hw *adapter = hw->priv; + struct rsi_common *common = adapter->priv; + + mutex_lock(&common->mutex); + if (common->fsm_state != FSM_MAC_INIT_DONE) + wiphy_rfkill_set_hw_state(hw->wiphy, true); + else + wiphy_rfkill_set_hw_state(hw->wiphy, false); + mutex_unlock(&common->mutex); } -static struct ieee80211_ops mac80211_ops = { +static const struct ieee80211_ops mac80211_ops = { .tx = rsi_mac80211_tx, .start = rsi_mac80211_start, .stop = rsi_mac80211_stop, @@ -1195,13 +1526,14 @@ static struct ieee80211_ops mac80211_ops = { .sta_remove = rsi_mac80211_sta_remove, .set_antenna = rsi_mac80211_set_antenna, .get_antenna = rsi_mac80211_get_antenna, + .rfkill_poll = rsi_mac80211_rfkill_poll, }; /** * rsi_mac80211_attach() - This function is used to initialize Mac80211 stack. * @common: Pointer to the driver private structure. * - * Return: 0 on success, -1 on failure. + * Return: 0 on success, negative error codes on failure. */ int rsi_mac80211_attach(struct rsi_common *common) { @@ -1229,12 +1561,16 @@ int rsi_mac80211_attach(struct rsi_common *common) ieee80211_hw_set(hw, SIGNAL_DBM); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); hw->queues = MAX_HW_QUEUES; hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; hw->max_rates = 1; hw->max_rate_tries = MAX_RETRIES; + hw->uapsd_queues = RSI_IEEE80211_UAPSD_QUEUES; + hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL; hw->max_tx_aggregation_subframes = 6; rsi_register_rates_channels(adapter, NL80211_BAND_2GHZ); @@ -1244,7 +1580,8 @@ int rsi_mac80211_attach(struct rsi_common *common) SET_IEEE80211_PERM_ADDR(hw, common->mac_addr); ether_addr_copy(hw->wiphy->addr_mask, addr_mask); - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->retry_short = RETRY_SHORT; wiphy->retry_long = RETRY_LONG; @@ -1259,6 +1596,14 @@ int rsi_mac80211_attach(struct rsi_common *common) wiphy->bands[NL80211_BAND_5GHZ] = &adapter->sbands[NL80211_BAND_5GHZ]; + /* AP Parameters */ + wiphy->max_ap_assoc_sta = rsi_max_ap_stas[common->oper_mode - 1]; + common->max_stations = wiphy->max_ap_assoc_sta; + rsi_dbg(ERR_ZONE, "Max Stations Allowed = %d\n", common->max_stations); + hw->sta_data_size = sizeof(struct rsi_sta); + wiphy->flags = WIPHY_FLAG_REPORTS_OBSS; + wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; wiphy->reg_notifier = rsi_reg_notify; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); diff --git a/drivers/net/wireless/rsi/rsi_91x_main.c b/drivers/net/wireless/rsi/rsi_91x_main.c index f1cde0ca81f9..3e1e80888d98 100644 --- a/drivers/net/wireless/rsi/rsi_91x_main.c +++ b/drivers/net/wireless/rsi/rsi_91x_main.c @@ -220,7 +220,8 @@ struct rsi_hw *rsi_91x_init(void) rsi_init_event(&common->tx_thread.event); mutex_init(&common->mutex); - mutex_init(&common->tx_rxlock); + mutex_init(&common->tx_lock); + mutex_init(&common->rx_lock); if (rsi_create_kthread(common, &common->tx_thread, @@ -230,6 +231,8 @@ struct rsi_hw *rsi_91x_init(void) goto err; } + rsi_default_ps_params(adapter); + spin_lock_init(&adapter->ps_lock); common->init_done = true; return adapter; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index d4d365b5d2d6..f7b550f900c4 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -17,6 +17,8 @@ #include <linux/etherdevice.h> #include "rsi_mgmt.h" #include "rsi_common.h" +#include "rsi_ps.h" +#include "rsi_hal.h" static struct bootup_params boot_params_20 = { .magic_number = cpu_to_le16(0x5aa5), @@ -230,6 +232,8 @@ static void rsi_set_default_parameters(struct rsi_common *common) common->rf_power_val = 0; /* Default 1.9V */ common->wlan_rf_power_mode = 0; common->obm_ant_sel_val = 2; + common->beacon_interval = RSI_BEACON_INTERVAL; + common->dtim_cnt = RSI_DTIM_COUNT; } /** @@ -266,11 +270,15 @@ static int rsi_send_internal_mgmt_frame(struct rsi_common *common, struct sk_buff *skb) { struct skb_info *tx_params; + struct rsi_cmd_desc *desc; if (skb == NULL) { rsi_dbg(ERR_ZONE, "%s: Unable to allocate skb\n", __func__); return -ENOMEM; } + desc = (struct rsi_cmd_desc *)skb->data; + desc->desc_dword0.len_qno |= cpu_to_le16(DESC_IMMEDIATE_WAKEUP); + skb->priority = MGMT_SOFT_Q; tx_params = (struct skb_info *)&IEEE80211_SKB_CB(skb)->driver_data; tx_params->flags |= INTERNAL_MGMT_PKT; skb_queue_tail(&common->tx_queue[MGMT_SOFT_Q], skb); @@ -298,10 +306,11 @@ static int rsi_load_radio_caps(struct rsi_common *common) 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0}; struct sk_buff *skb; + u16 frame_len = sizeof(struct rsi_radio_caps); rsi_dbg(INFO_ZONE, "%s: Sending rate symbol req frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_radio_caps)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", @@ -309,37 +318,40 @@ static int rsi_load_radio_caps(struct rsi_common *common) return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_radio_caps)); + memset(skb->data, 0, frame_len); radio_caps = (struct rsi_radio_caps *)skb->data; - radio_caps->desc_word[1] = cpu_to_le16(RADIO_CAPABILITIES); - radio_caps->desc_word[4] = cpu_to_le16(RSI_RF_TYPE << 8); + radio_caps->desc_dword0.frame_type = RADIO_CAPABILITIES; + radio_caps->channel_num = common->channel; + radio_caps->rf_model = RSI_RF_TYPE; if (common->channel_width == BW_40MHZ) { - radio_caps->desc_word[7] |= cpu_to_le16(RSI_LMAC_CLOCK_80MHZ); - radio_caps->desc_word[7] |= cpu_to_le16(RSI_ENABLE_40MHZ); + radio_caps->radio_cfg_info = RSI_LMAC_CLOCK_80MHZ; + radio_caps->radio_cfg_info |= RSI_ENABLE_40MHZ; if (common->fsm_state == FSM_MAC_INIT_DONE) { struct ieee80211_hw *hw = adapter->hw; struct ieee80211_conf *conf = &hw->conf; + if (conf_is_ht40_plus(conf)) { - radio_caps->desc_word[5] = - cpu_to_le16(LOWER_20_ENABLE); - radio_caps->desc_word[5] |= - cpu_to_le16(LOWER_20_ENABLE >> 12); + radio_caps->radio_cfg_info = + RSI_CMDDESC_LOWER_20_ENABLE; + radio_caps->radio_info = + RSI_CMDDESC_LOWER_20_ENABLE; } else if (conf_is_ht40_minus(conf)) { - radio_caps->desc_word[5] = - cpu_to_le16(UPPER_20_ENABLE); - radio_caps->desc_word[5] |= - cpu_to_le16(UPPER_20_ENABLE >> 12); + radio_caps->radio_cfg_info = + RSI_CMDDESC_UPPER_20_ENABLE; + radio_caps->radio_info = + RSI_CMDDESC_UPPER_20_ENABLE; } else { - radio_caps->desc_word[5] = - cpu_to_le16(BW_40MHZ << 12); - radio_caps->desc_word[5] |= - cpu_to_le16(FULL40M_ENABLE); + radio_caps->radio_cfg_info = + RSI_CMDDESC_40MHZ; + radio_caps->radio_info = + RSI_CMDDESC_FULL_40_ENABLE; } } } + radio_caps->radio_info |= radio_id; radio_caps->sifs_tx_11n = cpu_to_le16(SIFS_TX_11N_VALUE); radio_caps->sifs_tx_11b = cpu_to_le16(SIFS_TX_11B_VALUE); @@ -348,8 +360,6 @@ static int rsi_load_radio_caps(struct rsi_common *common) radio_caps->cck_ack_tout = cpu_to_le16(CCK_ACK_TOUT_VALUE); radio_caps->preamble_type = cpu_to_le16(LONG_PREAMBLE); - radio_caps->desc_word[7] |= cpu_to_le16(radio_id << 8); - for (ii = 0; ii < MAX_HW_QUEUES; ii++) { radio_caps->qos_params[ii].cont_win_min_q = cpu_to_le16(3); radio_caps->qos_params[ii].cont_win_max_q = cpu_to_le16(0x3f); @@ -357,7 +367,7 @@ static int rsi_load_radio_caps(struct rsi_common *common) radio_caps->qos_params[ii].txop_q = 0; } - for (ii = 0; ii < MAX_HW_QUEUES - 4; ii++) { + for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { radio_caps->qos_params[ii].cont_win_min_q = cpu_to_le16(common->edca_params[ii].cw_min); radio_caps->qos_params[ii].cont_win_max_q = @@ -368,17 +378,19 @@ static int rsi_load_radio_caps(struct rsi_common *common) cpu_to_le16(common->edca_params[ii].txop); } + radio_caps->qos_params[BROADCAST_HW_Q].txop_q = cpu_to_le16(0xffff); + radio_caps->qos_params[MGMT_HW_Q].txop_q = 0; + radio_caps->qos_params[BEACON_HW_Q].txop_q = cpu_to_le16(0xffff); + memcpy(&common->rate_pwr[0], &gc[0], 40); for (ii = 0; ii < 20; ii++) radio_caps->gcpd_per_rate[inx++] = cpu_to_le16(common->rate_pwr[ii] & 0x00FF); - radio_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_radio_caps) - - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - + rsi_set_len_qno(&radio_caps->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); - skb_put(skb, (sizeof(struct rsi_radio_caps))); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } @@ -394,8 +406,7 @@ static int rsi_load_radio_caps(struct rsi_common *common) */ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, u8 *msg, - s32 msg_len, - u8 type) + s32 msg_len) { struct rsi_hw *adapter = common->priv; struct ieee80211_tx_info *info; @@ -403,37 +414,30 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, u8 pad_bytes = msg[4]; struct sk_buff *skb; - if (type == RX_DOT11_MGMT) { - if (!adapter->sc_nvifs) - return -ENOLINK; + if (!adapter->sc_nvifs) + return -ENOLINK; - msg_len -= pad_bytes; - if (msg_len <= 0) { - rsi_dbg(MGMT_RX_ZONE, - "%s: Invalid rx msg of len = %d\n", - __func__, msg_len); - return -EINVAL; - } + msg_len -= pad_bytes; + if (msg_len <= 0) { + rsi_dbg(MGMT_RX_ZONE, + "%s: Invalid rx msg of len = %d\n", + __func__, msg_len); + return -EINVAL; + } - skb = dev_alloc_skb(msg_len); - if (!skb) { - rsi_dbg(ERR_ZONE, "%s: Failed to allocate skb\n", - __func__); - return -ENOMEM; - } + skb = dev_alloc_skb(msg_len); + if (!skb) + return -ENOMEM; - skb_put_data(skb, - (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), - msg_len); + skb_put_data(skb, + (u8 *)(msg + FRAME_DESC_SZ + pad_bytes), + msg_len); - info = IEEE80211_SKB_CB(skb); - rx_params = (struct skb_info *)info->driver_data; - rx_params->rssi = rsi_get_rssi(msg); - rx_params->channel = rsi_get_channel(msg); - rsi_indicate_pkt_to_os(common, skb); - } else { - rsi_dbg(MGMT_TX_ZONE, "%s: Internal Packet\n", __func__); - } + info = IEEE80211_SKB_CB(skb); + rx_params = (struct skb_info *)info->driver_data; + rx_params->rssi = rsi_get_rssi(msg); + rx_params->channel = rsi_get_channel(msg); + rsi_indicate_pkt_to_os(common, skb); return 0; } @@ -451,20 +455,23 @@ static int rsi_mgmt_pkt_to_core(struct rsi_common *common, * Return: status: 0 on success, corresponding negative error code on failure. */ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, - u8 opmode, + enum opmode opmode, u8 notify_event, const unsigned char *bssid, u8 qos_enable, - u16 aid) + u16 aid, + u16 sta_id) { + struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb = NULL; struct rsi_peer_notify *peer_notify; u16 vap_id = 0; int status; + u16 frame_len = sizeof(struct rsi_peer_notify); rsi_dbg(MGMT_TX_ZONE, "%s: Sending sta notify frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_peer_notify)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", @@ -472,10 +479,13 @@ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_peer_notify)); + memset(skb->data, 0, frame_len); peer_notify = (struct rsi_peer_notify *)skb->data; - peer_notify->command = cpu_to_le16(opmode << 1); + if (opmode == STA_OPMODE) + peer_notify->command = cpu_to_le16(PEER_TYPE_AP << 1); + else if (opmode == AP_OPMODE) + peer_notify->command = cpu_to_le16(PEER_TYPE_STA << 1); switch (notify_event) { case STA_CONNECTED: @@ -490,20 +500,22 @@ static int rsi_hal_send_sta_notify_frame(struct rsi_common *common, peer_notify->command |= cpu_to_le16((aid & 0xfff) << 4); ether_addr_copy(peer_notify->mac_addr, bssid); - + peer_notify->mpdu_density = cpu_to_le16(RSI_MPDU_DENSITY); peer_notify->sta_flags = cpu_to_le32((qos_enable) ? 1 : 0); - peer_notify->desc_word[0] = - cpu_to_le16((sizeof(struct rsi_peer_notify) - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - peer_notify->desc_word[1] = cpu_to_le16(PEER_NOTIFY); - peer_notify->desc_word[7] |= cpu_to_le16(vap_id << 8); + rsi_set_len_qno(&peer_notify->desc.desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), + RSI_WIFI_MGMT_Q); + peer_notify->desc.desc_dword0.frame_type = PEER_NOTIFY; + peer_notify->desc.desc_dword3.qid_tid = sta_id; + peer_notify->desc.desc_dword3.sta_id = vap_id; - skb_put(skb, sizeof(struct rsi_peer_notify)); + skb_put(skb, frame_len); status = rsi_send_internal_mgmt_frame(common, skb); - if (!status && qos_enable) { + if ((vif->type == NL80211_IFTYPE_STATION) && + (!status && qos_enable)) { rsi_set_contention_vals(common); status = rsi_load_radio_caps(common); } @@ -525,13 +537,14 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, u16 ssn, u8 buf_size, - u8 event) + u8 event, + u8 sta_id) { struct sk_buff *skb = NULL; - struct rsi_mac_frame *mgmt_frame; - u8 peer_id = 0; + struct rsi_aggr_params *aggr_params; + u16 frame_len = sizeof(struct rsi_aggr_params); - skb = dev_alloc_skb(FRAME_DESC_SZ); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", @@ -539,37 +552,29 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, return -ENOMEM; } - memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; + memset(skb->data, 0, frame_len); + aggr_params = (struct rsi_aggr_params *)skb->data; rsi_dbg(MGMT_TX_ZONE, "%s: Sending AMPDU indication frame\n", __func__); - mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); - mgmt_frame->desc_word[1] = cpu_to_le16(AMPDU_IND); + rsi_set_len_qno(&aggr_params->desc_dword0.len_qno, 0, RSI_WIFI_MGMT_Q); + aggr_params->desc_dword0.frame_type = AMPDU_IND; + aggr_params->aggr_params = tid & RSI_AGGR_PARAMS_TID_MASK; + aggr_params->peer_id = sta_id; if (event == STA_TX_ADDBA_DONE) { - mgmt_frame->desc_word[4] = cpu_to_le16(ssn); - mgmt_frame->desc_word[5] = cpu_to_le16(buf_size); - mgmt_frame->desc_word[7] = - cpu_to_le16((tid | (START_AMPDU_AGGR << 4) | (peer_id << 8))); + aggr_params->seq_start = cpu_to_le16(ssn); + aggr_params->baw_size = cpu_to_le16(buf_size); + aggr_params->aggr_params |= RSI_AGGR_PARAMS_START; } else if (event == STA_RX_ADDBA_DONE) { - mgmt_frame->desc_word[4] = cpu_to_le16(ssn); - mgmt_frame->desc_word[7] = cpu_to_le16(tid | - (START_AMPDU_AGGR << 4) | - (RX_BA_INDICATION << 5) | - (peer_id << 8)); - } else if (event == STA_TX_DELBA) { - mgmt_frame->desc_word[7] = cpu_to_le16(tid | - (STOP_AMPDU_AGGR << 4) | - (peer_id << 8)); + aggr_params->seq_start = cpu_to_le16(ssn); + aggr_params->aggr_params |= (RSI_AGGR_PARAMS_START | + RSI_AGGR_PARAMS_RX_AGGR); } else if (event == STA_RX_DELBA) { - mgmt_frame->desc_word[7] = cpu_to_le16(tid | - (STOP_AMPDU_AGGR << 4) | - (RX_BA_INDICATION << 5) | - (peer_id << 8)); + aggr_params->aggr_params |= RSI_AGGR_PARAMS_RX_AGGR; } - skb_put(skb, FRAME_DESC_SZ); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } @@ -584,34 +589,36 @@ int rsi_send_aggregation_params_frame(struct rsi_common *common, static int rsi_program_bb_rf(struct rsi_common *common) { struct sk_buff *skb; - struct rsi_mac_frame *mgmt_frame; + struct rsi_bb_rf_prog *bb_rf_prog; + u16 frame_len = sizeof(struct rsi_bb_rf_prog); rsi_dbg(MGMT_TX_ZONE, "%s: Sending program BB/RF frame\n", __func__); - skb = dev_alloc_skb(FRAME_DESC_SZ); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); return -ENOMEM; } - memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; + memset(skb->data, 0, frame_len); + bb_rf_prog = (struct rsi_bb_rf_prog *)skb->data; - mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); - mgmt_frame->desc_word[1] = cpu_to_le16(BBP_PROG_IN_TA); - mgmt_frame->desc_word[4] = cpu_to_le16(common->endpoint); + rsi_set_len_qno(&bb_rf_prog->desc_dword0.len_qno, 0, RSI_WIFI_MGMT_Q); + bb_rf_prog->desc_dword0.frame_type = BBP_PROG_IN_TA; + bb_rf_prog->endpoint = common->endpoint; + bb_rf_prog->rf_power_mode = common->wlan_rf_power_mode; if (common->rf_reset) { - mgmt_frame->desc_word[7] = cpu_to_le16(RF_RESET_ENABLE); + bb_rf_prog->flags = cpu_to_le16(RF_RESET_ENABLE); rsi_dbg(MGMT_TX_ZONE, "%s: ===> RF RESET REQUEST SENT <===\n", __func__); common->rf_reset = 0; } common->bb_rf_prog_count = 1; - mgmt_frame->desc_word[7] |= cpu_to_le16(PUT_BBP_RESET | - BBP_REG_WRITE | (RSI_RF_TYPE << 4)); - skb_put(skb, FRAME_DESC_SZ); + bb_rf_prog->flags |= cpu_to_le16(PUT_BBP_RESET | BBP_REG_WRITE | + (RSI_RF_TYPE << 4)); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } @@ -625,6 +632,8 @@ static int rsi_program_bb_rf(struct rsi_common *common) */ int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, + u8 *mac_addr, + u8 vap_id, u8 vap_status) { struct sk_buff *skb = NULL; @@ -632,59 +641,60 @@ int rsi_set_vap_capabilities(struct rsi_common *common, struct rsi_hw *adapter = common->priv; struct ieee80211_hw *hw = adapter->hw; struct ieee80211_conf *conf = &hw->conf; - u16 vap_id = 0; + u16 frame_len = sizeof(struct rsi_vap_caps); rsi_dbg(MGMT_TX_ZONE, "%s: Sending VAP capabilities frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_vap_caps)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_vap_caps)); + memset(skb->data, 0, frame_len); vap_caps = (struct rsi_vap_caps *)skb->data; - vap_caps->desc_word[0] = cpu_to_le16((sizeof(struct rsi_vap_caps) - - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - vap_caps->desc_word[1] = cpu_to_le16(VAP_CAPABILITIES); - vap_caps->desc_word[2] = cpu_to_le16(vap_status << 8); - vap_caps->desc_word[4] = cpu_to_le16(mode | - (common->channel_width << 8)); - vap_caps->desc_word[7] = cpu_to_le16((vap_id << 8) | - (common->mac_id << 4) | - common->radio_id); - - memcpy(vap_caps->mac_addr, common->mac_addr, IEEE80211_ADDR_LEN); + rsi_set_len_qno(&vap_caps->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); + vap_caps->desc_dword0.frame_type = VAP_CAPABILITIES; + vap_caps->status = vap_status; + vap_caps->vif_type = mode; + vap_caps->channel_bw = common->channel_width; + vap_caps->vap_id = vap_id; + vap_caps->radioid_macid = ((common->mac_id & 0xf) << 4) | + (common->radio_id & 0xf); + + memcpy(vap_caps->mac_addr, mac_addr, IEEE80211_ADDR_LEN); vap_caps->keep_alive_period = cpu_to_le16(90); vap_caps->frag_threshold = cpu_to_le16(IEEE80211_MAX_FRAG_THRESHOLD); vap_caps->rts_threshold = cpu_to_le16(common->rts_threshold); - vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_6); if (common->band == NL80211_BAND_5GHZ) { - vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_6); - if (conf_is_ht40(&common->priv->hw->conf)) { - vap_caps->default_ctrl_rate |= - cpu_to_le32(FULL40M_ENABLE << 16); - } + vap_caps->default_ctrl_rate = cpu_to_le16(RSI_RATE_6); + vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_6); } else { - vap_caps->default_ctrl_rate = cpu_to_le32(RSI_RATE_1); + vap_caps->default_ctrl_rate = cpu_to_le16(RSI_RATE_1); + vap_caps->default_mgmt_rate = cpu_to_le32(RSI_RATE_1); + } + if (conf_is_ht40(conf)) { if (conf_is_ht40_minus(conf)) - vap_caps->default_ctrl_rate |= - cpu_to_le32(UPPER_20_ENABLE << 16); + vap_caps->ctrl_rate_flags = + cpu_to_le16(UPPER_20_ENABLE); else if (conf_is_ht40_plus(conf)) - vap_caps->default_ctrl_rate |= - cpu_to_le32(LOWER_20_ENABLE << 16); + vap_caps->ctrl_rate_flags = + cpu_to_le16(LOWER_20_ENABLE); + else + vap_caps->ctrl_rate_flags = + cpu_to_le16(FULL40M_ENABLE); } vap_caps->default_data_rate = 0; - vap_caps->beacon_interval = cpu_to_le16(200); - vap_caps->dtim_period = cpu_to_le16(4); + vap_caps->beacon_interval = cpu_to_le16(common->beacon_interval); + vap_caps->dtim_period = cpu_to_le16(common->dtim_cnt); - skb_put(skb, sizeof(*vap_caps)); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } @@ -705,58 +715,66 @@ int rsi_hal_load_key(struct rsi_common *common, u16 key_len, u8 key_type, u8 key_id, - u32 cipher) + u32 cipher, + s16 sta_id) { + struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb = NULL; struct rsi_set_key *set_key; u16 key_descriptor = 0; + u16 frame_len = sizeof(struct rsi_set_key); rsi_dbg(MGMT_TX_ZONE, "%s: Sending load key frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_set_key)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_set_key)); + memset(skb->data, 0, frame_len); set_key = (struct rsi_set_key *)skb->data; + if (key_type == RSI_GROUP_KEY) { + key_descriptor = RSI_KEY_TYPE_BROADCAST; + if (vif->type == NL80211_IFTYPE_AP) + key_descriptor |= RSI_KEY_MODE_AP; + } if ((cipher == WLAN_CIPHER_SUITE_WEP40) || (cipher == WLAN_CIPHER_SUITE_WEP104)) { - key_len += 1; - key_descriptor |= BIT(2); + key_id = 0; + key_descriptor |= RSI_WEP_KEY; if (key_len >= 13) - key_descriptor |= BIT(3); + key_descriptor |= RSI_WEP_KEY_104; } else if (cipher != KEY_TYPE_CLEAR) { - key_descriptor |= BIT(4); - if (key_type == RSI_PAIRWISE_KEY) - key_id = 0; + key_descriptor |= RSI_CIPHER_WPA; if (cipher == WLAN_CIPHER_SUITE_TKIP) - key_descriptor |= BIT(5); + key_descriptor |= RSI_CIPHER_TKIP; } - key_descriptor |= (key_type | BIT(13) | (key_id << 14)); - - set_key->desc_word[0] = cpu_to_le16((sizeof(struct rsi_set_key) - - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); - set_key->desc_word[1] = cpu_to_le16(SET_KEY_REQ); - set_key->desc_word[4] = cpu_to_le16(key_descriptor); - - if ((cipher == WLAN_CIPHER_SUITE_WEP40) || - (cipher == WLAN_CIPHER_SUITE_WEP104)) { - memcpy(&set_key->key[key_id][1], - data, - key_len * 2); + key_descriptor |= RSI_PROTECT_DATA_FRAMES; + key_descriptor |= ((key_id << RSI_KEY_ID_OFFSET) & RSI_KEY_ID_MASK); + + rsi_set_len_qno(&set_key->desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); + set_key->desc_dword0.frame_type = SET_KEY_REQ; + set_key->key_desc = cpu_to_le16(key_descriptor); + set_key->sta_id = sta_id; + + if (data) { + if ((cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104)) { + memcpy(&set_key->key[key_id][1], data, key_len * 2); + } else { + memcpy(&set_key->key[0][0], data, key_len); + } + memcpy(set_key->tx_mic_key, &data[16], 8); + memcpy(set_key->rx_mic_key, &data[24], 8); } else { - memcpy(&set_key->key[0][0], data, key_len); + memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ); } - memcpy(set_key->tx_mic_key, &data[16], 8); - memcpy(set_key->rx_mic_key, &data[24], 8); - - skb_put(skb, sizeof(struct rsi_set_key)); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } @@ -970,12 +988,13 @@ int rsi_set_channel(struct rsi_common *common, struct ieee80211_channel *channel) { struct sk_buff *skb = NULL; - struct rsi_mac_frame *mgmt_frame; + struct rsi_chan_config *chan_cfg; + u16 frame_len = sizeof(struct rsi_chan_config); rsi_dbg(MGMT_TX_ZONE, "%s: Sending scan req frame\n", __func__); - skb = dev_alloc_skb(FRAME_DESC_SZ); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); @@ -986,37 +1005,33 @@ int rsi_set_channel(struct rsi_common *common, dev_kfree_skb(skb); return 0; } - memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; - - mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); - mgmt_frame->desc_word[1] = cpu_to_le16(SCAN_REQUEST); - mgmt_frame->desc_word[4] = cpu_to_le16(channel->hw_value); - - mgmt_frame->desc_word[4] |= - cpu_to_le16(((char)(channel->max_antenna_gain)) << 8); - mgmt_frame->desc_word[5] = - cpu_to_le16((char)(channel->max_antenna_gain)); - - mgmt_frame->desc_word[7] = cpu_to_le16(PUT_BBP_RESET | - BBP_REG_WRITE | - (RSI_RF_TYPE << 4)); - - if (!(channel->flags & IEEE80211_CHAN_NO_IR) && - !(channel->flags & IEEE80211_CHAN_RADAR)) { + memset(skb->data, 0, frame_len); + chan_cfg = (struct rsi_chan_config *)skb->data; + + rsi_set_len_qno(&chan_cfg->desc_dword0.len_qno, 0, RSI_WIFI_MGMT_Q); + chan_cfg->desc_dword0.frame_type = SCAN_REQUEST; + chan_cfg->channel_number = channel->hw_value; + chan_cfg->antenna_gain_offset_2g = channel->max_antenna_gain; + chan_cfg->antenna_gain_offset_5g = channel->max_antenna_gain; + chan_cfg->region_rftype = (RSI_RF_TYPE & 0xf) << 4; + + if ((channel->flags & IEEE80211_CHAN_NO_IR) || + (channel->flags & IEEE80211_CHAN_RADAR)) { + chan_cfg->antenna_gain_offset_2g |= RSI_CHAN_RADAR; + } else { if (common->tx_power < channel->max_power) - mgmt_frame->desc_word[6] = cpu_to_le16(common->tx_power); + chan_cfg->tx_power = cpu_to_le16(common->tx_power); else - mgmt_frame->desc_word[6] = cpu_to_le16(channel->max_power); + chan_cfg->tx_power = cpu_to_le16(channel->max_power); } - mgmt_frame->desc_word[7] = cpu_to_le16(common->priv->dfs_region); + chan_cfg->region_rftype |= (common->priv->dfs_region & 0xf); if (common->channel_width == BW_40MHZ) - mgmt_frame->desc_word[5] |= cpu_to_le16(0x1 << 8); + chan_cfg->channel_width = 0x1; common->channel = channel->hw_value; - skb_put(skb, FRAME_DESC_SZ); + skb_put(skb, frame_len); return rsi_send_internal_mgmt_frame(common, skb); } @@ -1058,6 +1073,37 @@ int rsi_send_radio_params_update(struct rsi_common *common) return rsi_send_internal_mgmt_frame(common, skb); } +/* This function programs the threshold. */ +int rsi_send_vap_dynamic_update(struct rsi_common *common) +{ + struct sk_buff *skb; + struct rsi_dynamic_s *dynamic_frame; + + rsi_dbg(MGMT_TX_ZONE, + "%s: Sending vap update indication frame\n", __func__); + + skb = dev_alloc_skb(sizeof(struct rsi_dynamic_s)); + if (!skb) + return -ENOMEM; + + memset(skb->data, 0, sizeof(struct rsi_dynamic_s)); + dynamic_frame = (struct rsi_dynamic_s *)skb->data; + rsi_set_len_qno(&dynamic_frame->desc_dword0.len_qno, + sizeof(dynamic_frame->frame_body), RSI_WIFI_MGMT_Q); + + dynamic_frame->desc_dword0.frame_type = VAP_DYNAMIC_UPDATE; + dynamic_frame->desc_dword2.pkt_info = + cpu_to_le32(common->rts_threshold); + /* Beacon miss threshold */ + dynamic_frame->frame_body.keep_alive_period = + cpu_to_le16(RSI_DEF_KEEPALIVE); + dynamic_frame->desc_dword3.sta_id = 0; /* vap id */ + + skb_put(skb, sizeof(struct rsi_dynamic_s)); + + return rsi_send_internal_mgmt_frame(common, skb); +} + /** * rsi_compare() - This function is used to compare two integers * @a: pointer to the first integer @@ -1112,8 +1158,11 @@ static bool rsi_map_rates(u16 rate, int *offset) * * Return: 0 on success, corresponding error code on failure. */ -static int rsi_send_auto_rate_request(struct rsi_common *common) +static int rsi_send_auto_rate_request(struct rsi_common *common, + struct ieee80211_sta *sta, + u16 sta_id) { + struct ieee80211_vif *vif = common->priv->vifs[0]; struct sk_buff *skb; struct rsi_auto_rate *auto_rate; int ii = 0, jj = 0, kk = 0; @@ -1121,11 +1170,15 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) u8 band = hw->conf.chandef.chan->band; u8 num_supported_rates = 0; u8 rate_table_offset, rate_offset = 0; - u32 rate_bitmap = common->bitrate_mask[band]; - + u32 rate_bitmap; u16 *selected_rates, min_rate; + bool is_ht = false, is_sgi = false; + u16 frame_len = sizeof(struct rsi_auto_rate); + + rsi_dbg(MGMT_TX_ZONE, + "%s: Sending auto rate request frame\n", __func__); - skb = dev_alloc_skb(sizeof(struct rsi_auto_rate)); + skb = dev_alloc_skb(frame_len); if (!skb) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", __func__); @@ -1140,8 +1193,6 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) return -ENOMEM; } - memset(skb->data, 0, sizeof(struct rsi_auto_rate)); - auto_rate = (struct rsi_auto_rate *)skb->data; auto_rate->aarf_rssi = cpu_to_le16(((u16)3 << 6) | (u16)(18 & 0x3f)); @@ -1150,16 +1201,35 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) auto_rate->initial_boundary = cpu_to_le16(3); auto_rate->max_threshold_limt = cpu_to_le16(27); - auto_rate->desc_word[1] = cpu_to_le16(AUTO_RATE_IND); + auto_rate->desc.desc_dword0.frame_type = AUTO_RATE_IND; if (common->channel_width == BW_40MHZ) - auto_rate->desc_word[7] |= cpu_to_le16(1); + auto_rate->desc.desc_dword3.qid_tid = BW_40MHZ; + auto_rate->desc.desc_dword3.sta_id = sta_id; + + if (vif->type == NL80211_IFTYPE_STATION) { + rate_bitmap = common->bitrate_mask[band]; + is_ht = common->vif_info[0].is_ht; + is_sgi = common->vif_info[0].sgi; + } else { + rate_bitmap = sta->supp_rates[band]; + is_ht = sta->ht_cap.ht_supported; + if ((sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) || + (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)) + is_sgi = true; + } if (band == NL80211_BAND_2GHZ) { - min_rate = RSI_RATE_1; + if ((rate_bitmap == 0) && (is_ht)) + min_rate = RSI_RATE_MCS0; + else + min_rate = RSI_RATE_1; rate_table_offset = 0; } else { - min_rate = RSI_RATE_6; + if ((rate_bitmap == 0) && (is_ht)) + min_rate = RSI_RATE_MCS0; + else + min_rate = RSI_RATE_6; rate_table_offset = 4; } @@ -1173,7 +1243,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) } num_supported_rates = jj; - if (common->vif_info[0].is_ht) { + if (is_ht) { for (ii = 0; ii < ARRAY_SIZE(mcs); ii++) selected_rates[jj++] = mcs[ii]; num_supported_rates += ARRAY_SIZE(mcs); @@ -1194,13 +1264,15 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) } /* loading HT rates in the bottom half of the auto rate table */ - if (common->vif_info[0].is_ht) { + if (is_ht) { for (ii = rate_offset, kk = ARRAY_SIZE(rsi_mcsrates) - 1; ii < rate_offset + 2 * ARRAY_SIZE(rsi_mcsrates); ii++) { - if (common->vif_info[0].sgi || - conf_is_ht40(&common->priv->hw->conf)) + if (is_sgi || conf_is_ht40(&common->priv->hw->conf)) auto_rate->supported_rates[ii++] = cpu_to_le16(rsi_mcsrates[kk] | BIT(9)); + else + auto_rate->supported_rates[ii++] = + cpu_to_le16(rsi_mcsrates[kk]); auto_rate->supported_rates[ii] = cpu_to_le16(rsi_mcsrates[kk--]); } @@ -1216,15 +1288,12 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) auto_rate->num_supported_rates = cpu_to_le16(num_supported_rates * 2); auto_rate->moderate_rate_inx = cpu_to_le16(num_supported_rates / 2); - auto_rate->desc_word[7] |= cpu_to_le16(0 << 8); num_supported_rates *= 2; - auto_rate->desc_word[0] = cpu_to_le16((sizeof(*auto_rate) - - FRAME_DESC_SZ) | - (RSI_WIFI_MGMT_Q << 12)); + rsi_set_len_qno(&auto_rate->desc.desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); - skb_put(skb, - sizeof(struct rsi_auto_rate)); + skb_put(skb, frame_len); kfree(selected_rates); return rsi_send_internal_mgmt_frame(common, skb); @@ -1243,27 +1312,40 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) * Return: None. */ void rsi_inform_bss_status(struct rsi_common *common, + enum opmode opmode, u8 status, - const unsigned char *bssid, + const u8 *addr, u8 qos_enable, - u16 aid) + u16 aid, + struct ieee80211_sta *sta, + u16 sta_id) { if (status) { + if (opmode == STA_OPMODE) + common->hw_data_qs_blocked = true; rsi_hal_send_sta_notify_frame(common, - RSI_IFTYPE_STATION, + opmode, STA_CONNECTED, - bssid, + addr, qos_enable, - aid); + aid, sta_id); if (common->min_rate == 0xffff) - rsi_send_auto_rate_request(common); + rsi_send_auto_rate_request(common, sta, sta_id); + if (opmode == STA_OPMODE) { + if (!rsi_send_block_unblock_frame(common, false)) + common->hw_data_qs_blocked = false; + } } else { + if (opmode == STA_OPMODE) + common->hw_data_qs_blocked = true; rsi_hal_send_sta_notify_frame(common, - RSI_IFTYPE_STATION, + opmode, STA_DISCONNECTED, - bssid, + addr, qos_enable, - aid); + aid, sta_id); + if (opmode == STA_OPMODE) + rsi_send_block_unblock_frame(common, true); } } @@ -1276,7 +1358,8 @@ void rsi_inform_bss_status(struct rsi_common *common, */ static int rsi_eeprom_read(struct rsi_common *common) { - struct rsi_mac_frame *mgmt_frame; + struct rsi_eeprom_read_frame *mgmt_frame; + struct rsi_hw *adapter = common->priv; struct sk_buff *skb; rsi_dbg(MGMT_TX_ZONE, "%s: Sending EEPROM read req frame\n", __func__); @@ -1289,18 +1372,21 @@ static int rsi_eeprom_read(struct rsi_common *common) } memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; + mgmt_frame = (struct rsi_eeprom_read_frame *)skb->data; /* FrameType */ - mgmt_frame->desc_word[1] = cpu_to_le16(EEPROM_READ_TYPE); - mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + rsi_set_len_qno(&mgmt_frame->len_qno, 0, RSI_WIFI_MGMT_Q); + mgmt_frame->pkt_type = EEPROM_READ; + /* Number of bytes to read */ - mgmt_frame->desc_word[3] = cpu_to_le16(ETH_ALEN + - WLAN_MAC_MAGIC_WORD_LEN + - WLAN_HOST_MODE_LEN + - WLAN_FW_VERSION_LEN); + mgmt_frame->pkt_info = + cpu_to_le32((adapter->eeprom.length << RSI_EEPROM_LEN_OFFSET) & + RSI_EEPROM_LEN_MASK); + mgmt_frame->pkt_info |= cpu_to_le32((3 << RSI_EEPROM_HDR_SIZE_OFFSET) & + RSI_EEPROM_HDR_SIZE_MASK); + /* Address to read */ - mgmt_frame->desc_word[4] = cpu_to_le16(WLAN_MAC_EEPROM_ADDR); + mgmt_frame->eeprom_offset = cpu_to_le32(adapter->eeprom.offset); skb_put(skb, FRAME_DESC_SZ); @@ -1317,7 +1403,7 @@ static int rsi_eeprom_read(struct rsi_common *common) */ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event) { - struct rsi_mac_frame *mgmt_frame; + struct rsi_block_unblock_data *mgmt_frame; struct sk_buff *skb; rsi_dbg(MGMT_TX_ZONE, "%s: Sending block/unblock frame\n", __func__); @@ -1330,23 +1416,25 @@ int rsi_send_block_unblock_frame(struct rsi_common *common, bool block_event) } memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; + mgmt_frame = (struct rsi_block_unblock_data *)skb->data; - mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); - mgmt_frame->desc_word[1] = cpu_to_le16(BLOCK_HW_QUEUE); + rsi_set_len_qno(&mgmt_frame->desc_dword0.len_qno, 0, RSI_WIFI_MGMT_Q); + mgmt_frame->desc_dword0.frame_type = BLOCK_HW_QUEUE; + mgmt_frame->host_quiet_info = QUIET_INFO_VALID; if (block_event) { rsi_dbg(INFO_ZONE, "blocking the data qs\n"); - mgmt_frame->desc_word[4] = cpu_to_le16(0xf); + mgmt_frame->block_q_bitmap = cpu_to_le16(0xf); + mgmt_frame->block_q_bitmap |= cpu_to_le16(0xf << 4); } else { rsi_dbg(INFO_ZONE, "unblocking the data qs\n"); - mgmt_frame->desc_word[5] = cpu_to_le16(0xf); + mgmt_frame->unblock_q_bitmap = cpu_to_le16(0xf); + mgmt_frame->unblock_q_bitmap |= cpu_to_le16(0xf << 4); } skb_put(skb, FRAME_DESC_SZ); return rsi_send_internal_mgmt_frame(common, skb); - } /** @@ -1383,6 +1471,61 @@ int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word) return rsi_send_internal_mgmt_frame(common, skb); } +int rsi_send_ps_request(struct rsi_hw *adapter, bool enable) +{ + struct rsi_common *common = adapter->priv; + struct ieee80211_bss_conf *bss = &adapter->vifs[0]->bss_conf; + struct rsi_request_ps *ps; + struct rsi_ps_info *ps_info; + struct sk_buff *skb; + int frame_len = sizeof(*ps); + + skb = dev_alloc_skb(frame_len); + if (!skb) + return -ENOMEM; + memset(skb->data, 0, frame_len); + + ps = (struct rsi_request_ps *)skb->data; + ps_info = &adapter->ps_info; + + rsi_set_len_qno(&ps->desc.desc_dword0.len_qno, + (frame_len - FRAME_DESC_SZ), RSI_WIFI_MGMT_Q); + ps->desc.desc_dword0.frame_type = WAKEUP_SLEEP_REQUEST; + if (enable) { + ps->ps_sleep.enable = RSI_PS_ENABLE; + ps->desc.desc_dword3.token = cpu_to_le16(RSI_SLEEP_REQUEST); + } else { + ps->ps_sleep.enable = RSI_PS_DISABLE; + ps->desc.desc_dword0.len_qno |= cpu_to_le16(RSI_PS_DISABLE_IND); + ps->desc.desc_dword3.token = cpu_to_le16(RSI_WAKEUP_REQUEST); + } + + ps->ps_uapsd_acs = common->uapsd_bitmap; + + ps->ps_sleep.sleep_type = ps_info->sleep_type; + ps->ps_sleep.num_bcns_per_lis_int = + cpu_to_le16(ps_info->num_bcns_per_lis_int); + ps->ps_sleep.sleep_duration = + cpu_to_le32(ps_info->deep_sleep_wakeup_period); + + if (bss->assoc) + ps->ps_sleep.connected_sleep = RSI_CONNECTED_SLEEP; + else + ps->ps_sleep.connected_sleep = RSI_DEEP_SLEEP; + + ps->ps_listen_interval = cpu_to_le32(ps_info->listen_interval); + ps->ps_dtim_interval_duration = + cpu_to_le32(ps_info->dtim_interval_duration); + + if (ps_info->listen_interval > ps_info->dtim_interval_duration) + ps->ps_listen_interval = cpu_to_le32(RSI_PS_DISABLE); + + ps->ps_num_dtim_intervals = cpu_to_le16(ps_info->num_dtims_per_sleep); + skb_put(skb, frame_len); + + return rsi_send_internal_mgmt_frame(common, skb); +} + /** * rsi_set_antenna() - This fuction send antenna configuration request * to device @@ -1394,7 +1537,7 @@ int rsi_send_rx_filter_frame(struct rsi_common *common, u16 rx_filter_word) */ int rsi_set_antenna(struct rsi_common *common, u8 antenna) { - struct rsi_mac_frame *cmd_frame; + struct rsi_ant_sel_frame *ant_sel_frame; struct sk_buff *skb; skb = dev_alloc_skb(FRAME_DESC_SZ); @@ -1405,17 +1548,43 @@ int rsi_set_antenna(struct rsi_common *common, u8 antenna) } memset(skb->data, 0, FRAME_DESC_SZ); - cmd_frame = (struct rsi_mac_frame *)skb->data; - - cmd_frame->desc_word[1] = cpu_to_le16(ANT_SEL_FRAME); - cmd_frame->desc_word[3] = cpu_to_le16(antenna & 0x00ff); - cmd_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); + ant_sel_frame = (struct rsi_ant_sel_frame *)skb->data; + ant_sel_frame->desc_dword0.frame_type = ANT_SEL_FRAME; + ant_sel_frame->sub_frame_type = ANTENNA_SEL_TYPE; + ant_sel_frame->ant_value = cpu_to_le16(antenna & ANTENNA_MASK_VALUE); + rsi_set_len_qno(&ant_sel_frame->desc_dword0.len_qno, + 0, RSI_WIFI_MGMT_Q); skb_put(skb, FRAME_DESC_SZ); return rsi_send_internal_mgmt_frame(common, skb); } +static int rsi_send_beacon(struct rsi_common *common) +{ + struct sk_buff *skb = NULL; + u8 dword_align_bytes = 0; + + skb = dev_alloc_skb(MAX_MGMT_PKT_SIZE); + if (!skb) + return -ENOMEM; + + memset(skb->data, 0, MAX_MGMT_PKT_SIZE); + + dword_align_bytes = ((unsigned long)skb->data & 0x3f); + if (dword_align_bytes) + skb_pull(skb, (64 - dword_align_bytes)); + if (rsi_prepare_beacon(common, skb)) { + rsi_dbg(ERR_ZONE, "Failed to prepare beacon\n"); + return -EINVAL; + } + skb_queue_tail(&common->tx_queue[MGMT_BEACON_Q], skb); + rsi_set_event(&common->tx_thread.event); + rsi_dbg(DATA_TX_ZONE, "%s: Added to beacon queue\n", __func__); + + return 0; +} + /** * rsi_handle_ta_confirm_type() - This function handles the confirm frames. * @common: Pointer to the driver private structure. @@ -1426,19 +1595,25 @@ int rsi_set_antenna(struct rsi_common *common, u8 antenna) static int rsi_handle_ta_confirm_type(struct rsi_common *common, u8 *msg) { + struct rsi_hw *adapter = common->priv; u8 sub_type = (msg[15] & 0xff); + u16 msg_len = ((u16 *)msg)[0] & 0xfff; + u8 offset; switch (sub_type) { case BOOTUP_PARAMS_REQUEST: rsi_dbg(FSM_ZONE, "%s: Boot up params confirm received\n", __func__); if (common->fsm_state == FSM_BOOT_PARAMS_SENT) { + adapter->eeprom.length = (IEEE80211_ADDR_LEN + + WLAN_MAC_MAGIC_WORD_LEN + + WLAN_HOST_MODE_LEN); + adapter->eeprom.offset = WLAN_MAC_EEPROM_ADDR; if (rsi_eeprom_read(common)) { common->fsm_state = FSM_CARD_NOT_READY; goto out; - } else { - common->fsm_state = FSM_EEPROM_READ_MAC_ADDR; } + common->fsm_state = FSM_EEPROM_READ_MAC_ADDR; } else { rsi_dbg(INFO_ZONE, "%s: Received bootup params cfm in %d state\n", @@ -1447,30 +1622,52 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, } break; - case EEPROM_READ_TYPE: + case EEPROM_READ: + rsi_dbg(FSM_ZONE, "EEPROM READ confirm received\n"); + if (msg_len <= 0) { + rsi_dbg(FSM_ZONE, + "%s: [EEPROM_READ] Invalid len %d\n", + __func__, msg_len); + goto out; + } + if (msg[16] != MAGIC_WORD) { + rsi_dbg(FSM_ZONE, + "%s: [EEPROM_READ] Invalid token\n", __func__); + common->fsm_state = FSM_CARD_NOT_READY; + goto out; + } if (common->fsm_state == FSM_EEPROM_READ_MAC_ADDR) { - if (msg[16] == MAGIC_WORD) { - u8 offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN - + WLAN_MAC_MAGIC_WORD_LEN); - memcpy(common->mac_addr, - &msg[offset], - ETH_ALEN); - memcpy(&common->fw_ver, - &msg[offset + ETH_ALEN], - sizeof(struct version_info)); - - } else { + offset = (FRAME_DESC_SZ + WLAN_HOST_MODE_LEN + + WLAN_MAC_MAGIC_WORD_LEN); + memcpy(common->mac_addr, &msg[offset], ETH_ALEN); + adapter->eeprom.length = + ((WLAN_MAC_MAGIC_WORD_LEN + 3) & (~3)); + adapter->eeprom.offset = WLAN_EEPROM_RFTYPE_ADDR; + if (rsi_eeprom_read(common)) { + rsi_dbg(ERR_ZONE, + "%s: Failed reading RF band\n", + __func__); common->fsm_state = FSM_CARD_NOT_READY; - break; + goto out; + } + common->fsm_state = FSM_EEPROM_READ_RF_TYPE; + } else if (common->fsm_state == FSM_EEPROM_READ_RF_TYPE) { + if ((msg[17] & 0x3) == 0x3) { + rsi_dbg(INIT_ZONE, "Dual band supported\n"); + common->band = NL80211_BAND_5GHZ; + common->num_supp_bands = 2; + } else if ((msg[17] & 0x3) == 0x1) { + rsi_dbg(INIT_ZONE, + "Only 2.4Ghz band supported\n"); + common->band = NL80211_BAND_2GHZ; + common->num_supp_bands = 1; } if (rsi_send_reset_mac(common)) goto out; - else - common->fsm_state = FSM_RESET_MAC_SENT; + common->fsm_state = FSM_RESET_MAC_SENT; } else { - rsi_dbg(ERR_ZONE, - "%s: Received eeprom mac addr in %d state\n", - __func__, common->fsm_state); + rsi_dbg(ERR_ZONE, "%s: Invalid EEPROM read type\n", + __func__); return 0; } break; @@ -1527,7 +1724,9 @@ static int rsi_handle_ta_confirm_type(struct rsi_common *common, return 0; } break; - + case WAKEUP_SLEEP_REQUEST: + rsi_dbg(INFO_ZONE, "Wakeup/Sleep confirmation.\n"); + return rsi_handle_ps_confirm(adapter, msg); default: rsi_dbg(INFO_ZONE, "%s: Invalid TA confirm pkt received\n", __func__); @@ -1590,20 +1789,34 @@ int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg) rsi_dbg(FSM_ZONE, "%s: Msg Len: %d, Msg Type: %4x\n", __func__, msg_len, msg_type); - if (msg_type == TA_CONFIRM_TYPE) { + switch (msg_type) { + case TA_CONFIRM_TYPE: return rsi_handle_ta_confirm_type(common, msg); - } else if (msg_type == CARD_READY_IND) { + case CARD_READY_IND: rsi_dbg(FSM_ZONE, "%s: Card ready indication received\n", __func__); return rsi_handle_card_ready(common, msg); - } else if (msg_type == TX_STATUS_IND) { + case TX_STATUS_IND: if (msg[15] == PROBEREQ_CONFIRM) { common->mgmt_q_block = false; rsi_dbg(FSM_ZONE, "%s: Probe confirm received\n", __func__); } - } else { - return rsi_mgmt_pkt_to_core(common, msg, msg_len, msg_type); + break; + case BEACON_EVENT_IND: + rsi_dbg(INFO_ZONE, "Beacon event\n"); + if (common->fsm_state != FSM_MAC_INIT_DONE) + return -1; + if (common->iface_down) + return -1; + if (!common->beacon_enabled) + return -1; + rsi_send_beacon(common); + break; + case RX_DOT11_MGMT: + return rsi_mgmt_pkt_to_core(common, msg, msg_len); + default: + rsi_dbg(INFO_ZONE, "Received packet type: 0x%x\n", msg_type); } return 0; } diff --git a/drivers/net/wireless/rsi/rsi_91x_ps.c b/drivers/net/wireless/rsi/rsi_91x_ps.c new file mode 100644 index 000000000000..48c79f035c59 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_91x_ps.c @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2014 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/etherdevice.h> +#include <linux/if.h> +#include <linux/version.h> +#include "rsi_debugfs.h" +#include "rsi_mgmt.h" +#include "rsi_common.h" +#include "rsi_ps.h" + +char *str_psstate(enum ps_state state) +{ + switch (state) { + case PS_NONE: + return "PS_NONE"; + case PS_DISABLE_REQ_SENT: + return "PS_DISABLE_REQ_SENT"; + case PS_ENABLE_REQ_SENT: + return "PS_ENABLE_REQ_SENT"; + case PS_ENABLED: + return "PS_ENABLED"; + default: + return "INVALID_STATE"; + } + return "INVALID_STATE"; +} + +static inline void rsi_modify_ps_state(struct rsi_hw *adapter, + enum ps_state nstate) +{ + rsi_dbg(INFO_ZONE, "PS state changed %s => %s\n", + str_psstate(adapter->ps_state), + str_psstate(nstate)); + + adapter->ps_state = nstate; +} + +void rsi_default_ps_params(struct rsi_hw *adapter) +{ + struct rsi_ps_info *ps_info = &adapter->ps_info; + + ps_info->enabled = true; + ps_info->sleep_type = RSI_SLEEP_TYPE_LP; + ps_info->tx_threshold = 0; + ps_info->rx_threshold = 0; + ps_info->tx_hysterisis = 0; + ps_info->rx_hysterisis = 0; + ps_info->monitor_interval = 0; + ps_info->listen_interval = RSI_DEF_LISTEN_INTERVAL; + ps_info->num_bcns_per_lis_int = 0; + ps_info->dtim_interval_duration = 0; + ps_info->num_dtims_per_sleep = 0; + ps_info->deep_sleep_wakeup_period = RSI_DEF_DS_WAKEUP_PERIOD; +} + +void rsi_enable_ps(struct rsi_hw *adapter) +{ + if (adapter->ps_state != PS_NONE) { + rsi_dbg(ERR_ZONE, + "%s: Cannot accept enable PS in %s state\n", + __func__, str_psstate(adapter->ps_state)); + return; + } + + if (rsi_send_ps_request(adapter, true)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to send PS request to device\n", + __func__); + return; + } + + rsi_modify_ps_state(adapter, PS_ENABLE_REQ_SENT); +} + +void rsi_disable_ps(struct rsi_hw *adapter) +{ + if (adapter->ps_state != PS_ENABLED) { + rsi_dbg(ERR_ZONE, + "%s: Cannot accept disable PS in %s state\n", + __func__, str_psstate(adapter->ps_state)); + return; + } + + if (rsi_send_ps_request(adapter, false)) { + rsi_dbg(ERR_ZONE, + "%s: Failed to send PS request to device\n", + __func__); + return; + } + + rsi_modify_ps_state(adapter, PS_DISABLE_REQ_SENT); +} + +void rsi_conf_uapsd(struct rsi_hw *adapter) +{ + int ret; + + if (adapter->ps_state != PS_ENABLED) + return; + + ret = rsi_send_ps_request(adapter, false); + if (!ret) + ret = rsi_send_ps_request(adapter, true); + if (ret) + rsi_dbg(ERR_ZONE, + "%s: Failed to send PS request to device\n", + __func__); +} + +int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg) +{ + u16 cfm_type = get_unaligned_le16(msg + PS_CONFIRM_INDEX); + + switch (cfm_type) { + case RSI_SLEEP_REQUEST: + if (adapter->ps_state == PS_ENABLE_REQ_SENT) + rsi_modify_ps_state(adapter, PS_ENABLED); + break; + case RSI_WAKEUP_REQUEST: + if (adapter->ps_state == PS_DISABLE_REQ_SENT) + rsi_modify_ps_state(adapter, PS_NONE); + break; + default: + rsi_dbg(ERR_ZONE, + "Invalid PS confirm type %x in state %s\n", + cfm_type, str_psstate(adapter->ps_state)); + return -1; + } + + return 0; +} + diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index e5ea99bb2dd8..8d3a4839b6ef 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -138,12 +138,15 @@ static int rsi_issue_sdiocommand(struct sdio_func *func, static void rsi_handle_interrupt(struct sdio_func *function) { struct rsi_hw *adapter = sdio_get_drvdata(function); + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED) return; - sdio_release_host(function); + + dev->sdio_irq_task = current; rsi_interrupt_handler(adapter); - sdio_claim_host(function); + dev->sdio_irq_task = NULL; } /** @@ -219,26 +222,18 @@ static void rsi_reset_card(struct sdio_func *pfunction) if (err) rsi_dbg(ERR_ZONE, "%s: CMD0 failed : %d\n", __func__, err); - if (!host->ocr_avail) { - /* Issue CMD5, arg = 0 */ - err = rsi_issue_sdiocommand(pfunction, - SD_IO_SEND_OP_COND, - 0, - (MMC_RSP_R4 | MMC_CMD_BCR), - &resp); - if (err) - rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n", - __func__, err); - host->ocr_avail = resp; - } + /* Issue CMD5, arg = 0 */ + err = rsi_issue_sdiocommand(pfunction, SD_IO_SEND_OP_COND, 0, + (MMC_RSP_R4 | MMC_CMD_BCR), &resp); + if (err) + rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n", __func__, err); + card->ocr = resp; /* Issue CMD5, arg = ocr. Wait till card is ready */ for (i = 0; i < 100; i++) { - err = rsi_issue_sdiocommand(pfunction, - SD_IO_SEND_OP_COND, - host->ocr_avail, - (MMC_RSP_R4 | MMC_CMD_BCR), - &resp); + err = rsi_issue_sdiocommand(pfunction, SD_IO_SEND_OP_COND, + card->ocr, + (MMC_RSP_R4 | MMC_CMD_BCR), &resp); if (err) { rsi_dbg(ERR_ZONE, "%s: CMD5 failed : %d\n", __func__, err); @@ -415,14 +410,16 @@ int rsi_sdio_read_register(struct rsi_hw *adapter, u8 fun_num = 0; int status; - sdio_claim_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_claim_host(dev->pfunction); if (fun_num == 0) *data = sdio_f0_readb(dev->pfunction, addr, &status); else *data = sdio_readb(dev->pfunction, addr, &status); - sdio_release_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_release_host(dev->pfunction); return status; } @@ -446,14 +443,16 @@ int rsi_sdio_write_register(struct rsi_hw *adapter, (struct rsi_91x_sdiodev *)adapter->rsi_dev; int status = 0; - sdio_claim_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_claim_host(dev->pfunction); if (function == 0) sdio_f0_writeb(dev->pfunction, *data, addr, &status); else sdio_writeb(dev->pfunction, *data, addr, &status); - sdio_release_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_release_host(dev->pfunction); return status; } @@ -498,11 +497,13 @@ static int rsi_sdio_read_register_multiple(struct rsi_hw *adapter, (struct rsi_91x_sdiodev *)adapter->rsi_dev; u32 status; - sdio_claim_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_claim_host(dev->pfunction); status = sdio_readsb(dev->pfunction, data, addr, count); - sdio_release_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_release_host(dev->pfunction); if (status != 0) rsi_dbg(ERR_ZONE, "%s: Synch Cmd53 read failed\n", __func__); @@ -540,11 +541,13 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, dev->write_fail++; } - sdio_claim_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_claim_host(dev->pfunction); status = sdio_writesb(dev->pfunction, addr, data, count); - sdio_release_host(dev->pfunction); + if (likely(dev->sdio_irq_task != current)) + sdio_release_host(dev->pfunction); if (status) { rsi_dbg(ERR_ZONE, "%s: Synch Cmd53 write failed %d\n", @@ -581,7 +584,6 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, } for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) { - memset(temp_buf, 0, block_size); memcpy(temp_buf, ta_firmware + offset, block_size); lsb_address = (u16)base_address; status = rsi_sdio_write_register_multiple @@ -857,7 +859,7 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter, sdio_release_host(pfunction); adapter->determine_event_timeout = rsi_sdio_determine_event_timeout; - adapter->check_hw_queue_status = rsi_sdio_read_buffer_status_register; + adapter->check_hw_queue_status = rsi_sdio_check_buffer_status; #ifdef CONFIG_RSI_DEBUGFS adapter->num_debugfs_entries = MAX_DEBUGFS_ENTRIES; @@ -941,6 +943,84 @@ fail: return 1; } +static void ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, + u16 len_in_bits) +{ + rsi_sdio_master_reg_write(adapter, RSI_GSPI_DATA_REG1, + ((addr << 6) | ((data >> 16) & 0xffff)), 2); + rsi_sdio_master_reg_write(adapter, RSI_GSPI_DATA_REG0, + (data & 0xffff), 2); + rsi_sdio_master_reg_write(adapter, RSI_GSPI_CTRL_REG0, + RSI_GSPI_CTRL_REG0_VALUE, 2); + rsi_sdio_master_reg_write(adapter, RSI_GSPI_CTRL_REG1, + ((len_in_bits - 1) | RSI_GSPI_TRIG), 2); + msleep(20); +} + +/*This function resets and re-initializes the chip.*/ +static void rsi_reset_chip(struct rsi_hw *adapter) +{ + __le32 data; + u8 sdio_interrupt_status = 0; + u8 request = 1; + int ret; + + rsi_dbg(INFO_ZONE, "Writing disable to wakeup register\n"); + ret = rsi_sdio_write_register(adapter, 0, SDIO_WAKEUP_REG, &request); + if (ret < 0) { + rsi_dbg(ERR_ZONE, + "%s: Failed to write SDIO wakeup register\n", __func__); + return; + } + msleep(20); + ret = rsi_sdio_read_register(adapter, RSI_FN1_INT_REGISTER, + &sdio_interrupt_status); + if (ret < 0) { + rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", + __func__); + return; + } + rsi_dbg(INFO_ZONE, "%s: Intr Status Register value = %d\n", + __func__, sdio_interrupt_status); + + /* Put Thread-Arch processor on hold */ + if (rsi_sdio_master_access_msword(adapter, TA_BASE_ADDR)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to set ms word to common reg\n", + __func__); + return; + } + + data = TA_HOLD_THREAD_VALUE; + if (rsi_sdio_write_register_multiple(adapter, TA_HOLD_THREAD_REG | + RSI_SD_REQUEST_MASTER, + (u8 *)&data, 4)) { + rsi_dbg(ERR_ZONE, + "%s: Unable to hold Thread-Arch processor threads\n", + __func__); + return; + } + + /* This msleep will ensure Thread-Arch processor to go to hold + * and any pending dma transfers to rf spi in device to finish. + */ + msleep(100); + + ulp_read_write(adapter, RSI_ULP_RESET_REG, RSI_ULP_WRITE_0, 32); + ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_1, RSI_ULP_WRITE_2, 32); + ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_2, RSI_ULP_WRITE_0, 32); + ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_1, RSI_ULP_WRITE_50, + 32); + ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_2, RSI_ULP_WRITE_0, + 32); + ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_ENABLE, + RSI_ULP_TIMER_ENABLE, 32); + /* This msleep will be sufficient for the ulp + * read write operations to complete for chip reset. + */ + msleep(500); +} + /** * rsi_disconnect() - This function performs the reverse of the probe function. * @pfunction: Pointer to the sdio_func structure. @@ -956,17 +1036,26 @@ static void rsi_disconnect(struct sdio_func *pfunction) return; dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; + sdio_claim_host(pfunction); + sdio_release_irq(pfunction); + sdio_release_host(pfunction); + mdelay(10); - dev->write_fail = 2; rsi_mac80211_detach(adapter); + mdelay(10); + + /* Reset Chip */ + rsi_reset_chip(adapter); - sdio_claim_host(pfunction); - sdio_release_irq(pfunction); - sdio_disable_func(pfunction); - rsi_91x_deinit(adapter); /* Resetting to take care of the case, where-in driver is re-loaded */ + sdio_claim_host(pfunction); rsi_reset_card(pfunction); + sdio_disable_func(pfunction); sdio_release_host(pfunction); + dev->write_fail = 2; + rsi_91x_deinit(adapter); + rsi_dbg(ERR_ZONE, "##### RSI SDIO device disconnected #####\n"); + } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index df2a63b1f15c..8e2a95c486b0 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -69,20 +69,37 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word) static int rsi_process_pkt(struct rsi_common *common) { struct rsi_hw *adapter = common->priv; + struct rsi_91x_sdiodev *dev = + (struct rsi_91x_sdiodev *)adapter->rsi_dev; u8 num_blks = 0; u32 rcv_pkt_len = 0; int status = 0; + u8 value = 0; - status = rsi_sdio_read_register(adapter, - SDIO_RX_NUM_BLOCKS_REG, - &num_blks); + num_blks = ((adapter->interrupt_status & 1) | + ((adapter->interrupt_status >> RECV_NUM_BLOCKS) << 1)); - if (status) { - rsi_dbg(ERR_ZONE, - "%s: Failed to read pkt length from the card:\n", - __func__); - return status; + if (!num_blks) { + status = rsi_sdio_read_register(adapter, + SDIO_RX_NUM_BLOCKS_REG, + &value); + if (status) { + rsi_dbg(ERR_ZONE, + "%s: Failed to read pkt length from the card:\n", + __func__); + return status; + } + num_blks = value & 0x1f; + } + + if (dev->write_fail == 2) + rsi_sdio_ack_intr(common->priv, (1 << MSDU_PKT_PENDING)); + + if (unlikely(!num_blks)) { + dev->write_fail = 2; + return -1; } + rcv_pkt_len = (num_blks * 256); common->rx_data_pkt = kmalloc(rcv_pkt_len, GFP_KERNEL); @@ -213,7 +230,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) dev->rx_info.sdio_int_counter++; do { - mutex_lock(&common->tx_rxlock); + mutex_lock(&common->rx_lock); status = rsi_sdio_read_register(common->priv, RSI_FN1_INT_REGISTER, &isr_status); @@ -221,14 +238,15 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Failed to Read Intr Status Register\n", __func__); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } + adapter->interrupt_status = isr_status; if (isr_status == 0) { rsi_set_event(&common->tx_thread.event); dev->rx_info.sdio_intr_status_zero++; - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } @@ -241,10 +259,12 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) switch (isr_type) { case BUFFER_AVAILABLE: - dev->rx_info.watch_bufferfull_count = 0; - dev->rx_info.buffer_full = false; - dev->rx_info.semi_buffer_full = false; - dev->rx_info.mgmt_buffer_full = false; + status = rsi_sdio_check_buffer_status(adapter, + 0); + if (status < 0) + rsi_dbg(ERR_ZONE, + "%s: Failed to check buffer status\n", + __func__); rsi_sdio_ack_intr(common->priv, (1 << PKT_BUFF_AVAILABLE)); rsi_set_event(&common->tx_thread.event); @@ -252,7 +272,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) rsi_dbg(ISR_ZONE, "%s: ==> BUFFER_AVAILABLE <==\n", __func__); - dev->rx_info.buf_available_counter++; + dev->buff_status_updated = true; break; case FIRMWARE_ASSERT_IND: @@ -286,7 +306,7 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) rsi_dbg(ERR_ZONE, "%s: Failed to read pkt\n", __func__); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } break; @@ -301,28 +321,28 @@ void rsi_interrupt_handler(struct rsi_hw *adapter) } isr_status ^= BIT(isr_type - 1); } while (isr_status); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); } while (1); } -/** - * rsi_sdio_read_buffer_status_register() - This function is used to the read - * buffer status register and set - * relevant fields in - * rsi_91x_sdiodev struct. - * @adapter: Pointer to the driver hw structure. - * @q_num: The Q number whose status is to be found. - * - * Return: status: -1 on failure or else queue full/stop is indicated. +/* This function is used to read buffer status register and + * set relevant fields in rsi_91x_sdiodev struct. */ -int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num) +int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num) { struct rsi_common *common = adapter->priv; struct rsi_91x_sdiodev *dev = (struct rsi_91x_sdiodev *)adapter->rsi_dev; u8 buf_status = 0; int status = 0; + static int counter = 4; + + if (!dev->buff_status_updated && counter) { + counter--; + goto out; + } + dev->buff_status_updated = false; status = rsi_sdio_read_register(common->priv, RSI_DEVICE_BUFFER_STATUS_REGISTER, &buf_status); @@ -357,10 +377,16 @@ int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num) dev->rx_info.semi_buffer_full = false; } + if (dev->rx_info.mgmt_buffer_full || dev->rx_info.buf_full_counter) + counter = 1; + else + counter = 4; + +out: if ((q_num == MGMT_SOFT_Q) && (dev->rx_info.mgmt_buffer_full)) return QUEUE_FULL; - if (dev->rx_info.buffer_full) + if ((q_num < MGMT_SOFT_Q) && (dev->rx_info.buffer_full)) return QUEUE_FULL; return QUEUE_NOT_FULL; diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index bcd7f454ef30..81df09dd2636 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -29,19 +29,24 @@ * Return: status: 0 on success, a negative error code on failure. */ static int rsi_usb_card_write(struct rsi_hw *adapter, - void *buf, + u8 *buf, u16 len, u8 endpoint) { struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; int status; - s32 transfer; + u8 *seg = dev->tx_buffer; + int transfer; + int ep = dev->bulkout_endpoint_addr[endpoint - 1]; + memset(seg, 0, len + RSI_USB_TX_HEAD_ROOM); + memcpy(seg + RSI_USB_TX_HEAD_ROOM, buf, len); + len += RSI_USB_TX_HEAD_ROOM; + transfer = len; status = usb_bulk_msg(dev->usbdev, - usb_sndbulkpipe(dev->usbdev, - dev->bulkout_endpoint_addr[endpoint - 1]), - buf, - len, + usb_sndbulkpipe(dev->usbdev, ep), + (void *)seg, + (int)len, &transfer, HZ * 5); @@ -68,23 +73,19 @@ static int rsi_write_multiple(struct rsi_hw *adapter, u8 *data, u32 count) { - struct rsi_91x_usbdev *dev = (struct rsi_91x_usbdev *)adapter->rsi_dev; - u8 *seg = dev->tx_buffer; + struct rsi_91x_usbdev *dev = + (struct rsi_91x_usbdev *)adapter->rsi_dev; - if (dev->write_fail) - return 0; + if (!adapter) + return -ENODEV; - if (endpoint == MGMT_EP) { - memset(seg, 0, RSI_USB_TX_HEAD_ROOM); - memcpy(seg + RSI_USB_TX_HEAD_ROOM, data, count); - } else { - seg = ((u8 *)data - RSI_USB_TX_HEAD_ROOM); - } + if (endpoint == 0) + return -EINVAL; - return rsi_usb_card_write(adapter, - seg, - count + RSI_USB_TX_HEAD_ROOM, - endpoint); + if (dev->write_fail) + return -ENETDOWN; + + return rsi_usb_card_write(adapter, data, count, endpoint); } /** @@ -161,10 +162,13 @@ static int rsi_usb_reg_read(struct usb_device *usbdev, u8 *buf; int status = -ENOMEM; - buf = kmalloc(0x04, GFP_KERNEL); + buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); if (!buf) return status; + if (len > RSI_USB_CTRL_BUF_SIZE) + return -EINVAL; + status = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), USB_VENDOR_REGISTER_READ, @@ -203,10 +207,13 @@ static int rsi_usb_reg_write(struct usb_device *usbdev, u8 *usb_reg_buf; int status = -ENOMEM; - usb_reg_buf = kmalloc(0x04, GFP_KERNEL); + usb_reg_buf = kmalloc(RSI_USB_CTRL_BUF_SIZE, GFP_KERNEL); if (!usb_reg_buf) return status; + if (len > RSI_USB_CTRL_BUF_SIZE) + return -EINVAL; + usb_reg_buf[0] = (value & 0x00ff); usb_reg_buf[1] = (value & 0xff00) >> 8; usb_reg_buf[2] = 0x0; @@ -380,10 +387,11 @@ static int rsi_usb_host_intf_write_pkt(struct rsi_hw *adapter, u8 *pkt, u32 len) { - u32 queueno = ((pkt[1] >> 4) & 0xf); + u32 queueno = ((pkt[1] >> 4) & 0x7); u8 endpoint; - endpoint = ((queueno == RSI_WIFI_MGMT_Q) ? MGMT_EP : DATA_EP); + endpoint = ((queueno == RSI_WIFI_MGMT_Q || queueno == RSI_WIFI_DATA_Q || + queueno == RSI_COEX_Q) ? WLAN_EP : BT_EP); return rsi_write_multiple(adapter, endpoint, @@ -396,8 +404,15 @@ static int rsi_usb_master_reg_read(struct rsi_hw *adapter, u32 reg, { struct usb_device *usbdev = ((struct rsi_91x_usbdev *)adapter->rsi_dev)->usbdev; + u16 temp; + int ret; + + ret = rsi_usb_reg_read(usbdev, reg, &temp, len); + if (ret < 0) + return ret; + *value = temp; - return rsi_usb_reg_read(usbdev, reg, (u16 *)value, len); + return 0; } static int rsi_usb_master_reg_write(struct rsi_hw *adapter, @@ -424,7 +439,6 @@ static int rsi_usb_load_data_master_write(struct rsi_hw *adapter, rsi_dbg(INFO_ZONE, "num_blocks: %d\n", num_blocks); for (cur_indx = 0, i = 0; i < num_blocks; i++, cur_indx += block_size) { - memset(temp_buf, 0, block_size); memcpy(temp_buf, ta_firmware + cur_indx, block_size); status = rsi_usb_write_register_multiple(adapter, base_address, (u8 *)(temp_buf), @@ -558,6 +572,77 @@ fail_tx: return status; } +static int usb_ulp_read_write(struct rsi_hw *adapter, u16 addr, u32 data, + u16 len_in_bits) +{ + int ret; + + ret = rsi_usb_master_reg_write + (adapter, RSI_GSPI_DATA_REG1, + ((addr << 6) | ((data >> 16) & 0xffff)), 2); + if (ret < 0) + return ret; + + ret = rsi_usb_master_reg_write(adapter, RSI_GSPI_DATA_REG0, + (data & 0xffff), 2); + if (ret < 0) + return ret; + + /* Initializing GSPI for ULP read/writes */ + rsi_usb_master_reg_write(adapter, RSI_GSPI_CTRL_REG0, + RSI_GSPI_CTRL_REG0_VALUE, 2); + + ret = rsi_usb_master_reg_write(adapter, RSI_GSPI_CTRL_REG1, + ((len_in_bits - 1) | RSI_GSPI_TRIG), 2); + if (ret < 0) + return ret; + + msleep(20); + + return 0; +} + +static int rsi_reset_card(struct rsi_hw *adapter) +{ + int ret; + + rsi_dbg(INFO_ZONE, "Resetting Card...\n"); + rsi_usb_master_reg_write(adapter, RSI_TA_HOLD_REG, 0xE, 4); + + /* This msleep will ensure Thread-Arch processor to go to hold + * and any pending dma transfers to rf in device to finish. + */ + msleep(100); + + ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_1, + RSI_ULP_WRITE_2, 32); + if (ret < 0) + goto fail; + ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_2, + RSI_ULP_WRITE_0, 32); + if (ret < 0) + goto fail; + ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_1, + RSI_ULP_WRITE_50, 32); + if (ret < 0) + goto fail; + ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_DELAY_TIMER_2, + RSI_ULP_WRITE_0, 32); + if (ret < 0) + goto fail; + ret = usb_ulp_read_write(adapter, RSI_WATCH_DOG_TIMER_ENABLE, + RSI_ULP_TIMER_ENABLE, 32); + if (ret < 0) + goto fail; + + rsi_dbg(INFO_ZONE, "Reset card done\n"); + return ret; + +fail: + rsi_dbg(ERR_ZONE, "Reset card failed\n"); + return ret; +} + /** * rsi_probe() - This function is called by kernel when the driver provided * Vendor and device IDs are matched. All the initialization @@ -641,6 +726,7 @@ static void rsi_disconnect(struct usb_interface *pfunction) return; rsi_mac80211_detach(adapter); + rsi_reset_card(adapter); rsi_deinit_usb_interface(adapter); rsi_91x_deinit(adapter); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index d3e0a07604a6..465692b3c351 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -37,14 +37,14 @@ void rsi_usb_rx_thread(struct rsi_common *common) if (atomic_read(&dev->rx_thread.thread_done)) goto out; - mutex_lock(&common->tx_rxlock); + mutex_lock(&common->rx_lock); status = rsi_read_pkt(common, 0); if (status) { rsi_dbg(ERR_ZONE, "%s: Failed To read data", __func__); - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); return; } - mutex_unlock(&common->tx_rxlock); + mutex_unlock(&common->rx_lock); rsi_reset_event(&dev->rx_thread.event); if (adapter->rx_urb_submit(adapter)) { rsi_dbg(ERR_ZONE, diff --git a/drivers/net/wireless/rsi/rsi_common.h b/drivers/net/wireless/rsi/rsi_common.h index 44349696f5de..e579d694d13c 100644 --- a/drivers/net/wireless/rsi/rsi_common.h +++ b/drivers/net/wireless/rsi/rsi_common.h @@ -83,4 +83,5 @@ u16 rsi_get_connected_channel(struct rsi_hw *adapter); struct rsi_hw *rsi_91x_init(void); void rsi_91x_deinit(struct rsi_hw *adapter); int rsi_read_pkt(struct rsi_common *common, s32 rcv_pkt_len); +struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr); #endif diff --git a/drivers/net/wireless/rsi/rsi_hal.h b/drivers/net/wireless/rsi/rsi_hal.h index 902dc540849c..7c145053da6d 100644 --- a/drivers/net/wireless/rsi/rsi_hal.h +++ b/drivers/net/wireless/rsi/rsi_hal.h @@ -52,6 +52,39 @@ #define FW_LOADING_SUCCESSFUL 'S' #define LOADING_INITIATED '1' +#define RSI_ULP_RESET_REG 0x161 +#define RSI_WATCH_DOG_TIMER_1 0x16c +#define RSI_WATCH_DOG_TIMER_2 0x16d +#define RSI_WATCH_DOG_DELAY_TIMER_1 0x16e +#define RSI_WATCH_DOG_DELAY_TIMER_2 0x16f +#define RSI_WATCH_DOG_TIMER_ENABLE 0x170 + +#define RSI_ULP_WRITE_0 00 +#define RSI_ULP_WRITE_2 02 +#define RSI_ULP_WRITE_50 50 + +#define RSI_RESTART_WDT BIT(11) +#define RSI_BYPASS_ULP_ON_WDT BIT(1) + +#define RSI_ULP_TIMER_ENABLE ((0xaa000) | RSI_RESTART_WDT | \ + RSI_BYPASS_ULP_ON_WDT) +#define RSI_RF_SPI_PROG_REG_BASE_ADDR 0x40080000 + +#define RSI_GSPI_CTRL_REG0 (RSI_RF_SPI_PROG_REG_BASE_ADDR) +#define RSI_GSPI_CTRL_REG1 (RSI_RF_SPI_PROG_REG_BASE_ADDR + 0x2) +#define RSI_GSPI_DATA_REG0 (RSI_RF_SPI_PROG_REG_BASE_ADDR + 0x4) +#define RSI_GSPI_DATA_REG1 (RSI_RF_SPI_PROG_REG_BASE_ADDR + 0x6) +#define RSI_GSPI_DATA_REG2 (RSI_RF_SPI_PROG_REG_BASE_ADDR + 0x8) + +#define RSI_GSPI_CTRL_REG0_VALUE 0x340 + +#define RSI_GSPI_DMA_MODE BIT(13) + +#define RSI_GSPI_2_ULP BIT(12) +#define RSI_GSPI_TRIG BIT(7) +#define RSI_GSPI_READ BIT(6) +#define RSI_GSPI_RF_SPI_ACTIVE BIT(8) + /* Boot loader commands */ #define SEND_RPS_FILE '2' @@ -66,6 +99,8 @@ #define RSI_DEV_OPMODE_WIFI_ALONE 1 #define RSI_DEV_COEX_MODE_WIFI_ALONE 1 +#define BBP_INFO_40MHZ 0x6 + struct bl_header { __le32 flags; __le32 image_no; @@ -79,6 +114,37 @@ struct ta_metadata { unsigned int address; }; +struct rsi_mgmt_desc { + __le16 len_qno; + u8 frame_type; + u8 misc_flags; + u8 xtend_desc_size; + u8 header_len; + __le16 frame_info; + u8 rate_info; + u8 reserved1; + __le16 bbp_info; + __le16 seq_ctrl; + u8 reserved2; + u8 sta_id; +} __packed; + +struct rsi_data_desc { + __le16 len_qno; + u8 cfm_frame_type; + u8 misc_flags; + u8 xtend_desc_size; + u8 header_len; + __le16 frame_info; + __le16 rate_info; + __le16 bbp_info; + __le16 mac_flags; + u8 qid_tid; + u8 sta_id; +} __packed; + int rsi_hal_device_init(struct rsi_hw *adapter); +int rsi_prepare_beacon(struct rsi_common *common, struct sk_buff *skb); +int rsi_send_pkt_to_bus(struct rsi_common *common, struct sk_buff *skb); #endif diff --git a/drivers/net/wireless/rsi/rsi_main.h b/drivers/net/wireless/rsi/rsi_main.h index f3985250b593..2c18dde633ea 100644 --- a/drivers/net/wireless/rsi/rsi_main.h +++ b/drivers/net/wireless/rsi/rsi_main.h @@ -21,6 +21,17 @@ #include <linux/skbuff.h> #include <net/mac80211.h> +struct rsi_sta { + struct ieee80211_sta *sta; + s16 sta_id; + u16 seq_start[IEEE80211_NUM_TIDS]; + bool start_tx_aggr[IEEE80211_NUM_TIDS]; +}; + +struct rsi_hw; + +#include "rsi_ps.h" + #define ERR_ZONE BIT(0) /* For Error Msgs */ #define INFO_ZONE BIT(1) /* For General Status Msgs */ #define INIT_ZONE BIT(2) /* For Driver Init Seq Msgs */ @@ -37,10 +48,13 @@ enum RSI_FSM_STATES { FSM_COMMON_DEV_PARAMS_SENT, FSM_BOOT_PARAMS_SENT, FSM_EEPROM_READ_MAC_ADDR, + FSM_EEPROM_READ_RF_TYPE, FSM_RESET_MAC_SENT, FSM_RADIO_CAPS_SENT, FSM_BB_RF_PROG_SENT, - FSM_MAC_INIT_DONE + FSM_MAC_INIT_DONE, + + NUM_FSM_STATES }; extern u32 rsi_zone_enabled; @@ -51,18 +65,24 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define IEEE80211_ADDR_LEN 6 #define FRAME_DESC_SZ 16 #define MIN_802_11_HDR_LEN 24 +#define RSI_DEF_KEEPALIVE 90 #define DATA_QUEUE_WATER_MARK 400 #define MIN_DATA_QUEUE_WATER_MARK 300 #define MULTICAST_WATER_MARK 200 #define MAC_80211_HDR_FRAME_CONTROL 0 #define WME_NUM_AC 4 -#define NUM_SOFT_QUEUES 5 -#define MAX_HW_QUEUES 8 +#define NUM_SOFT_QUEUES 6 +#define MAX_HW_QUEUES 12 #define INVALID_QUEUE 0xff #define MAX_CONTINUOUS_VO_PKTS 8 #define MAX_CONTINUOUS_VI_PKTS 4 +/* Hardware queue info */ +#define BROADCAST_HW_Q 9 +#define MGMT_HW_Q 10 +#define BEACON_HW_Q 11 + /* Queue information */ #define RSI_COEX_Q 0x0 #define RSI_WIFI_MGMT_Q 0x4 @@ -70,6 +90,7 @@ extern __printf(2, 3) void rsi_dbg(u32 zone, const char *fmt, ...); #define IEEE80211_MGMT_FRAME 0x00 #define IEEE80211_CTL_FRAME 0x04 +#define RSI_MAX_ASSOC_STAS 32 #define IEEE80211_QOS_TID 0x0f #define IEEE80211_NONQOS_TID 16 @@ -102,6 +123,7 @@ struct skb_info { u16 channel; s8 tid; s8 sta_id; + u8 internal_hdr_size; }; enum edca_queue { @@ -109,7 +131,8 @@ enum edca_queue { BE_Q, VI_Q, VO_Q, - MGMT_SOFT_Q + MGMT_SOFT_Q, + MGMT_BEACON_Q }; struct security_info { @@ -126,8 +149,8 @@ struct wmm_qinfo { }; struct transmit_q_stats { - u32 total_tx_pkt_send[NUM_EDCA_QUEUES + 1]; - u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 1]; + u32 total_tx_pkt_send[NUM_EDCA_QUEUES + 2]; + u32 total_tx_pkt_freed[NUM_EDCA_QUEUES + 2]; }; struct vif_priv { @@ -155,7 +178,18 @@ struct cqm_info { u32 rssi_hyst; }; -struct rsi_hw; +struct xtended_desc { + u8 confirm_frame_type; + u8 retry_cnt; + u16 reserved; +}; + +enum rsi_dfs_regions { + RSI_REGION_FCC = 0, + RSI_REGION_ETSI, + RSI_REGION_TELEC, + RSI_REGION_WORLD +}; struct rsi_common { struct rsi_hw *priv; @@ -166,15 +200,18 @@ struct rsi_common { struct version_info fw_ver; struct rsi_thread tx_thread; - struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 1]; + struct sk_buff_head tx_queue[NUM_EDCA_QUEUES + 2]; /* Mutex declaration */ struct mutex mutex; - /* Mutex used between tx/rx threads */ - struct mutex tx_rxlock; + /* Mutex used for tx thread */ + struct mutex tx_lock; + /* Mutex used for rx thread */ + struct mutex rx_lock; u8 endpoint; /* Channel/band related */ u8 band; + u8 num_supp_bands; u8 channel_width; u16 rts_threshold; @@ -216,11 +253,23 @@ struct rsi_common { u16 oper_mode; u8 lp_ps_handshake_mode; u8 ulp_ps_handshake_mode; + u8 uapsd_bitmap; u8 rf_power_val; u8 wlan_rf_power_mode; u8 obm_ant_sel_val; int tx_power; u8 ant_in_use; + + u16 beacon_interval; + u8 dtim_cnt; + + /* AP mode parameters */ + u8 beacon_enabled; + u16 beacon_cnt; + struct rsi_sta stations[RSI_MAX_ASSOC_STAS + 1]; + int num_stations; + int max_stations; + struct ieee80211_key_conf *key; }; enum host_intf { @@ -228,6 +277,19 @@ enum host_intf { RSI_HOST_INTF_USB }; +struct eepromrw_info { + u32 offset; + u32 length; + u8 write; + u16 eeprom_erase; + u8 data[480]; +}; + +struct eeprom_read { + u16 length; + u16 off_set; +}; + struct rsi_hw { struct rsi_common *priv; u8 device_model; @@ -241,6 +303,9 @@ struct rsi_hw { enum host_intf rsi_host_intf; u16 block_size; + enum ps_state ps_state; + struct rsi_ps_info ps_info; + spinlock_t ps_lock; /*To protect power save config*/ u32 usb_buffer_status_reg; #ifdef CONFIG_RSI_DEBUGFS struct rsi_debugfs *dfsentry; @@ -250,7 +315,10 @@ struct rsi_hw { struct timer_list bl_cmd_timer; bool blcmd_timer_expired; u32 flash_capacity; + struct eepromrw_info eeprom; + u32 interrupt_status; u8 dfs_region; + char country[2]; void *rsi_dev; struct rsi_host_intf_ops *host_intf_ops; int (*check_hw_queue_status)(struct rsi_hw *adapter, u8 q_num); diff --git a/drivers/net/wireless/rsi/rsi_mgmt.h b/drivers/net/wireless/rsi/rsi_mgmt.h index dcb6db728cbd..c6e1fa669a27 100644 --- a/drivers/net/wireless/rsi/rsi_mgmt.h +++ b/drivers/net/wireless/rsi/rsi_mgmt.h @@ -43,11 +43,13 @@ #define WLAN_HOST_MODE_LEN 0x04 #define WLAN_FW_VERSION_LEN 0x08 #define MAGIC_WORD 0x5A +#define WLAN_EEPROM_RFTYPE_ADDR 424 /* Receive Frame Types */ #define TA_CONFIRM_TYPE 0x01 #define RX_DOT11_MGMT 0x02 #define TX_STATUS_IND 0x04 +#define BEACON_EVENT_IND 0x08 #define PROBEREQ_CONFIRM 2 #define CARD_READY_IND 0x00 @@ -61,8 +63,20 @@ #define BBP_REG_WRITE 0 #define RF_RESET_ENABLE BIT(3) #define RATE_INFO_ENABLE BIT(0) +#define MORE_DATA_PRESENT BIT(1) #define RSI_BROADCAST_PKT BIT(9) - +#define RSI_DESC_REQUIRE_CFM_TO_HOST BIT(2) +#define RSI_ADD_DELTA_TSF_VAP_ID BIT(3) +#define RSI_FETCH_RETRY_CNT_FRM_HST BIT(4) +#define RSI_QOS_ENABLE BIT(12) +#define RSI_REKEY_PURPOSE BIT(13) +#define RSI_ENCRYPT_PKT BIT(15) +#define RSI_SET_PS_ENABLE BIT(12) + +#define RSI_CMDDESC_40MHZ BIT(4) +#define RSI_CMDDESC_UPPER_20_ENABLE BIT(5) +#define RSI_CMDDESC_LOWER_20_ENABLE BIT(6) +#define RSI_CMDDESC_FULL_40_ENABLE (BIT(5) | BIT(6)) #define UPPER_20_ENABLE (0x2 << 12) #define LOWER_20_ENABLE (0x4 << 12) #define FULL40M_ENABLE 0x6 @@ -120,6 +134,7 @@ #define RSI_RATE_MCS6 0x106 #define RSI_RATE_MCS7 0x107 #define RSI_RATE_MCS7_SG 0x307 +#define RSI_RATE_AUTO 0xffff #define BW_20MHZ 0 #define BW_40MHZ 1 @@ -143,6 +158,8 @@ #define ANTENNA_SEL_INT 0x02 /* RF_OUT_2 / Integerated */ #define ANTENNA_SEL_UFL 0x03 /* RF_OUT_1 / U.FL */ +#define ANTENNA_MASK_VALUE 0x00ff +#define ANTENNA_SEL_TYPE 1 /* Rx filter word definitions */ #define PROMISCOUS_MODE BIT(0) @@ -153,9 +170,38 @@ #define ALLOW_CONN_PEER_MGMT_WHILE_BUF_FULL BIT(5) #define DISALLOW_BROADCAST_DATA BIT(6) +#define RSI_MPDU_DENSITY 0x8 +#define RSI_CHAN_RADAR BIT(7) +#define RSI_BEACON_INTERVAL 200 +#define RSI_DTIM_COUNT 2 + +#define RSI_PS_DISABLE_IND BIT(15) +#define RSI_PS_ENABLE 1 +#define RSI_PS_DISABLE 0 +#define RSI_DEEP_SLEEP 1 +#define RSI_CONNECTED_SLEEP 2 +#define RSI_SLEEP_REQUEST 1 +#define RSI_WAKEUP_REQUEST 2 + +#define RSI_IEEE80211_UAPSD_QUEUES \ + (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO | \ + IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ + IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) + +#define RSI_DATA_DESC_MAC_BBP_INFO BIT(0) +#define RSI_DATA_DESC_NO_ACK_IND BIT(9) +#define RSI_DATA_DESC_QOS_EN BIT(12) +#define RSI_DATA_DESC_NORMAL_FRAME 0x00 +#define RSI_DATA_DESC_DTIM_BEACON_GATED_FRAME BIT(10) +#define RSI_DATA_DESC_BEACON_FRAME BIT(11) +#define RSI_DATA_DESC_DTIM_BEACON (BIT(10) | BIT(11)) +#define RSI_DATA_DESC_INSERT_TSF BIT(15) +#define RSI_DATA_DESC_INSERT_SEQ_NO BIT(2) + enum opmode { - STA_OPMODE = 1, - AP_OPMODE = 2 + AP_OPMODE = 0, + STA_OPMODE, }; enum vap_status { @@ -164,6 +210,10 @@ enum vap_status { VAP_UPDATE = 3 }; +enum peer_type { + PEER_TYPE_AP, + PEER_TYPE_STA, +}; extern struct ieee80211_rate rsi_rates[12]; extern const u16 rsi_mcsrates[8]; @@ -192,7 +242,7 @@ enum cmd_frame_type { AUTO_RATE_IND, BOOTUP_PARAMS_REQUEST, VAP_CAPABILITIES, - EEPROM_READ_TYPE , + EEPROM_READ, EEPROM_WRITE, GPIO_PIN_CONFIG , SET_RX_FILTER, @@ -205,6 +255,7 @@ enum cmd_frame_type { CW_MODE_REQ, PER_CMD_PKT, ANT_SEL_FRAME = 0x20, + VAP_DYNAMIC_UPDATE = 0x27, COMMON_DEV_CONFIG = 0x28, RADIO_PARAMS_UPDATE = 0x29 }; @@ -213,13 +264,52 @@ struct rsi_mac_frame { __le16 desc_word[8]; } __packed; +#define PWR_SAVE_WAKEUP_IND BIT(0) +#define TCP_CHECK_SUM_OFFLOAD BIT(1) +#define CONFIRM_REQUIRED_TO_HOST BIT(2) +#define ADD_DELTA_TSF BIT(3) +#define FETCH_RETRY_CNT_FROM_HOST_DESC BIT(4) +#define EOSP_INDICATION BIT(5) +#define REQUIRE_TSF_SYNC_CONFIRM BIT(6) +#define ENCAP_MGMT_PKT BIT(7) +#define DESC_IMMEDIATE_WAKEUP BIT(15) + +struct rsi_cmd_desc_dword0 { + __le16 len_qno; + u8 frame_type; + u8 misc_flags; +}; + +struct rsi_cmd_desc_dword1 { + u8 xtend_desc_size; + u8 reserved1; + __le16 reserved2; +}; + +struct rsi_cmd_desc_dword2 { + __le32 pkt_info; /* Packet specific data */ +}; + +struct rsi_cmd_desc_dword3 { + __le16 token; + u8 qid_tid; + u8 sta_id; +}; + +struct rsi_cmd_desc { + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword1 desc_dword1; + struct rsi_cmd_desc_dword2 desc_dword2; + struct rsi_cmd_desc_dword3 desc_dword3; +}; + struct rsi_boot_params { __le16 desc_word[8]; struct bootup_params bootup_params; } __packed; struct rsi_peer_notify { - __le16 desc_word[8]; + struct rsi_cmd_desc desc; u8 mac_addr[6]; __le16 command; __le16 mpdu_density; @@ -227,31 +317,116 @@ struct rsi_peer_notify { __le32 sta_flags; } __packed; +/* Aggregation params flags */ +#define RSI_AGGR_PARAMS_TID_MASK 0xf +#define RSI_AGGR_PARAMS_START BIT(4) +#define RSI_AGGR_PARAMS_RX_AGGR BIT(5) +struct rsi_aggr_params { + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword0 desc_dword1; + __le16 seq_start; + __le16 baw_size; + __le16 token; + u8 aggr_params; + u8 peer_id; +} __packed; + +struct rsi_bb_rf_prog { + struct rsi_cmd_desc_dword0 desc_dword0; + __le16 reserved1; + u8 rf_power_mode; + u8 reserved2; + u8 endpoint; + u8 reserved3; + __le16 reserved4; + __le16 reserved5; + __le16 flags; +} __packed; + +struct rsi_chan_config { + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword1 desc_dword1; + u8 channel_number; + u8 antenna_gain_offset_2g; + u8 antenna_gain_offset_5g; + u8 channel_width; + __le16 tx_power; + u8 region_rftype; + u8 flags; +} __packed; + struct rsi_vap_caps { - __le16 desc_word[8]; + struct rsi_cmd_desc_dword0 desc_dword0; + u8 reserved1; + u8 status; + __le16 reserved2; + u8 vif_type; + u8 channel_bw; + __le16 antenna_info; + u8 radioid_macid; + u8 vap_id; + __le16 reserved3; u8 mac_addr[6]; __le16 keep_alive_period; u8 bssid[6]; - __le16 reserved; + __le16 reserved4; __le32 flags; __le16 frag_threshold; __le16 rts_threshold; __le32 default_mgmt_rate; - __le32 default_ctrl_rate; + __le16 default_ctrl_rate; + __le16 ctrl_rate_flags; __le32 default_data_rate; __le16 beacon_interval; __le16 dtim_period; + __le16 beacon_miss_threshold; } __packed; +struct rsi_ant_sel_frame { + struct rsi_cmd_desc_dword0 desc_dword0; + u8 reserved; + u8 sub_frame_type; + __le16 ant_value; + __le32 reserved1; + __le32 reserved2; +} __packed; + +struct rsi_dynamic_s { + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword1 desc_dword1; + struct rsi_cmd_desc_dword2 desc_dword2; + struct rsi_cmd_desc_dword3 desc_dword3; + struct framebody { + __le16 data_rate; + __le16 mgmt_rate; + __le16 keep_alive_period; + } frame_body; +} __packed; + +/* Key descriptor flags */ +#define RSI_KEY_TYPE_BROADCAST BIT(1) +#define RSI_WEP_KEY BIT(2) +#define RSI_WEP_KEY_104 BIT(3) +#define RSI_CIPHER_WPA BIT(4) +#define RSI_CIPHER_TKIP BIT(5) +#define RSI_KEY_MODE_AP BIT(7) +#define RSI_PROTECT_DATA_FRAMES BIT(13) +#define RSI_KEY_ID_MASK 0xC0 +#define RSI_KEY_ID_OFFSET 14 struct rsi_set_key { - __le16 desc_word[8]; + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword1 desc_dword1; + __le16 key_desc; + __le32 bpn; + u8 sta_id; + u8 vap_id; u8 key[4][32]; u8 tx_mic_key[8]; u8 rx_mic_key[8]; } __packed; struct rsi_auto_rate { - __le16 desc_word[8]; + struct rsi_cmd_desc desc; __le16 failure_limit; __le16 initial_boundary; __le16 max_threshold_limt; @@ -262,6 +437,19 @@ struct rsi_auto_rate { __le16 supported_rates[40]; } __packed; +#define QUIET_INFO_VALID BIT(0) +#define QUIET_ENABLE BIT(1) +struct rsi_block_unblock_data { + struct rsi_cmd_desc_dword0 desc_dword0; + u8 xtend_desc_size; + u8 host_quiet_info; + __le16 reserved; + __le16 block_q_bitmap; + __le16 unblock_q_bitmap; + __le16 token; + __le16 flush_q_bitmap; +} __packed; + struct qos_params { __le16 cont_win_min_q; __le16 cont_win_max_q; @@ -270,7 +458,14 @@ struct qos_params { } __packed; struct rsi_radio_caps { - __le16 desc_word[8]; + struct rsi_cmd_desc_dword0 desc_dword0; + struct rsi_cmd_desc_dword0 desc_dword1; + u8 channel_num; + u8 rf_model; + __le16 ppe_ack_rate; + __le16 mode_11j; + u8 radio_cfg_info; + u8 radio_info; struct qos_params qos_params[MAX_HW_QUEUES]; u8 num_11n_rates; u8 num_11ac_rates; @@ -353,6 +548,34 @@ struct rsi_config_vals { u8 reserved2[16]; } __packed; +/* Packet info flags */ +#define RSI_EEPROM_HDR_SIZE_OFFSET 8 +#define RSI_EEPROM_HDR_SIZE_MASK 0x300 +#define RSI_EEPROM_LEN_OFFSET 20 +#define RSI_EEPROM_LEN_MASK 0xFFF00000 + +struct rsi_eeprom_read_frame { + __le16 len_qno; + u8 pkt_type; + u8 misc_flags; + __le32 pkt_info; + __le32 eeprom_offset; + __le16 delay_ms; + __le16 reserved3; +} __packed; + +struct rsi_request_ps { + struct rsi_cmd_desc desc; + struct ps_sleep_params ps_sleep; + u8 ps_mimic_support; + u8 ps_uapsd_acs; + u8 ps_uapsd_wakeup_period; + u8 reserved; + __le32 ps_listen_interval; + __le32 ps_dtim_interval_duration; + __le16 ps_num_dtim_intervals; +} __packed; + static inline u32 rsi_get_queueno(u8 *addr, u16 offset) { return (le16_to_cpu(*(__le16 *)&addr[offset]) & 0x7000) >> 12; @@ -385,16 +608,19 @@ static inline void rsi_set_len_qno(__le16 *addr, u16 len, u8 qno) int rsi_mgmt_pkt_recv(struct rsi_common *common, u8 *msg); int rsi_set_vap_capabilities(struct rsi_common *common, enum opmode mode, - u8 vap_status); + u8 *mac_addr, u8 vap_id, u8 vap_status); int rsi_send_aggregation_params_frame(struct rsi_common *common, u16 tid, - u16 ssn, u8 buf_size, u8 event); + u16 ssn, u8 buf_size, u8 event, + u8 sta_id); int rsi_hal_load_key(struct rsi_common *common, u8 *data, u16 key_len, - u8 key_type, u8 key_id, u32 cipher); + u8 key_type, u8 key_id, u32 cipher, s16 sta_id); int rsi_set_channel(struct rsi_common *common, struct ieee80211_channel *channel); +int rsi_send_vap_dynamic_update(struct rsi_common *common); int rsi_send_block_unblock_frame(struct rsi_common *common, bool event); -void rsi_inform_bss_status(struct rsi_common *common, u8 status, - const u8 *bssid, u8 qos_enable, u16 aid); +void rsi_inform_bss_status(struct rsi_common *common, enum opmode opmode, + u8 status, const u8 *addr, u8 qos_enable, u16 aid, + struct ieee80211_sta *sta, u16 sta_id); void rsi_indicate_pkt_to_os(struct rsi_common *common, struct sk_buff *skb); int rsi_mac80211_attach(struct rsi_common *common); void rsi_indicate_tx_status(struct rsi_hw *common, struct sk_buff *skb, diff --git a/drivers/net/wireless/rsi/rsi_ps.h b/drivers/net/wireless/rsi/rsi_ps.h new file mode 100644 index 000000000000..d8475873df36 --- /dev/null +++ b/drivers/net/wireless/rsi/rsi_ps.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2017 Redpine Signals Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __RSI_PS_H__ +#define __RSI_PS_H__ + +#define PS_CONFIRM_INDEX 12 +#define RSI_DEF_DS_WAKEUP_PERIOD 200 +#define RSI_DEF_LISTEN_INTERVAL 200 +#define RSI_SLEEP_TYPE_LP 1 + +enum ps_state { + PS_NONE = 0, + PS_ENABLE_REQ_SENT = 1, + PS_DISABLE_REQ_SENT = 2, + PS_ENABLED = 3 +}; + +struct ps_sleep_params { + u8 enable; + u8 sleep_type; + u8 connected_sleep; + u8 reserved1; + __le16 num_bcns_per_lis_int; + __le16 wakeup_type; + __le32 sleep_duration; +} __packed; + +struct rsi_ps_info { + u8 enabled; + u8 sleep_type; + u8 tx_threshold; + u8 rx_threshold; + u8 tx_hysterisis; + u8 rx_hysterisis; + u16 monitor_interval; + u32 listen_interval; + u16 num_bcns_per_lis_int; + u32 dtim_interval_duration; + u16 num_dtims_per_sleep; + u32 deep_sleep_wakeup_period; +} __packed; + +char *str_psstate(enum ps_state state); +void rsi_enable_ps(struct rsi_hw *adapter); +void rsi_disable_ps(struct rsi_hw *adapter); +int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg); +void rsi_default_ps_params(struct rsi_hw *hw); +int rsi_send_ps_request(struct rsi_hw *adapter, bool enable); +void rsi_conf_uapsd(struct rsi_hw *adapter); +#endif diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index 9fb73f68282a..95e4bed57baf 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -41,6 +41,7 @@ enum sdio_interrupt_type { #define PKT_BUFF_FULL 1 #define PKT_MGMT_BUFF_FULL 2 #define MSDU_PKT_PENDING 3 +#define RECV_NUM_BLOCKS 4 /* Interrupt Bit Related Macros */ #define PKT_BUFF_AVAILABLE 1 #define FW_ASSERT_IND 2 @@ -58,6 +59,7 @@ enum sdio_interrupt_type { #define SDIO_READ_START_LVL 0x000FC #define SDIO_READ_FIFO_CTL 0x000FD #define SDIO_WRITE_FIFO_CTL 0x000FE +#define SDIO_WAKEUP_REG 0x000FF #define SDIO_FUN1_INTR_CLR_REG 0x0008 #define SDIO_REG_HIGH_SPEED 0x0013 @@ -103,7 +105,7 @@ struct receive_info { struct rsi_91x_sdiodev { struct sdio_func *pfunction; - struct task_struct *in_sdio_litefi_irq; + struct task_struct *sdio_irq_task; struct receive_info rx_info; u32 next_read_delay; u32 sdio_high_speed_enable; @@ -112,6 +114,7 @@ struct rsi_91x_sdiodev { u8 prev_desc[16]; u16 tx_blk_size; u8 write_fail; + bool buff_status_updated; }; void rsi_interrupt_handler(struct rsi_hw *adapter); @@ -125,5 +128,5 @@ int rsi_sdio_write_register_multiple(struct rsi_hw *adapter, u32 addr, int rsi_sdio_master_access_msword(struct rsi_hw *adapter, u16 ms_word); void rsi_sdio_ack_intr(struct rsi_hw *adapter, u8 int_bit); int rsi_sdio_determine_event_timeout(struct rsi_hw *adapter); -int rsi_sdio_read_buffer_status_register(struct rsi_hw *adapter, u8 q_num); +int rsi_sdio_check_buffer_status(struct rsi_hw *adapter, u8 q_num); #endif diff --git a/drivers/net/wireless/rsi/rsi_usb.h b/drivers/net/wireless/rsi/rsi_usb.h index 59513ac61fb3..891daea2d932 100644 --- a/drivers/net/wireless/rsi/rsi_usb.h +++ b/drivers/net/wireless/rsi/rsi_usb.h @@ -25,6 +25,7 @@ #define USB_INTERNAL_REG_1 0x25000 #define RSI_USB_READY_MAGIC_NUM 0xab #define FW_STATUS_REG 0x41050012 +#define RSI_TA_HOLD_REG 0x22000844 #define USB_VENDOR_REGISTER_READ 0x15 #define USB_VENDOR_REGISTER_WRITE 0x16 @@ -32,10 +33,11 @@ #define MAX_RX_URBS 1 #define MAX_BULK_EP 8 -#define MGMT_EP 1 -#define DATA_EP 2 +#define WLAN_EP 1 +#define BT_EP 2 #define RSI_USB_BUF_SIZE 4096 +#define RSI_USB_CTRL_BUF_SIZE 0x04 struct rsi_91x_usbdev { struct rsi_thread rx_thread; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 60aaa850fbd1..c346c021b999 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -6016,6 +6016,8 @@ static int wl1271_register_hw(struct wl1271 *wl) { int ret; u32 oui_addr = 0, nic_addr = 0; + struct platform_device *pdev = wl->pdev; + struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev); if (wl->mac80211_registered) return 0; @@ -6040,6 +6042,27 @@ static int wl1271_register_hw(struct wl1271 *wl) nic_addr = wl->fuse_nic_addr + 1; } + if (oui_addr == 0xdeadbe && nic_addr == 0xef0000) { + wl1271_warning("Detected unconfigured mac address in nvs, derive from fuse instead.\n"); + if (!strcmp(pdev_data->family->name, "wl18xx")) { + wl1271_warning("This default nvs file can be removed from the file system\n"); + } else { + wl1271_warning("Your device performance is not optimized.\n"); + wl1271_warning("Please use the calibrator tool to configure your device.\n"); + } + + if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) { + wl1271_warning("Fuse mac address is zero. using random mac\n"); + /* Use TI oui and a random nic */ + oui_addr = WLCORE_TI_OUI_ADDRESS; + nic_addr = get_random_int(); + } else { + oui_addr = wl->fuse_oui_addr; + /* fuse has the BD_ADDR, the WLAN addresses are the next two */ + nic_addr = wl->fuse_nic_addr + 1; + } + } + wl12xx_derive_mac_addresses(wl, oui_addr, nic_addr); ret = ieee80211_register_hw(wl->hw); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index 2fb38717346f..f8a1fea64e25 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -230,6 +230,7 @@ static const struct wilink_family_data wl128x_data = { static const struct wilink_family_data wl18xx_data = { .name = "wl18xx", .cfg_name = "ti-connectivity/wl18xx-conf.bin", + .nvs_name = "ti-connectivity/wl1271-nvs.bin", }; static const struct of_device_id wlcore_sdio_of_match_table[] = { diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index fdabb9242cca..62ce54a949e9 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -92,6 +92,7 @@ static const struct wilink_family_data wl128x_data = { static const struct wilink_family_data wl18xx_data = { .name = "wl18xx", .cfg_name = "ti-connectivity/wl18xx-conf.bin", + .nvs_name = "ti-connectivity/wl1271-nvs.bin", }; struct wl12xx_spi_glue { diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index a9218e5b0efc..b72e2101488b 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -138,7 +138,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, return len; } -static struct bin_attribute fwlog_attr = { +static const struct bin_attribute fwlog_attr = { .attr = {.name = "fwlog", .mode = S_IRUSR}, .read = wl1271_sysfs_read_fwlog, }; diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 1827546ba807..95fbedc8ea34 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -40,6 +40,9 @@ /* wl12xx/wl18xx maximum transmission power (in dBm) */ #define WLCORE_MAX_TXPWR 25 +/* Texas Instruments pre assigned OUI */ +#define WLCORE_TI_OUI_ADDRESS 0x080028 + /* forward declaration */ struct wl1271_tx_hw_descr; enum wl_rx_buf_align; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index acec0d9ec422..da62220b9c01 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -965,7 +965,7 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev, &addr4, sizeof(addr4)); if (!(addr4[0] == 0xAA && addr4[1] == 0xAA && addr4[2] == 0x03 && addr4[4] == 0x00)) { - printk(KERN_INFO "Insupported packet type!\n"); + printk(KERN_INFO "Unsupported packet type!\n"); return; } pkt_len = sig.size + 12 - 24 - 4 - 6; diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c index 7f586d76cf17..581e8577a221 100644 --- a/drivers/net/wireless/zydas/zd1201.c +++ b/drivers/net/wireless/zydas/zd1201.c @@ -25,7 +25,7 @@ #include <linux/firmware.h> #include "zd1201.h" -static struct usb_device_id zd1201_table[] = { +static const struct usb_device_id zd1201_table[] = { {USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */ {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */ {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zydas/zd1211rw/zd_rf_rf2959.c index a93f657a41c7..d4e512f50945 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_rf_rf2959.c @@ -61,7 +61,7 @@ static void dump_regwrite(u32 rw) switch (reg) { case 0: - PDEBUG("reg0 CFG1 ref_sel %d hybernate %d rf_vco_reg_en %d" + PDEBUG("reg0 CFG1 ref_sel %d hibernate %d rf_vco_reg_en %d" " if_vco_reg_en %d if_vga_en %d", bits(rw, 14, 15), bit(rw, 3), bit(rw, 2), bit(rw, 1), bit(rw, 0)); diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index 01ca1d57b3d9..c30bf118c67d 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -35,7 +35,7 @@ #include "zd_mac.h" #include "zd_usb.h" -static struct usb_device_id usb_ids[] = { +static const struct usb_device_id usb_ids[] = { /* ZD1211 */ { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, |