aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig7
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile3
-rw-r--r--drivers/net/wireless/ath/ath10k/ahb.c18
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c299
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h30
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c29
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h9
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c31
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c150
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h14
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c105
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h14
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c12
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.c1106
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.h128
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c166
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h271
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c5
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c5
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c52
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h3
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig12
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile2
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c84
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c27
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c14
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c42
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c27
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h20
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c14
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h720
-rw-r--r--drivers/net/wireless/atmel/at76c50x-usb.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c18
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c5
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c11
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h3
-rw-r--r--drivers/net/wireless/cisco/airo.c2
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2100.c34
-rw-r--r--drivers/net/wireless/intel/ipw2x00/ipw2200.c17
-rw-r--r--drivers/net/wireless/intel/iwlegacy/3945-mac.c2
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-mac.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/Makefile2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/8000.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/9000.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/cfg/a000.c44
-rw-r--r--drivers/net/wireless/intel/iwlwifi/dvm/commands.h24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/alive.h206
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/binding.h144
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/cmdhdr.h (renamed from drivers/net/wireless/intel/iwlwifi/fw/api.h)78
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/coex.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-coex.h)73
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/commands.h657
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/config.h184
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/context.h94
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/d3.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h)11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h127
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/debug.h345
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/filter.h183
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/led.h71
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h152
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/mac.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-mac.h)33
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h386
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/offload.h101
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/paging.h108
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/phy-ctxt.h164
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/phy.h258
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/power.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-power.h)13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rs.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rs.h)13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/rx.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h)31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/scan.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-scan.h)11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/sf.h138
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/sta.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h)15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/stats.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-stats.h)13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h208
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h386
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/tof.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tof.h)9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/tx.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-api-tx.h)66
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/txq.h163
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/common_rx.c88
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c)474
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h (renamed from drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.h)125
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/error-dump.h30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/init.c75
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/notif-wait.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/nvm.c162
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/paging.c414
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/runtime.h158
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/smem.c155
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-csr.h11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c36
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-io.c14
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c123
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-prph.h13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/Makefile2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/coex.c310
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/constants.h4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c75
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h2846
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c553
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/led.c59
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c413
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c217
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h158
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/nvm.c200
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c157
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/power.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rs.c142
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rx.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c9
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c558
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c54
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tof.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tof.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tt.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c164
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/utils.c18
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c63
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c22
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_main.c4
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_usb.c2
-rw-r--r--drivers/net/wireless/intersil/p54/p54usb.c2
-rw-r--r--drivers/net/wireless/marvell/libertas/if_usb.c2
-rw-r--r--drivers/net/wireless/marvell/libertas_tf/if_usb.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/11n.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c35
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfp.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cmdevt.c15
-rw-r--r--drivers/net/wireless/marvell/mwifiex/debugfs.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/init.c32
-rw-r--r--drivers/net/wireless/marvell/mwifiex/join.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.c173
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.h14
-rw-r--r--drivers/net/wireless/marvell/mwifiex/pcie.c126
-rw-r--r--drivers/net/wireless/marvell/mwifiex/scan.c15
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sdio.c3
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_cmd.c19
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c5
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_ioctl.c121
-rw-r--r--drivers/net/wireless/marvell/mwifiex/tdls.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/uap_cmd.c34
-rw-r--r--drivers/net/wireless/marvell/mwifiex/usb.c5
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/dma.c5
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c2
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/Makefile4
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/bus.h1
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/cfg80211.c315
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/cfg80211.h4
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/commands.c486
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/commands.h5
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/core.c5
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/core.h27
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/event.c67
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c408
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h15
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h11
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h2
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/qlink.h202
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/qlink_util.c26
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/qlink_util.h10
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2500usb.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c5
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800mmio.c13
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800usb.c17
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt73usb.c2
-rw-r--r--drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c2
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/base.c22
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/base.h2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbt_precomp.h16
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c10
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c17
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.c28
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/btcoexist/rtl_btc.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/core.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/pci.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rc.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c12
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.h3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c9
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/fw.c9
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c7
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c365
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c17
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.c192
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/table.h10
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c15
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c43
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c5
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c21
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/wifi.h49
-rw-r--r--drivers/net/wireless/rsi/Makefile1
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_core.c80
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_debugfs.c3
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_hal.c368
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c495
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_main.c5
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mgmt.c741
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_ps.c146
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio.c157
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio_ops.c84
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb.c138
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_usb_ops.c6
-rw-r--r--drivers/net/wireless/rsi/rsi_common.h1
-rw-r--r--drivers/net/wireless/rsi/rsi_hal.h66
-rw-r--r--drivers/net/wireless/rsi/rsi_main.h88
-rw-r--r--drivers/net/wireless/rsi/rsi_mgmt.h258
-rw-r--r--drivers/net/wireless/rsi/rsi_ps.h64
-rw-r--r--drivers/net/wireless/rsi/rsi_sdio.h7
-rw-r--r--drivers/net/wireless/rsi/rsi_usb.h6
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c23
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h3
-rw-r--r--drivers/net/wireless/wl3501_cs.c2
-rw-r--r--drivers/net/wireless/zydas/zd1201.c2
-rw-r--r--drivers/net/wireless/zydas/zd1211rw/zd_rf_rf2959.c2
-rw-r--r--drivers/net/wireless/zydas/zd1211rw/zd_usb.c2
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(&notif_wait->notif_wait_lock);
+ list_del(&wait_entry->list);
+ spin_unlock_bh(&notif_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(&notif_wait->notif_wait_lock);
- list_del(&wait_entry->list);
- spin_unlock_bh(&notif_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(&notif_wait->notif_wait_lock);
- list_del(&wait_entry->list);
- spin_unlock_bh(&notif_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, &params->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(&params->chandef,
+ &mac->csa_chandef))
+ return -EINVAL;
+
+ return 0;
+ }
+
+ if (!cfg80211_chandef_valid(&params->chandef)) {
+ pr_err("%s: invalid channel\n", dev->name);
+ return -EINVAL;
+ }
+
+ if (cfg80211_chandef_identical(&params->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, &params->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 = &params->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 },