Merge branch 'net_next_ovs' of git://git.kernel.org/pub/scm/linux/kernel/git/pshelar...
authorDavid S. Miller <davem@davemloft.net>
Tue, 11 Nov 2014 18:32:25 +0000 (13:32 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 11 Nov 2014 18:32:25 +0000 (13:32 -0500)
Pravin B Shelar says:

====================
Open vSwitch

Following batch of patches brings feature parity between upstream
ovs and out of tree ovs module.

Two features are added, first adds support to export egress
tunnel information for a packet. This is used to improve
visibility in network traffic. Second feature allows userspace
vswitchd process to probe ovs module features. Other patches
are optimization and code cleanup.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
329 files changed:
MAINTAINERS
arch/alpha/include/uapi/asm/socket.h
arch/avr32/include/uapi/asm/socket.h
arch/cris/include/uapi/asm/socket.h
arch/frv/include/uapi/asm/socket.h
arch/ia64/include/uapi/asm/socket.h
arch/m32r/include/uapi/asm/socket.h
arch/mips/include/uapi/asm/socket.h
arch/mn10300/include/uapi/asm/socket.h
arch/parisc/include/uapi/asm/socket.h
arch/powerpc/include/uapi/asm/socket.h
arch/s390/include/uapi/asm/socket.h
arch/sparc/include/uapi/asm/socket.h
arch/xtensa/include/uapi/asm/socket.h
drivers/bcma/bcma_private.h
drivers/bcma/main.c
drivers/bcma/scan.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_h5.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/cq.c
drivers/infiniband/hw/cxgb4/mem.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_debugfs.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bond_procfs.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bond_sysfs_slave.c
drivers/net/ethernet/chelsio/cxgb4/Makefile
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c [new file with mode: 0644]
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h [new file with mode: 0644]
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_port.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/ieee802154/Kconfig
drivers/net/ieee802154/Makefile
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/cc2520.c
drivers/net/ieee802154/fakehard.c [deleted file]
drivers/net/ieee802154/fakelb.c
drivers/net/ieee802154/mrf24j40.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/hif.h
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/mac.h
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/spectral.c
drivers/net/wireless/ath/ath10k/spectral.h
drivers/net/wireless/ath/ath10k/trace.h
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/common.h
drivers/net/wireless/ath/ath6kl/debug.c
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_rtt.h
drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/channel.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/tx99.c
drivers/net/wireless/ath/carl9170/phy.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/main.c
drivers/net/wireless/ath/wil6210/netdev.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/txrx.h
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/btcoex.c
drivers/net/wireless/brcm80211/brcmfmac/bus.h [moved from drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c [moved from drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h [moved from drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/chip.c
drivers/net/wireless/brcm80211/brcmfmac/common.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/commonring.c
drivers/net/wireless/brcm80211/brcmfmac/core.c [moved from drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c with 99% similarity]
drivers/net/wireless/brcm80211/brcmfmac/core.h [moved from drivers/net/wireless/brcm80211/brcmfmac/dhd.h with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/debug.c [moved from drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/debug.h [moved from drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c [deleted file]
drivers/net/wireless/brcm80211/brcmfmac/feature.c
drivers/net/wireless/brcm80211/brcmfmac/firmware.c
drivers/net/wireless/brcm80211/brcmfmac/flowring.c
drivers/net/wireless/brcm80211/brcmfmac/fweh.c
drivers/net/wireless/brcm80211/brcmfmac/fwil.c
drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
drivers/net/wireless/brcm80211/brcmfmac/of.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/brcm80211/brcmfmac/proto.c
drivers/net/wireless/brcm80211/brcmfmac/sdio.c [moved from drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/sdio.h [moved from drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h with 98% similarity]
drivers/net/wireless/brcm80211/brcmfmac/tracepoint.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h [deleted file]
drivers/net/wireless/brcm80211/brcmfmac/vendor.c
drivers/net/wireless/brcm80211/brcmsmac/debug.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965.h
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmdresp.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rtlwifi/rtl8821ae/phy.c
drivers/net/wireless/ti/wlcore/main.c
drivers/scsi/csiostor/csio_attr.c
drivers/scsi/csiostor/csio_hw.c
drivers/scsi/csiostor/csio_hw_t4.c
drivers/scsi/csiostor/csio_hw_t5.c
drivers/scsi/csiostor/csio_init.c
drivers/scsi/csiostor/csio_lnode.c
drivers/scsi/csiostor/csio_mb.c
drivers/scsi/csiostor/csio_scsi.c
drivers/scsi/csiostor/csio_wr.h
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
include/linux/ath9k_platform.h
include/linux/ieee80211.h
include/linux/ieee802154.h [moved from include/net/ieee802154.h with 94% similarity]
include/linux/mlx4/device.h
include/linux/netdevice.h
include/linux/nl802154.h
include/net/6lowpan.h
include/net/af_ieee802154.h
include/net/bluetooth/hci_core.h
include/net/bond_3ad.h [moved from drivers/net/bonding/bond_3ad.h with 99% similarity]
include/net/bond_alb.h [moved from drivers/net/bonding/bond_alb.h with 98% similarity]
include/net/bond_options.h [moved from drivers/net/bonding/bond_options.h with 97% similarity]
include/net/bonding.h [moved from drivers/net/bonding/bonding.h with 99% similarity]
include/net/cfg80211.h
include/net/cfg802154.h [moved from include/net/wpan-phy.h with 77% similarity]
include/net/ieee802154_netdev.h
include/net/mac80211.h
include/net/mac802154.h
include/net/nl802154.h
include/net/sock.h
include/uapi/asm-generic/socket.h
include/uapi/linux/nl80211.h
include/uapi/linux/rtnetlink.h
net/6lowpan/iphc.c
net/bluetooth/6lowpan.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/smp.c
net/core/dev.c
net/core/net-sysfs.c
net/core/sock.c
net/dsa/dsa.c
net/dsa/slave.c
net/ieee802154/6lowpan_rtnl.c
net/ieee802154/Makefile
net/ieee802154/af802154.h
net/ieee802154/af_ieee802154.c
net/ieee802154/core.c [moved from net/ieee802154/wpan-class.c with 60% similarity]
net/ieee802154/dgram.c
net/ieee802154/header_ops.c
net/ieee802154/ieee802154.h
net/ieee802154/netlink.c
net/ieee802154/nl-mac.c
net/ieee802154/nl-phy.c
net/ieee802154/nl_policy.c
net/ieee802154/raw.c
net/ieee802154/reassembly.c
net/ieee802154/reassembly.h
net/ieee802154/sysfs.c [new file with mode: 0644]
net/ieee802154/sysfs.h [new file with mode: 0644]
net/ipv4/raw.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debug.h
net/mac80211/debugfs_key.c
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.h
net/mac80211/mesh_pathtbl.c
net/mac80211/mlme.c
net/mac80211/ocb.c [new file with mode: 0644]
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_minstrel_ht.h
net/mac80211/rc80211_minstrel_ht_debugfs.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/status.c
net/mac80211/tdls.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wep.c
net/mac80211/wme.c
net/mac80211/wme.h
net/mac80211/wpa.c
net/mac802154/Kconfig
net/mac802154/Makefile
net/mac802154/driver-ops.h [new file with mode: 0644]
net/mac802154/ieee802154_dev.c [deleted file]
net/mac802154/ieee802154_i.h [moved from net/mac802154/mac802154.h with 73% similarity]
net/mac802154/iface.c [new file with mode: 0644]
net/mac802154/llsec.c
net/mac802154/mac_cmd.c
net/mac802154/main.c [new file with mode: 0644]
net/mac802154/mib.c
net/mac802154/monitor.c [deleted file]
net/mac802154/rx.c
net/mac802154/tx.c
net/mac802154/util.c [new file with mode: 0644]
net/mac802154/wpan.c [deleted file]
net/sctp/ulpqueue.c
net/wireless/Makefile
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/ocb.c [new file with mode: 0644]
net/wireless/rdev-ops.h
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c

index 3a41fb0db2bd8780bdb83f540eb141cb7573256e..5bf11c7066519ac1c71f5a81b99d61d73fc5c0a2 100644 (file)
@@ -2306,6 +2306,14 @@ F:       security/capability.c
 F:     security/commoncap.c
 F:     kernel/capability.c
 
+CC2520 IEEE-802.15.4 RADIO DRIVER
+M:     Varka Bhadram <varkabhadram@gmail.com>
+L:     linux-wpan@vger.kernel.org
+S:     Maintained
+F:     drivers/net/ieee802154/cc2520.c
+F:     include/linux/spi/cc2520.h
+F:     Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
+
 CELL BROADBAND ENGINE ARCHITECTURE
 M:     Arnd Bergmann <arnd@arndb.de>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -4693,6 +4701,13 @@ S:       Maintained
 F:     net/ieee802154/
 F:     net/mac802154/
 F:     drivers/net/ieee802154/
+F:     include/linux/nl802154.h
+F:     include/linux/ieee802154.h
+F:     include/net/nl802154.h
+F:     include/net/mac802154.h
+F:     include/net/af_ieee802154.h
+F:     include/net/cfg802154.h
+F:     include/net/ieee802154_netdev.h
 F:     Documentation/networking/ieee802154.txt
 
 IGUANAWORKS USB IR TRANSCEIVER
index 3de1394bcab821984674e89a3ee022cc6dd5f0f2..e2fe0700b3b442bffc1f606b1b8b0bb7759aa157 100644 (file)
@@ -87,4 +87,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 6e6cd159924b1855aa5f1811ad4e4c60b403c431..92121b0f5b989a61c008e0be24030725bab88e36 100644 (file)
@@ -80,4 +80,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _UAPI__ASM_AVR32_SOCKET_H */
index ed94e5ed0a238c2750e677ccb806a6bc0a94041a..60f60f5b9b35bd219d7a9834fe5394e8ac5fdbab 100644 (file)
@@ -82,6 +82,8 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_SOCKET_H */
 
 
index ca2c6e6f31c6817780d31a246652adcc9847e373..2c6890209ea60c149bf097c2a1b369519cb8c301 100644 (file)
@@ -80,5 +80,7 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_SOCKET_H */
 
index a1b49bac7951929127ed08db549218c2c16ccf89..09a93fb566f6c6c6fe29c10c95b931881843d1cd 100644 (file)
@@ -89,4 +89,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_IA64_SOCKET_H */
index 6c9a24b3aefa3a4f3048c17a7fa06d97b585ec14..e8589819c2743c6e112b15a245fc3ebd146e6313 100644 (file)
@@ -80,4 +80,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_M32R_SOCKET_H */
index a14baa218c76f14de988ef106bdac5dadc48aceb..2e9ee8c55a103a0337d9f80f71fe9ef28be1154b 100644 (file)
@@ -98,4 +98,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 6aa3ce1854aa9523d46bc28851eddabd59edeb37..f3492e8c9f7009c33e07168df916f7337bef3929 100644 (file)
@@ -80,4 +80,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_SOCKET_H */
index fe35ceacf0e72cad69a43d9b1ce7b8f5ec3da98a..7984a1cab3da980f1f810827967b4b67616eb89b 100644 (file)
@@ -79,4 +79,6 @@
 
 #define SO_BPF_EXTENSIONS      0x4029
 
+#define SO_INCOMING_CPU                0x402A
+
 #endif /* _UAPI_ASM_SOCKET_H */
index a9c3e2e18c054a1e952fe33599401de57c6a6544..3474e4ef166df4a573773916b325d0fa9f3b45d0 100644 (file)
@@ -87,4 +87,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index e031332096d7c7b23b5953680289e8f3bcc3b378..8457636c33e1b67a9b7804daa05627839035a8fb 100644 (file)
@@ -86,4 +86,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _ASM_SOCKET_H */
index 54d9608681b6947ae25dab008f808841d96125c0..4a8003a9416348006cfa85d5bcdf7553c8d23958 100644 (file)
@@ -76,6 +76,8 @@
 
 #define SO_BPF_EXTENSIONS      0x0032
 
+#define SO_INCOMING_CPU                0x0033
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index 39acec0cf0b1d500c1c40f9b523ef3a9a142c2f1..c46f6a696849c6f7f8a34b2cc522b48e04b17380 100644 (file)
@@ -91,4 +91,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* _XTENSA_SOCKET_H */
index b6412b2d748dd11d6236963432c3984dd537f704..314ae4032f3e7347ee2f4d391bab32964fad0594 100644 (file)
@@ -24,6 +24,7 @@ struct bcma_bus;
 /* main.c */
 bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
                     int timeout);
+void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
 int bcma_bus_register(struct bcma_bus *bus);
 void bcma_bus_unregister(struct bcma_bus *bus);
 int __init bcma_bus_early_register(struct bcma_bus *bus,
index 1000955ce09d870db23979e3950d75e32b75cfc1..a15e0bcfb3977218e9014e72fb8ad50d4fafeec0 100644 (file)
@@ -169,10 +169,8 @@ static void bcma_of_fill_device(struct platform_device *parent,
 }
 #endif /* CONFIG_OF */
 
-static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
 {
-       int err;
-
        core->dev.release = bcma_release_core_dev;
        core->dev.bus = &bcma_bus_type;
        dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
@@ -196,6 +194,11 @@ static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
        case BCMA_HOSTTYPE_SDIO:
                break;
        }
+}
+
+static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
+{
+       int err;
 
        err = device_register(&core->dev);
        if (err) {
index 14b56561a36f10713cc5c470b838b25da4687999..917520776879255c94350f5458e079ecb07df062 100644 (file)
@@ -505,6 +505,7 @@ int bcma_bus_scan(struct bcma_bus *bus)
                bus->nr_cores++;
                other_core = bcma_find_core_reverse(bus, core->id.id);
                core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
+               bcma_prepare_core(bus, core);
 
                bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
                          core->core_index, bcma_device_name(&core->id),
index d85ced27ebd58f5a40b1881032daced2aedf82b0..25c874da5f2b676a156ab323ef8e94eb51504a4f 100644 (file)
@@ -79,6 +79,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0489, 0xe057) },
        { USB_DEVICE(0x0489, 0xe056) },
        { USB_DEVICE(0x0489, 0xe05f) },
+       { USB_DEVICE(0x0489, 0xe078) },
        { USB_DEVICE(0x04c5, 0x1330) },
        { USB_DEVICE(0x04CA, 0x3004) },
        { USB_DEVICE(0x04CA, 0x3005) },
@@ -130,6 +131,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
index edfc17bfcd44e02a8c8fb8748687cf265770863d..03ce301fca9279e9e5058fdcfc804de0b17944d7 100644 (file)
@@ -156,6 +156,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
index a22838669b4ed227d447925ea45337f5efd9f72d..20bdd71559b16569d8bed368e1eb7842a841705a 100644 (file)
@@ -168,6 +168,36 @@ wakeup:
        hci_uart_tx_wakeup(hu);
 }
 
+static void h5_peer_reset(struct hci_uart *hu)
+{
+       struct h5 *h5 = hu->priv;
+       struct sk_buff *skb;
+       const unsigned char hard_err[] = { 0x10, 0x01, 0x00 };
+
+       BT_ERR("Peer device has reset");
+
+       h5->state = H5_UNINITIALIZED;
+
+       del_timer(&h5->timer);
+
+       skb_queue_purge(&h5->rel);
+       skb_queue_purge(&h5->unrel);
+       skb_queue_purge(&h5->unack);
+
+       h5->tx_seq = 0;
+       h5->tx_ack = 0;
+
+       skb = bt_skb_alloc(3, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+       memcpy(skb_put(skb, 3), hard_err, 3);
+
+       /* Send Hardware Error to upper stack */
+       hci_recv_frame(hu->hdev, skb);
+}
+
 static int h5_open(struct hci_uart *hu)
 {
        struct h5 *h5;
@@ -283,8 +313,12 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
        conf_req[2] = h5_cfg_field(h5);
 
        if (memcmp(data, sync_req, 2) == 0) {
+               if (h5->state == H5_ACTIVE)
+                       h5_peer_reset(hu);
                h5_link_control(hu, sync_rsp, 2);
        } else if (memcmp(data, sync_rsp, 2) == 0) {
+               if (h5->state == H5_ACTIVE)
+                       h5_peer_reset(hu);
                h5->state = H5_INITIALIZED;
                h5_link_control(hu, conf_req, 3);
        } else if (memcmp(data, conf_req, 2) == 0) {
index fb61f6685809e21f853d849d056a9111e2c3b6d0..a07d8e124a80b05af4bd807273e89425a92783e4 100644 (file)
@@ -472,10 +472,10 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
        skb = get_skb(skb, flowclen, GFP_KERNEL);
        flowc = (struct fw_flowc_wr *)__skb_put(skb, flowclen);
 
-       flowc->op_to_nparams = cpu_to_be32(FW_WR_OP(FW_FLOWC_WR) |
-                                          FW_FLOWC_WR_NPARAMS(8));
-       flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16(DIV_ROUND_UP(flowclen,
-                                         16)) | FW_WR_FLOWID(ep->hwtid));
+       flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) |
+                                          FW_FLOWC_WR_NPARAMS_V(8));
+       flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(flowclen,
+                                         16)) | FW_WR_FLOWID_V(ep->hwtid));
 
        flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
        flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN
@@ -803,16 +803,16 @@ static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb,
        req = (struct fw_ofld_tx_data_wr *)skb_put(skb, wrlen);
        memset(req, 0, wrlen);
        req->op_to_immdlen = cpu_to_be32(
-               FW_WR_OP(FW_OFLD_TX_DATA_WR) |
-               FW_WR_COMPL(1) |
-               FW_WR_IMMDLEN(mpalen));
+               FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+               FW_WR_COMPL_F |
+               FW_WR_IMMDLEN_V(mpalen));
        req->flowid_len16 = cpu_to_be32(
-               FW_WR_FLOWID(ep->hwtid) |
-               FW_WR_LEN16(wrlen >> 4));
+               FW_WR_FLOWID_V(ep->hwtid) |
+               FW_WR_LEN16_V(wrlen >> 4));
        req->plen = cpu_to_be32(mpalen);
        req->tunnel_to_proxy = cpu_to_be32(
-               FW_OFLD_TX_DATA_WR_FLUSH(1) |
-               FW_OFLD_TX_DATA_WR_SHOVE(1));
+               FW_OFLD_TX_DATA_WR_FLUSH_F |
+               FW_OFLD_TX_DATA_WR_SHOVE_F);
 
        mpa = (struct mpa_message *)(req + 1);
        memcpy(mpa->key, MPA_KEY_REQ, sizeof(mpa->key));
@@ -897,16 +897,16 @@ static int send_mpa_reject(struct c4iw_ep *ep, const void *pdata, u8 plen)
        req = (struct fw_ofld_tx_data_wr *)skb_put(skb, wrlen);
        memset(req, 0, wrlen);
        req->op_to_immdlen = cpu_to_be32(
-               FW_WR_OP(FW_OFLD_TX_DATA_WR) |
-               FW_WR_COMPL(1) |
-               FW_WR_IMMDLEN(mpalen));
+               FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+               FW_WR_COMPL_F |
+               FW_WR_IMMDLEN_V(mpalen));
        req->flowid_len16 = cpu_to_be32(
-               FW_WR_FLOWID(ep->hwtid) |
-               FW_WR_LEN16(wrlen >> 4));
+               FW_WR_FLOWID_V(ep->hwtid) |
+               FW_WR_LEN16_V(wrlen >> 4));
        req->plen = cpu_to_be32(mpalen);
        req->tunnel_to_proxy = cpu_to_be32(
-               FW_OFLD_TX_DATA_WR_FLUSH(1) |
-               FW_OFLD_TX_DATA_WR_SHOVE(1));
+               FW_OFLD_TX_DATA_WR_FLUSH_F |
+               FW_OFLD_TX_DATA_WR_SHOVE_F);
 
        mpa = (struct mpa_message *)(req + 1);
        memset(mpa, 0, sizeof(*mpa));
@@ -977,16 +977,16 @@ static int send_mpa_reply(struct c4iw_ep *ep, const void *pdata, u8 plen)
        req = (struct fw_ofld_tx_data_wr *) skb_put(skb, wrlen);
        memset(req, 0, wrlen);
        req->op_to_immdlen = cpu_to_be32(
-               FW_WR_OP(FW_OFLD_TX_DATA_WR) |
-               FW_WR_COMPL(1) |
-               FW_WR_IMMDLEN(mpalen));
+               FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+               FW_WR_COMPL_F |
+               FW_WR_IMMDLEN_V(mpalen));
        req->flowid_len16 = cpu_to_be32(
-               FW_WR_FLOWID(ep->hwtid) |
-               FW_WR_LEN16(wrlen >> 4));
+               FW_WR_FLOWID_V(ep->hwtid) |
+               FW_WR_LEN16_V(wrlen >> 4));
        req->plen = cpu_to_be32(mpalen);
        req->tunnel_to_proxy = cpu_to_be32(
-               FW_OFLD_TX_DATA_WR_FLUSH(1) |
-               FW_OFLD_TX_DATA_WR_SHOVE(1));
+               FW_OFLD_TX_DATA_WR_FLUSH_F |
+               FW_OFLD_TX_DATA_WR_SHOVE_F);
 
        mpa = (struct mpa_message *)(req + 1);
        memset(mpa, 0, sizeof(*mpa));
@@ -1751,7 +1751,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
        req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));
        memset(req, 0, sizeof(*req));
        req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR));
-       req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+       req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
        req->le.filter = cpu_to_be32(cxgb4_select_ntuple(
                                     ep->com.dev->rdev.lldi.ports[0],
                                     ep->l2t));
@@ -3537,8 +3537,8 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
        req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
        req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
        memset(req, 0, sizeof(*req));
-       req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL(1));
-       req->len16_pkd = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*req), 16)));
+       req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F);
+       req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
        req->le.version_cpl = htonl(F_FW_OFLD_CONNECTION_WR_CPL);
        req->le.filter = (__force __be32) filter;
        req->le.lport = lport;
index 0f773e78e0801ebf2b230298b15a3eb4bde15444..e9fd3a029296389cc63628319491edf7a2644a15 100644 (file)
@@ -51,9 +51,9 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
        res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
        memset(res_wr, 0, wr_len);
        res_wr->op_nres = cpu_to_be32(
-                       FW_WR_OP(FW_RI_RES_WR) |
+                       FW_WR_OP_V(FW_RI_RES_WR) |
                        V_FW_RI_RES_WR_NRES(1) |
-                       FW_WR_COMPL(1));
+                       FW_WR_COMPL_F);
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
        res_wr->cookie = (unsigned long) &wr_wait;
        res = res_wr->res;
@@ -121,9 +121,9 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
        res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
        memset(res_wr, 0, wr_len);
        res_wr->op_nres = cpu_to_be32(
-                       FW_WR_OP(FW_RI_RES_WR) |
+                       FW_WR_OP_V(FW_RI_RES_WR) |
                        V_FW_RI_RES_WR_NRES(1) |
-                       FW_WR_COMPL(1));
+                       FW_WR_COMPL_F);
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
        res_wr->cookie = (unsigned long) &wr_wait;
        res = res_wr->res;
index ec7a2988a70344e1b784b6e68a2638f78cd439bc..9335148c1ad9ce746be5a0cb50062572627a37e3 100644 (file)
@@ -74,10 +74,10 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
        req = (struct ulp_mem_io *)__skb_put(skb, wr_len);
        memset(req, 0, wr_len);
        INIT_ULPTX_WR(req, wr_len, 0, 0);
-       req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
-                       (wait ? FW_WR_COMPL(1) : 0));
+       req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
+                       (wait ? FW_WR_COMPL_F : 0));
        req->wr.wr_lo = wait ? (__force __be64)(unsigned long) &wr_wait : 0L;
-       req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
+       req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
        req->cmd = cpu_to_be32(ULPTX_CMD(ULP_TX_MEM_WRITE));
        req->cmd |= cpu_to_be32(V_T5_ULP_MEMIO_ORDER(1));
        req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(len>>5));
@@ -135,13 +135,13 @@ static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
                INIT_ULPTX_WR(req, wr_len, 0, 0);
 
                if (i == (num_wqe-1)) {
-                       req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR) |
-                                                   FW_WR_COMPL(1));
+                       req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
+                                                   FW_WR_COMPL_F);
                        req->wr.wr_lo = (__force __be64)(unsigned long) &wr_wait;
                } else
-                       req->wr.wr_hi = cpu_to_be32(FW_WR_OP(FW_ULPTX_WR));
+                       req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
                req->wr.wr_mid = cpu_to_be32(
-                                      FW_WR_LEN16(DIV_ROUND_UP(wr_len, 16)));
+                                      FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
 
                req->cmd = cmd;
                req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN(
index 41cd6882b648128f06476e948c56b94792e807bb..2ed3ece2b2ee38de0bf38525914ffb85cb7ed80d 100644 (file)
@@ -271,9 +271,9 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
        memset(res_wr, 0, wr_len);
        res_wr->op_nres = cpu_to_be32(
-                       FW_WR_OP(FW_RI_RES_WR) |
+                       FW_WR_OP_V(FW_RI_RES_WR) |
                        V_FW_RI_RES_WR_NRES(2) |
-                       FW_WR_COMPL(1));
+                       FW_WR_COMPL_F);
        res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
        res_wr->cookie = (unsigned long) &wr_wait;
        res = res_wr->res;
@@ -1082,10 +1082,10 @@ static void post_terminate(struct c4iw_qp *qhp, struct t4_cqe *err_cqe,
 
        wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
        memset(wqe, 0, sizeof *wqe);
-       wqe->op_compl = cpu_to_be32(FW_WR_OP(FW_RI_INIT_WR));
+       wqe->op_compl = cpu_to_be32(FW_WR_OP_V(FW_RI_INIT_WR));
        wqe->flowid_len16 = cpu_to_be32(
-               FW_WR_FLOWID(qhp->ep->hwtid) |
-               FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+               FW_WR_FLOWID_V(qhp->ep->hwtid) |
+               FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
 
        wqe->u.terminate.type = FW_RI_TYPE_TERMINATE;
        wqe->u.terminate.immdlen = cpu_to_be32(sizeof *term);
@@ -1204,11 +1204,11 @@ static int rdma_fini(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
        wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
        memset(wqe, 0, sizeof *wqe);
        wqe->op_compl = cpu_to_be32(
-               FW_WR_OP(FW_RI_INIT_WR) |
-               FW_WR_COMPL(1));
+               FW_WR_OP_V(FW_RI_INIT_WR) |
+               FW_WR_COMPL_F);
        wqe->flowid_len16 = cpu_to_be32(
-               FW_WR_FLOWID(ep->hwtid) |
-               FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+               FW_WR_FLOWID_V(ep->hwtid) |
+               FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
        wqe->cookie = (unsigned long) &ep->com.wr_wait;
 
        wqe->u.fini.type = FW_RI_TYPE_FINI;
@@ -1273,11 +1273,11 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
        wqe = (struct fw_ri_wr *)__skb_put(skb, sizeof(*wqe));
        memset(wqe, 0, sizeof *wqe);
        wqe->op_compl = cpu_to_be32(
-               FW_WR_OP(FW_RI_INIT_WR) |
-               FW_WR_COMPL(1));
+               FW_WR_OP_V(FW_RI_INIT_WR) |
+               FW_WR_COMPL_F);
        wqe->flowid_len16 = cpu_to_be32(
-               FW_WR_FLOWID(qhp->ep->hwtid) |
-               FW_WR_LEN16(DIV_ROUND_UP(sizeof *wqe, 16)));
+               FW_WR_FLOWID_V(qhp->ep->hwtid) |
+               FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*wqe), 16)));
 
        wqe->cookie = (unsigned long) &qhp->ep->com.wr_wait;
 
index 2110215f3528fb0cf41c7c188de3821d171e170b..0a32143af12b20a064e85b25be7d4f932499f059 100644 (file)
@@ -29,8 +29,8 @@
 #include <linux/if_bonding.h>
 #include <linux/pkt_sched.h>
 #include <net/net_namespace.h>
-#include "bonding.h"
-#include "bond_3ad.h"
+#include <net/bonding.h>
+#include <net/bond_3ad.h>
 
 /* General definitions */
 #define AD_SHORT_TIMEOUT           1
index baa58e79256a8b804e6ab683af6665f0730b86de..e1f1a006af852d86b2aca78366b6bf2852522521 100644 (file)
@@ -37,8 +37,8 @@
 #include <net/arp.h>
 #include <net/ipv6.h>
 #include <asm/byteorder.h>
-#include "bonding.h"
-#include "bond_alb.h"
+#include <net/bonding.h>
+#include <net/bond_alb.h>
 
 
 
index 8f99082f90ebed3bf7d91a8914b66704a1c74512..e52e25a977fa203d82d4d35260584c1b1ef644a9 100644 (file)
@@ -3,8 +3,8 @@
 #include <linux/device.h>
 #include <linux/netdevice.h>
 
-#include "bonding.h"
-#include "bond_alb.h"
+#include <net/bonding.h>
+#include <net/bond_alb.h>
 
 #if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_NET_NS)
 
index c7520082fb0d7bfbc34ac00b4f4186a30197ad74..b9b34566b9b85d54b0b6b1eb2dfcead6c1205983 100644 (file)
@@ -77,9 +77,9 @@
 #include <net/pkt_sched.h>
 #include <linux/rculist.h>
 #include <net/flow_keys.h>
-#include "bonding.h"
-#include "bond_3ad.h"
-#include "bond_alb.h"
+#include <net/bonding.h>
+#include <net/bond_3ad.h>
+#include <net/bond_alb.h>
 
 /*---------------------------- Module parameters ----------------------------*/
 
index c13d83e15ace440fc624ff6913d617fdabd2699f..3e6eebd5be50d316466922652a9f4f3a6132ae8f 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/if_ether.h>
 #include <net/netlink.h>
 #include <net/rtnetlink.h>
-#include "bonding.h"
+#include <net/bonding.h>
 
 static size_t bond_get_slave_size(const struct net_device *bond_dev,
                                  const struct net_device *slave_dev)
index b62697f4a3deb90a5c2209ad6f032c6984284510..1a61cc9b3402b1e96e973cf88f5e51bb4d56bad2 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/rcupdate.h>
 #include <linux/ctype.h>
 #include <linux/inet.h>
-#include "bonding.h"
+#include <net/bonding.h>
 
 static int bond_option_active_slave_set(struct bonding *bond,
                                        const struct bond_opt_value *newval);
index a3948f8d1e533d86502c3efa4eac839dcba0e557..976f5ad2a0f2d17975e0523a70c0d497b5a4ee32 100644 (file)
@@ -2,7 +2,7 @@
 #include <linux/export.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
-#include "bonding.h"
+#include <net/bonding.h>
 
 
 static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
index 8ffbafd500fd439f4277489aa533790f8f43e774..7e9e151d4d6168821e28ef82e8c197b2c4666b87 100644 (file)
@@ -40,7 +40,7 @@
 #include <net/netns/generic.h>
 #include <linux/nsproxy.h>
 
-#include "bonding.h"
+#include <net/bonding.h>
 
 #define to_dev(obj)    container_of(obj, struct device, kobj)
 #define to_bond(cd)    ((struct bonding *)(netdev_priv(to_net_dev(cd))))
index b01b0ce4d1bef13d48c6f41c4e2e6a8f5d50e8d4..23618a8316122e87c074c863b0dc687f7ed1dcea 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 
-#include "bonding.h"
+#include <net/bonding.h>
 
 struct slave_attribute {
        struct attribute attr;
index 1df65c915b995228d7b8d22173541c7f1d4ee4af..b8528077599730ec48853fc6ab6495a72e04f826 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
 
 cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o
 cxgb4-$(CONFIG_CHELSIO_T4_DCB) +=  cxgb4_dcb.o
+cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
index 3c481b2607458ad453a975f2842fcce40476c720..a2196bc944851cb7fed32420fe1ac845ad89ca87 100644 (file)
@@ -354,7 +354,7 @@ struct link_config {
        unsigned char  link_ok;          /* link up? */
 };
 
-#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
 
 enum {
        MAX_ETH_QSETS = 32,           /* # of Ethernet Tx/Rx queue sets */
@@ -1085,4 +1085,5 @@ void t4_db_dropped(struct adapter *adapter);
 int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
                         u32 addr, u32 val);
 void t4_sge_decode_idma_state(struct adapter *adapter, int state);
+void t4_free_mem(void *addr);
 #endif /* __CXGB4_H__ */
index 2a6aa88984f44f31d34cc55664705ac6b8dc4a90..c0724a5b5942e33dfc374b6d6e395820f04af90b 100644 (file)
@@ -42,9 +42,9 @@
        do { \
                memset(&(__pcmd), 0, sizeof(__pcmd)); \
                (__pcmd).op_to_portid = \
-                       cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) | \
-                                   FW_CMD_REQUEST | \
-                                   FW_CMD_##__op | \
+                       cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) | \
+                                   FW_CMD_REQUEST_F | \
+                                   FW_CMD_##__op##_F | \
                                    FW_PORT_CMD_PORTID(__port)); \
                (__pcmd).action_to_len16 = \
                        cpu_to_be32(FW_PORT_CMD_ACTION(__action) | \
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
new file mode 100644 (file)
index 0000000..c98a350
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/string_helpers.h>
+#include <linux/sort.h>
+
+#include "cxgb4.h"
+#include "t4_regs.h"
+#include "t4fw_api.h"
+#include "cxgb4_debugfs.h"
+#include "l2t.h"
+
+static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
+                       loff_t *ppos)
+{
+       loff_t pos = *ppos;
+       loff_t avail = file_inode(file)->i_size;
+       unsigned int mem = (uintptr_t)file->private_data & 3;
+       struct adapter *adap = file->private_data - mem;
+       __be32 *data;
+       int ret;
+
+       if (pos < 0)
+               return -EINVAL;
+       if (pos >= avail)
+               return 0;
+       if (count > avail - pos)
+               count = avail - pos;
+
+       data = t4_alloc_mem(count);
+       if (!data)
+               return -ENOMEM;
+
+       spin_lock(&adap->win0_lock);
+       ret = t4_memory_rw(adap, 0, mem, pos, count, data, T4_MEMORY_READ);
+       spin_unlock(&adap->win0_lock);
+       if (ret) {
+               t4_free_mem(data);
+               return ret;
+       }
+       ret = copy_to_user(buf, data, count);
+
+       t4_free_mem(data);
+       if (ret)
+               return -EFAULT;
+
+       *ppos = pos + count;
+       return count;
+}
+
+static const struct file_operations mem_debugfs_fops = {
+       .owner   = THIS_MODULE,
+       .open    = simple_open,
+       .read    = mem_read,
+       .llseek  = default_llseek,
+};
+
+static void add_debugfs_mem(struct adapter *adap, const char *name,
+                           unsigned int idx, unsigned int size_mb)
+{
+       struct dentry *de;
+
+       de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root,
+                                (void *)adap + idx, &mem_debugfs_fops);
+       if (de && de->d_inode)
+               de->d_inode->i_size = size_mb << 20;
+}
+
+/* Add an array of Debug FS files.
+ */
+void add_debugfs_files(struct adapter *adap,
+                      struct t4_debugfs_entry *files,
+                      unsigned int nfiles)
+{
+       int i;
+
+       /* debugfs support is best effort */
+       for (i = 0; i < nfiles; i++)
+               debugfs_create_file(files[i].name, files[i].mode,
+                                   adap->debugfs_root,
+                                   (void *)adap + files[i].data,
+                                   files[i].ops);
+}
+
+int t4_setup_debugfs(struct adapter *adap)
+{
+       int i;
+       u32 size;
+
+       static struct t4_debugfs_entry t4_debugfs_files[] = {
+               { "l2t", &t4_l2t_fops, S_IRUSR, 0},
+       };
+
+       add_debugfs_files(adap,
+                         t4_debugfs_files,
+                         ARRAY_SIZE(t4_debugfs_files));
+
+       i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
+       if (i & EDRAM0_ENABLE_F) {
+               size = t4_read_reg(adap, MA_EDRAM0_BAR_A);
+               add_debugfs_mem(adap, "edc0", MEM_EDC0, EDRAM0_SIZE_G(size));
+       }
+       if (i & EDRAM1_ENABLE_F) {
+               size = t4_read_reg(adap, MA_EDRAM1_BAR_A);
+               add_debugfs_mem(adap, "edc1", MEM_EDC1, EDRAM1_SIZE_G(size));
+       }
+       if (is_t4(adap->params.chip)) {
+               size = t4_read_reg(adap, MA_EXT_MEMORY_BAR_A);
+               if (i & EXT_MEM_ENABLE_F)
+                       add_debugfs_mem(adap, "mc", MEM_MC,
+                                       EXT_MEM_SIZE_G(size));
+       } else {
+               if (i & EXT_MEM0_ENABLE_F) {
+                       size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
+                       add_debugfs_mem(adap, "mc0", MEM_MC0,
+                                       EXT_MEM0_SIZE_G(size));
+               }
+               if (i & EXT_MEM1_ENABLE_F) {
+                       size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
+                       add_debugfs_mem(adap, "mc1", MEM_MC1,
+                                       EXT_MEM1_SIZE_G(size));
+               }
+       }
+       return 0;
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h
new file mode 100644 (file)
index 0000000..a3d8867
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CXGB4_DEBUGFS_H
+#define __CXGB4_DEBUGFS_H
+
+#include <linux/export.h>
+
+struct t4_debugfs_entry {
+       const char *name;
+       const struct file_operations *ops;
+       mode_t mode;
+       unsigned char data;
+};
+
+int t4_setup_debugfs(struct adapter *adap);
+void add_debugfs_files(struct adapter *adap,
+                      struct t4_debugfs_entry *files,
+                      unsigned int nfiles);
+
+#endif
index 8520d5529df872fad60a377231f5154fcf91a4e3..d13d36abe55ce4b4597e2f68afac4809ae1664c4 100644 (file)
@@ -61,6 +61,7 @@
 #include <net/neighbour.h>
 #include <net/netevent.h>
 #include <net/addrconf.h>
+#include <net/bonding.h>
 #include <asm/uaccess.h>
 
 #include "cxgb4.h"
 #include "t4_msg.h"
 #include "t4fw_api.h"
 #include "cxgb4_dcb.h"
+#include "cxgb4_debugfs.h"
 #include "l2t.h"
 
-#include <../drivers/net/bonding/bonding.h>
-
 #ifdef DRV_VERSION
 #undef DRV_VERSION
 #endif
@@ -832,7 +832,7 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
 
 #ifdef CONFIG_CHELSIO_T4_DCB
                const struct fw_port_cmd *pcmd = (const void *)p->data;
-               unsigned int cmd = FW_CMD_OP_GET(ntohl(pcmd->op_to_portid));
+               unsigned int cmd = FW_CMD_OP_G(ntohl(pcmd->op_to_portid));
                unsigned int action =
                        FW_PORT_CMD_ACTION_GET(ntohl(pcmd->action_to_len16));
 
@@ -1287,7 +1287,7 @@ void *t4_alloc_mem(size_t size)
 /*
  * Free memory allocated through alloc_mem().
  */
-static void t4_free_mem(void *addr)
+void t4_free_mem(void *addr)
 {
        if (is_vmalloc_addr(addr))
                vfree(addr);
@@ -1339,8 +1339,8 @@ static int set_filter_wr(struct adapter *adapter, int fidx)
         * filter specification structure but for now it's easiest to simply
         * put this fairly direct code in line ...
         */
-       fwr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
-       fwr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*fwr)/16));
+       fwr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
+       fwr->len16_pkd = htonl(FW_WR_LEN16_V(sizeof(*fwr)/16));
        fwr->tid_to_iq =
                htonl(V_FW_FILTER_WR_TID(ftid) |
                      V_FW_FILTER_WR_RQTYPE(f->fs.type) |
@@ -3127,102 +3127,14 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
        .flash_device      = set_flash,
 };
 
-/*
- * debugfs support
- */
-static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
-                       loff_t *ppos)
-{
-       loff_t pos = *ppos;
-       loff_t avail = file_inode(file)->i_size;
-       unsigned int mem = (uintptr_t)file->private_data & 3;
-       struct adapter *adap = file->private_data - mem;
-       __be32 *data;
-       int ret;
-
-       if (pos < 0)
-               return -EINVAL;
-       if (pos >= avail)
-               return 0;
-       if (count > avail - pos)
-               count = avail - pos;
-
-       data = t4_alloc_mem(count);
-       if (!data)
-               return -ENOMEM;
-
-       spin_lock(&adap->win0_lock);
-       ret = t4_memory_rw(adap, 0, mem, pos, count, data, T4_MEMORY_READ);
-       spin_unlock(&adap->win0_lock);
-       if (ret) {
-               t4_free_mem(data);
-               return ret;
-       }
-       ret = copy_to_user(buf, data, count);
-
-       t4_free_mem(data);
-       if (ret)
-               return -EFAULT;
-
-       *ppos = pos + count;
-       return count;
-}
-
-static const struct file_operations mem_debugfs_fops = {
-       .owner   = THIS_MODULE,
-       .open    = simple_open,
-       .read    = mem_read,
-       .llseek  = default_llseek,
-};
-
-static void add_debugfs_mem(struct adapter *adap, const char *name,
-                           unsigned int idx, unsigned int size_mb)
-{
-       struct dentry *de;
-
-       de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root,
-                                (void *)adap + idx, &mem_debugfs_fops);
-       if (de && de->d_inode)
-               de->d_inode->i_size = size_mb << 20;
-}
-
 static int setup_debugfs(struct adapter *adap)
 {
-       int i;
-       u32 size;
-
        if (IS_ERR_OR_NULL(adap->debugfs_root))
                return -1;
 
-       i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE);
-       if (i & EDRAM0_ENABLE) {
-               size = t4_read_reg(adap, MA_EDRAM0_BAR);
-               add_debugfs_mem(adap, "edc0", MEM_EDC0, EDRAM_SIZE_GET(size));
-       }
-       if (i & EDRAM1_ENABLE) {
-               size = t4_read_reg(adap, MA_EDRAM1_BAR);
-               add_debugfs_mem(adap, "edc1", MEM_EDC1, EDRAM_SIZE_GET(size));
-       }
-       if (is_t4(adap->params.chip)) {
-               size = t4_read_reg(adap, MA_EXT_MEMORY_BAR);
-               if (i & EXT_MEM_ENABLE)
-                       add_debugfs_mem(adap, "mc", MEM_MC,
-                                       EXT_MEM_SIZE_GET(size));
-       } else {
-               if (i & EXT_MEM_ENABLE) {
-                       size = t4_read_reg(adap, MA_EXT_MEMORY_BAR);
-                       add_debugfs_mem(adap, "mc0", MEM_MC0,
-                                       EXT_MEM_SIZE_GET(size));
-               }
-               if (i & EXT_MEM1_ENABLE) {
-                       size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR);
-                       add_debugfs_mem(adap, "mc1", MEM_MC1,
-                                       EXT_MEM_SIZE_GET(size));
-               }
-       }
-       if (adap->l2t)
-               debugfs_create_file("l2t", S_IRUSR, adap->debugfs_root, adap,
-                                   &t4_l2t_fops);
+#ifdef CONFIG_DEBUG_FS
+       t4_setup_debugfs(adap);
+#endif
        return 0;
 }
 
@@ -3504,8 +3416,8 @@ int cxgb4_clip_get(const struct net_device *dev,
 
        adap = netdev2adap(dev);
        memset(&c, 0, sizeof(c));
-       c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
-                       FW_CMD_REQUEST | FW_CMD_WRITE);
+       c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+                       FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
        c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c));
        c.ip_hi = *(__be64 *)(lip->s6_addr);
        c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
@@ -3521,8 +3433,8 @@ int cxgb4_clip_release(const struct net_device *dev,
 
        adap = netdev2adap(dev);
        memset(&c, 0, sizeof(c));
-       c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
-                       FW_CMD_REQUEST | FW_CMD_READ);
+       c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+                       FW_CMD_REQUEST_F | FW_CMD_READ_F);
        c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c));
        c.ip_hi = *(__be64 *)(lip->s6_addr);
        c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
@@ -3889,7 +3801,7 @@ int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
 {
        struct adapter *adap;
        u32 offset, memtype, memaddr;
-       u32 edc0_size, edc1_size, mc0_size, mc1_size;
+       u32 edc0_size, edc1_size, mc0_size, mc1_size, size;
        u32 edc0_end, edc1_end, mc0_end, mc1_end;
        int ret;
 
@@ -3903,9 +3815,12 @@ int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
         * and EDC1.  Some cards will have neither MC0 nor MC1, most cards have
         * MC0, and some have both MC0 and MC1.
         */
-       edc0_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR)) << 20;
-       edc1_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM1_BAR)) << 20;
-       mc0_size = EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR)) << 20;
+       size = t4_read_reg(adap, MA_EDRAM0_BAR_A);
+       edc0_size = EDRAM0_SIZE_G(size) << 20;
+       size = t4_read_reg(adap, MA_EDRAM1_BAR_A);
+       edc1_size = EDRAM1_SIZE_G(size) << 20;
+       size = t4_read_reg(adap, MA_EXT_MEMORY0_BAR_A);
+       mc0_size = EXT_MEM0_SIZE_G(size) << 20;
 
        edc0_end = edc0_size;
        edc1_end = edc0_end + edc1_size;
@@ -3925,9 +3840,8 @@ int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
                        /* T4 only has a single memory channel */
                        goto err;
                } else {
-                       mc1_size = EXT_MEM_SIZE_GET(
-                                       t4_read_reg(adap,
-                                                   MA_EXT_MEMORY1_BAR)) << 20;
+                       size = t4_read_reg(adap, MA_EXT_MEMORY1_BAR_A);
+                       mc1_size = EXT_MEM1_SIZE_G(size) << 20;
                        mc1_end = mc0_end + mc1_size;
                        if (offset < mc1_end) {
                                memtype = MEM_MC1;
@@ -4395,8 +4309,7 @@ static int clip_add(struct net_device *event_dev, struct inet6_ifaddr *ifa,
        if (cxgb4_netdev(event_dev)) {
                switch (event) {
                case NETDEV_UP:
-                       ret = cxgb4_clip_get(event_dev,
-                               (const struct in6_addr *)ifa->addr.s6_addr);
+                       ret = cxgb4_clip_get(event_dev, &ifa->addr);
                        if (ret < 0) {
                                rcu_read_unlock();
                                return ret;
@@ -4404,8 +4317,7 @@ static int clip_add(struct net_device *event_dev, struct inet6_ifaddr *ifa,
                        ret = NOTIFY_OK;
                        break;
                case NETDEV_DOWN:
-                       cxgb4_clip_release(event_dev,
-                               (const struct in6_addr *)ifa->addr.s6_addr);
+                       cxgb4_clip_release(event_dev, &ifa->addr);
                        ret = NOTIFY_OK;
                        break;
                default:
@@ -4474,8 +4386,7 @@ static int update_dev_clip(struct net_device *root_dev, struct net_device *dev)
 
        read_lock_bh(&idev->lock);
        list_for_each_entry(ifa, &idev->addr_list, if_list) {
-               ret = cxgb4_clip_get(dev,
-                               (const struct in6_addr *)ifa->addr.s6_addr);
+               ret = cxgb4_clip_get(dev, &ifa->addr);
                if (ret < 0)
                        break;
        }
@@ -4956,9 +4867,9 @@ static u32 t4_read_pcie_cfg4(struct adapter *adap, int reg)
         */
        memset(&ldst_cmd, 0, sizeof(ldst_cmd));
        ldst_cmd.op_to_addrspace =
-               htonl(FW_CMD_OP(FW_LDST_CMD) |
-                     FW_CMD_REQUEST |
-                     FW_CMD_READ |
+               htonl(FW_CMD_OP_V(FW_LDST_CMD) |
+                     FW_CMD_REQUEST_F |
+                     FW_CMD_READ_F |
                      FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE));
        ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
        ldst_cmd.u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1);
@@ -5050,8 +4961,8 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
 
        /* get device capabilities */
        memset(c, 0, sizeof(*c));
-       c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                              FW_CMD_REQUEST | FW_CMD_READ);
+       c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                              FW_CMD_REQUEST_F | FW_CMD_READ_F);
        c->cfvalid_to_len16 = htonl(FW_LEN16(*c));
        ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), c);
        if (ret < 0)
@@ -5067,8 +4978,8 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
                dev_err(adap->pdev_dev, "virtualization ACLs not supported");
                return ret;
        }
-       c->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                              FW_CMD_REQUEST | FW_CMD_WRITE);
+       c->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                              FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
        ret = t4_wr_mbox(adap, adap->fn, c, sizeof(*c), NULL);
        if (ret < 0)
                return ret;
@@ -5294,9 +5205,9 @@ static int adap_init0_config(struct adapter *adapter, int reset)
         */
        memset(&caps_cmd, 0, sizeof(caps_cmd));
        caps_cmd.op_to_write =
-               htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                     FW_CMD_REQUEST |
-                     FW_CMD_READ);
+               htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                     FW_CMD_REQUEST_F |
+                     FW_CMD_READ_F);
        caps_cmd.cfvalid_to_len16 =
                htonl(FW_CAPS_CONFIG_CMD_CFVALID |
                      FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
@@ -5314,9 +5225,9 @@ static int adap_init0_config(struct adapter *adapter, int reset)
        if (ret == -ENOENT) {
                memset(&caps_cmd, 0, sizeof(caps_cmd));
                caps_cmd.op_to_write =
-                       htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                                       FW_CMD_REQUEST |
-                                       FW_CMD_READ);
+                       htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                                       FW_CMD_REQUEST_F |
+                                       FW_CMD_READ_F);
                caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
                ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd,
                                sizeof(caps_cmd), &caps_cmd);
@@ -5339,9 +5250,9 @@ static int adap_init0_config(struct adapter *adapter, int reset)
         * And now tell the firmware to use the configuration we just loaded.
         */
        caps_cmd.op_to_write =
-               htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                     FW_CMD_REQUEST |
-                     FW_CMD_WRITE);
+               htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                     FW_CMD_REQUEST_F |
+                     FW_CMD_WRITE_F);
        caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
                         NULL);
@@ -5412,8 +5323,8 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
         * Get device capabilities and select which we'll be using.
         */
        memset(&caps_cmd, 0, sizeof(caps_cmd));
-       caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                                    FW_CMD_REQUEST | FW_CMD_READ);
+       caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                                    FW_CMD_REQUEST_F | FW_CMD_READ_F);
        caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
                         &caps_cmd);
@@ -5429,8 +5340,8 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
                dev_err(adapter->pdev_dev, "virtualization ACLs not supported");
                goto bye;
        }
-       caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                             FW_CMD_REQUEST | FW_CMD_WRITE);
+       caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                             FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
        ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
                         NULL);
        if (ret < 0)
@@ -5798,7 +5709,6 @@ static int adap_init0(struct adapter *adap)
        } else {
                dev_info(adap->pdev_dev, "Coming up as MASTER: "\
                         "Initializing adapter\n");
-
                /*
                 * If the firmware doesn't support Configuration
                 * Files warn user and exit,
@@ -5842,6 +5752,7 @@ static int adap_init0(struct adapter *adap)
                                            "No Configuration File present "
                                            "on adapter. Using hard-wired "
                                            "configuration parameters.\n");
+                                       goto bye;
                                        ret = adap_init0_no_config(adap, reset);
                                }
                        }
@@ -5941,8 +5852,8 @@ static int adap_init0(struct adapter *adap)
         * to manage.
         */
        memset(&caps_cmd, 0, sizeof(caps_cmd));
-       caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                                    FW_CMD_REQUEST | FW_CMD_READ);
+       caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                                    FW_CMD_REQUEST_F | FW_CMD_READ_F);
        caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
        ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
                         &caps_cmd);
index 1366ba620c87cdf506e1bd0757d7062cd5bf605e..4eba7cb1b89ce8d2142c940a8f3e2e315dce6629 100644 (file)
@@ -52,10 +52,10 @@ enum {
 };
 
 #define INIT_TP_WR(w, tid) do { \
-       (w)->wr.wr_hi = htonl(FW_WR_OP(FW_TP_WR) | \
-                             FW_WR_IMMDLEN(sizeof(*w) - sizeof(w->wr))); \
-       (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(sizeof(*w), 16)) | \
-                              FW_WR_FLOWID(tid)); \
+       (w)->wr.wr_hi = htonl(FW_WR_OP_V(FW_TP_WR) | \
+                             FW_WR_IMMDLEN_V(sizeof(*w) - sizeof(w->wr))); \
+       (w)->wr.wr_mid = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*w), 16)) | \
+                              FW_WR_FLOWID_V(tid)); \
        (w)->wr.wr_lo = cpu_to_be64(0); \
 } while (0)
 
@@ -65,9 +65,10 @@ enum {
 } while (0)
 
 #define INIT_ULPTX_WR(w, wrlen, atomic, tid) do { \
-       (w)->wr.wr_hi = htonl(FW_WR_OP(FW_ULPTX_WR) | FW_WR_ATOMIC(atomic)); \
-       (w)->wr.wr_mid = htonl(FW_WR_LEN16(DIV_ROUND_UP(wrlen, 16)) | \
-                              FW_WR_FLOWID(tid)); \
+       (w)->wr.wr_hi = htonl(FW_WR_OP_V(FW_ULPTX_WR) | \
+                             FW_WR_ATOMIC_V(atomic)); \
+       (w)->wr.wr_mid = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(wrlen, 16)) | \
+                              FW_WR_FLOWID_V(tid)); \
        (w)->wr.wr_lo = cpu_to_be64(0); \
 } while (0)
 
index 5e1b314e11af674f8d0f7f1ebf3bed60835dda08..6399e008a7f7065c7d2dde8af1ec94d1c00fa2b3 100644 (file)
@@ -1092,10 +1092,10 @@ out_free:       dev_kfree_skb_any(skb);
                goto out_free;
        }
 
-       wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2));
+       wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2));
        if (unlikely(credits < ETHTXQ_STOP_THRES)) {
                eth_txq_stop(q);
-               wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ;
+               wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
        }
 
        wr = (void *)&q->q.desc[q->q.pidx];
@@ -1112,8 +1112,8 @@ out_free: dev_kfree_skb_any(skb);
                int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
 
                len += sizeof(*lso);
-               wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
-                                      FW_WR_IMMDLEN(len));
+               wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
+                                      FW_WR_IMMDLEN_V(len));
                lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
                                        LSO_FIRST_SLICE | LSO_LAST_SLICE |
                                        LSO_IPV6(v6) |
@@ -1135,8 +1135,8 @@ out_free: dev_kfree_skb_any(skb);
                q->tx_cso += ssi->gso_segs;
        } else {
                len += sizeof(*cpl);
-               wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
-                                      FW_WR_IMMDLEN(len));
+               wr->op_immdlen = htonl(FW_WR_OP_V(FW_ETH_TX_PKT_WR) |
+                                      FW_WR_IMMDLEN_V(len));
                cpl = (void *)(wr + 1);
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        cntrl = hwcsum(skb) | TXPKT_IPCSUM_DIS;
@@ -1224,7 +1224,7 @@ static void ctrlq_check_stop(struct sge_ctrl_txq *q, struct fw_wr_hdr *wr)
 {
        reclaim_completed_tx_imm(&q->q);
        if (unlikely(txq_avail(&q->q) < TXQ_STOP_THRES)) {
-               wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ);
+               wr->lo |= htonl(FW_WR_EQUEQ_F | FW_WR_EQUIQ_F);
                q->q.stops++;
                q->full = 1;
        }
@@ -1406,7 +1406,7 @@ static void ofldtxq_stop(struct sge_ofld_txq *q, struct sk_buff *skb)
 {
        struct fw_wr_hdr *wr = (struct fw_wr_hdr *)skb->data;
 
-       wr->lo |= htonl(FW_WR_EQUEQ | FW_WR_EQUIQ);
+       wr->lo |= htonl(FW_WR_EQUEQ_F | FW_WR_EQUIQ_F);
        q->q.stops++;
        q->full = 1;
 }
@@ -2297,8 +2297,8 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
                return -ENOMEM;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_CMD_EXEC |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_CMD_EXEC_F |
                            FW_IQ_CMD_PFN(adap->fn) | FW_IQ_CMD_VFN(0));
        c.alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC | FW_IQ_CMD_IQSTART(1) |
                                 FW_LEN16(c));
@@ -2423,8 +2423,8 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
                return -ENOMEM;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_CMD_EXEC |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_CMD_EXEC_F |
                            FW_EQ_ETH_CMD_PFN(adap->fn) | FW_EQ_ETH_CMD_VFN(0));
        c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_ALLOC |
                                 FW_EQ_ETH_CMD_EQSTART | FW_LEN16(c));
@@ -2476,8 +2476,8 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
        if (!txq->q.desc)
                return -ENOMEM;
 
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_CMD_EXEC |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_CMD_EXEC_F |
                            FW_EQ_CTRL_CMD_PFN(adap->fn) |
                            FW_EQ_CTRL_CMD_VFN(0));
        c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_ALLOC |
@@ -2530,8 +2530,8 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
                return -ENOMEM;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_CMD_EXEC |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_CMD_EXEC_F |
                            FW_EQ_OFLD_CMD_PFN(adap->fn) |
                            FW_EQ_OFLD_CMD_VFN(0));
        c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC |
index a9d9d74e4f092f969c2d58eaf01455b7bca7e257..2bb4efa7db98fd485d8eaed4859d7222102046fc 100644 (file)
@@ -310,16 +310,17 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
                        }
 
                        res = t4_read_reg64(adap, data_reg);
-                       if (FW_CMD_OP_GET(res >> 32) == FW_DEBUG_CMD) {
+                       if (FW_CMD_OP_G(res >> 32) == FW_DEBUG_CMD) {
                                fw_asrt(adap, data_reg);
-                               res = FW_CMD_RETVAL(EIO);
-                       } else if (rpl)
+                               res = FW_CMD_RETVAL_V(EIO);
+                       } else if (rpl) {
                                get_mbox_rpl(adap, rpl, size / 8, data_reg);
+                       }
 
-                       if (FW_CMD_RETVAL_GET((int)res))
+                       if (FW_CMD_RETVAL_G((int)res))
                                dump_mbox(adap, mbox, data_reg);
                        t4_write_reg(adap, ctl_reg, 0);
-                       return -FW_CMD_RETVAL_GET((int)res);
+                       return -FW_CMD_RETVAL_G((int)res);
                }
        }
 
@@ -483,12 +484,12 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
         * MEM_MC0  = 2 -- For T5
         * MEM_MC1  = 3 -- For T5
         */
-       edc_size  = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR));
+       edc_size  = EDRAM0_SIZE_G(t4_read_reg(adap, MA_EDRAM0_BAR_A));
        if (mtype != MEM_MC1)
                memoffset = (mtype * (edc_size * 1024 * 1024));
        else {
-               mc_size = EXT_MEM_SIZE_GET(t4_read_reg(adap,
-                                                      MA_EXT_MEMORY_BAR));
+               mc_size = EXT_MEM0_SIZE_G(t4_read_reg(adap,
+                                                     MA_EXT_MEMORY1_BAR_A));
                memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
        }
 
@@ -1245,8 +1246,8 @@ int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
                fc |= FW_PORT_CAP_FC_TX;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST |
-                              FW_CMD_EXEC | FW_PORT_CMD_PORTID(port));
+       c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F |
+                              FW_CMD_EXEC_F | FW_PORT_CMD_PORTID(port));
        c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
                                  FW_LEN16(c));
 
@@ -1275,8 +1276,8 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
        struct fw_port_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST |
-                              FW_CMD_EXEC | FW_PORT_CMD_PORTID(port));
+       c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) | FW_CMD_REQUEST_F |
+                              FW_CMD_EXEC_F | FW_PORT_CMD_PORTID(port));
        c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
                                  FW_LEN16(c));
        c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG);
@@ -2071,8 +2072,8 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
        struct fw_rss_ind_tbl_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = htonl(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
-                              FW_CMD_REQUEST | FW_CMD_WRITE |
+       cmd.op_to_viid = htonl(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) |
+                              FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
                               FW_RSS_IND_TBL_CMD_VIID(viid));
        cmd.retval_len16 = htonl(FW_LEN16(cmd));
 
@@ -2126,8 +2127,8 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
        struct fw_rss_glb_config_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
-                             FW_CMD_REQUEST | FW_CMD_WRITE);
+       c.op_to_write = htonl(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) |
+                             FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
        c.retval_len16 = htonl(FW_LEN16(c));
        if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
                c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode));
@@ -2553,8 +2554,8 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
 void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
 {
        memset(wr, 0, sizeof(*wr));
-       wr->op_pkd = htonl(FW_WR_OP(FW_FILTER_WR));
-       wr->len16_pkd = htonl(FW_WR_LEN16(sizeof(*wr) / 16));
+       wr->op_pkd = htonl(FW_WR_OP_V(FW_FILTER_WR));
+       wr->len16_pkd = htonl(FW_WR_LEN16_V(sizeof(*wr) / 16));
        wr->tid_to_iq = htonl(V_FW_FILTER_WR_TID(ftid) |
                        V_FW_FILTER_WR_NOREPLY(qid < 0));
        wr->del_filter_to_l2tix = htonl(F_FW_FILTER_WR_DEL_FILTER);
@@ -2563,8 +2564,8 @@ void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid)
 }
 
 #define INIT_CMD(var, cmd, rd_wr) do { \
-       (var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \
-                                 FW_CMD_REQUEST | FW_CMD_##rd_wr); \
+       (var).op_to_write = htonl(FW_CMD_OP_V(FW_##cmd##_CMD) | \
+                                 FW_CMD_REQUEST_F | FW_CMD_##rd_wr##_F); \
        (var).retval_len16 = htonl(FW_LEN16(var)); \
 } while (0)
 
@@ -2574,8 +2575,8 @@ int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
        struct fw_ldst_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE |
+       c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F |
                            FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
        c.cycles_to_len16 = htonl(FW_LEN16(c));
        c.u.addrval.addr = htonl(addr);
@@ -2602,8 +2603,8 @@ int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
        struct fw_ldst_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
-               FW_CMD_READ | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
+       c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
+               FW_CMD_READ_F | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
        c.cycles_to_len16 = htonl(FW_LEN16(c));
        c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) |
                                   FW_LDST_CMD_MMD(mmd));
@@ -2632,8 +2633,8 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
        struct fw_ldst_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
-               FW_CMD_WRITE | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
+       c.op_to_addrspace = htonl(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F |
+               FW_CMD_WRITE_F | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
        c.cycles_to_len16 = htonl(FW_LEN16(c));
        c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) |
                                   FW_LDST_CMD_MMD(mmd));
@@ -3211,8 +3212,8 @@ int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
                return -EINVAL;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_READ | FW_PARAMS_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_READ_F | FW_PARAMS_CMD_PFN(pf) |
                            FW_PARAMS_CMD_VFN(vf));
        c.retval_len16 = htonl(FW_LEN16(c));
        for (i = 0; i < nparams; i++, p += 2)
@@ -3251,8 +3252,8 @@ int t4_set_params_nosleep(struct adapter *adap, unsigned int mbox,
                return -EINVAL;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
-                               FW_CMD_REQUEST | FW_CMD_WRITE |
+       c.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+                               FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
                                FW_PARAMS_CMD_PFN(pf) |
                                FW_PARAMS_CMD_VFN(vf));
        c.retval_len16 = cpu_to_be32(FW_LEN16(c));
@@ -3289,8 +3290,8 @@ int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
                return -EINVAL;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_PARAMS_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_PARAMS_CMD_PFN(pf) |
                            FW_PARAMS_CMD_VFN(vf));
        c.retval_len16 = htonl(FW_LEN16(c));
        while (nparams--) {
@@ -3331,8 +3332,8 @@ int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
        struct fw_pfvf_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_PFVF_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_PFVF_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_PFVF_CMD_PFN(pf) |
                            FW_PFVF_CMD_VFN(vf));
        c.retval_len16 = htonl(FW_LEN16(c));
        c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) |
@@ -3373,8 +3374,8 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
        struct fw_vi_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_WRITE | FW_CMD_EXEC |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_VI_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_WRITE_F | FW_CMD_EXEC_F |
                            FW_VI_CMD_PFN(pf) | FW_VI_CMD_VFN(vf));
        c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC | FW_LEN16(c));
        c.portid_pkd = FW_VI_CMD_PORTID(port);
@@ -3435,8 +3436,8 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
                vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST |
-                            FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid));
+       c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST_F |
+                            FW_CMD_WRITE_F | FW_VI_RXMODE_CMD_VIID(viid));
        c.retval_len16 = htonl(FW_LEN16(c));
        c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU(mtu) |
                                  FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
@@ -3483,11 +3484,11 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
                return -EINVAL;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
-                            FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) |
+       c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
+                            FW_CMD_WRITE_F | (free ? FW_CMD_EXEC_F : 0) |
                             FW_VI_MAC_CMD_VIID(viid));
        c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS(free) |
-                                   FW_CMD_LEN16((naddr + 2) / 2));
+                                   FW_CMD_LEN16_V((naddr + 2) / 2));
 
        for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
                p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID |
@@ -3546,9 +3547,9 @@ int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
        mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
-                            FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid));
-       c.freemacs_to_len16 = htonl(FW_CMD_LEN16(1));
+       c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
+                            FW_CMD_WRITE_F | FW_VI_MAC_CMD_VIID(viid));
+       c.freemacs_to_len16 = htonl(FW_CMD_LEN16_V(1));
        p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID |
                                FW_VI_MAC_CMD_SMAC_RESULT(mode) |
                                FW_VI_MAC_CMD_IDX(idx));
@@ -3580,11 +3581,11 @@ int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
        struct fw_vi_mac_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
-                            FW_CMD_WRITE | FW_VI_ENABLE_CMD_VIID(viid));
+       c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_MAC_CMD) | FW_CMD_REQUEST_F |
+                            FW_CMD_WRITE_F | FW_VI_ENABLE_CMD_VIID(viid));
        c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN |
                                    FW_VI_MAC_CMD_HASHUNIEN(ucast) |
-                                   FW_CMD_LEN16(1));
+                                   FW_CMD_LEN16_V(1));
        c.u.hash.hashvec = cpu_to_be64(vec);
        return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
 }
@@ -3607,8 +3608,8 @@ int t4_enable_vi_params(struct adapter *adap, unsigned int mbox,
        struct fw_vi_enable_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
-                            FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
+       c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST_F |
+                            FW_CMD_EXEC_F | FW_VI_ENABLE_CMD_VIID(viid));
 
        c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) |
                               FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c) |
@@ -3647,8 +3648,8 @@ int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
        struct fw_vi_enable_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
-                            FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
+       c.op_to_viid = htonl(FW_CMD_OP_V(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST_F |
+                            FW_CMD_EXEC_F | FW_VI_ENABLE_CMD_VIID(viid));
        c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
        c.blinkdur = htons(nblinks);
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
@@ -3674,8 +3675,8 @@ int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
        struct fw_iq_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_EXEC_F | FW_IQ_CMD_PFN(pf) |
                            FW_IQ_CMD_VFN(vf));
        c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE | FW_LEN16(c));
        c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iqtype));
@@ -3701,8 +3702,8 @@ int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
        struct fw_eq_eth_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_EXEC | FW_EQ_ETH_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_ETH_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_EXEC_F | FW_EQ_ETH_CMD_PFN(pf) |
                            FW_EQ_ETH_CMD_VFN(vf));
        c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
        c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID(eqid));
@@ -3725,8 +3726,8 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
        struct fw_eq_ctrl_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_EXEC | FW_EQ_CTRL_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_EXEC_F | FW_EQ_CTRL_CMD_PFN(pf) |
                            FW_EQ_CTRL_CMD_VFN(vf));
        c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
        c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID(eqid));
@@ -3749,8 +3750,8 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
        struct fw_eq_ofld_cmd c;
 
        memset(&c, 0, sizeof(c));
-       c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
-                           FW_CMD_EXEC | FW_EQ_OFLD_CMD_PFN(pf) |
+       c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
+                           FW_CMD_EXEC_F | FW_EQ_OFLD_CMD_PFN(pf) |
                            FW_EQ_OFLD_CMD_VFN(vf));
        c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE | FW_LEN16(c));
        c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eqid));
@@ -4082,8 +4083,8 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
                while ((adap->params.portvec & (1 << j)) == 0)
                        j++;
 
-               c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) |
-                                      FW_CMD_REQUEST | FW_CMD_READ |
+               c.op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_READ_F |
                                       FW_PORT_CMD_PORTID(j));
                c.action_to_len16 = htonl(
                        FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
@@ -4109,8 +4110,8 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
                p->port_type = FW_PORT_CMD_PTYPE_GET(ret);
                p->mod_type = FW_PORT_MOD_TYPE_NA;
 
-               rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
-                                      FW_CMD_REQUEST | FW_CMD_READ |
+               rvc.op_to_viid = htonl(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_READ_F |
                                       FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
                rvc.retval_len16 = htonl(FW_LEN16(rvc));
                ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
index a1024db5dc136bb2a64fe5d3d696580ae3e38434..c8eb7ba225e1ae715567b0d0c6497f25a0da1897 100644 (file)
 
 #define MC_BIST_STATUS_RDATA 0x7688
 
-#define MA_EDRAM0_BAR 0x77c0
-#define MA_EDRAM1_BAR 0x77c4
-#define EDRAM_SIZE_MASK   0xfffU
-#define EDRAM_SIZE_GET(x) ((x) & EDRAM_SIZE_MASK)
-
-#define MA_EXT_MEMORY_BAR 0x77c8
-#define  EXT_MEM_SIZE_MASK   0x00000fffU
-#define  EXT_MEM_SIZE_SHIFT  0
-#define  EXT_MEM_SIZE_GET(x) (((x) & EXT_MEM_SIZE_MASK) >> EXT_MEM_SIZE_SHIFT)
-
-#define MA_TARGET_MEM_ENABLE 0x77d8
-#define  EXT_MEM1_ENABLE 0x00000010U
-#define  EXT_MEM_ENABLE 0x00000004U
-#define  EDRAM1_ENABLE  0x00000002U
-#define  EDRAM0_ENABLE  0x00000001U
+#define MA_EDRAM0_BAR_A 0x77c0
+
+#define EDRAM0_SIZE_S    0
+#define EDRAM0_SIZE_M    0xfffU
+#define EDRAM0_SIZE_V(x) ((x) << EDRAM0_SIZE_S)
+#define EDRAM0_SIZE_G(x) (((x) >> EDRAM0_SIZE_S) & EDRAM0_SIZE_M)
+
+#define MA_EDRAM1_BAR_A 0x77c4
+
+#define EDRAM1_SIZE_S    0
+#define EDRAM1_SIZE_M    0xfffU
+#define EDRAM1_SIZE_V(x) ((x) << EDRAM1_SIZE_S)
+#define EDRAM1_SIZE_G(x) (((x) >> EDRAM1_SIZE_S) & EDRAM1_SIZE_M)
+
+#define MA_EXT_MEMORY_BAR_A 0x77c8
+
+#define EXT_MEM_SIZE_S    0
+#define EXT_MEM_SIZE_M    0xfffU
+#define EXT_MEM_SIZE_V(x) ((x) << EXT_MEM_SIZE_S)
+#define EXT_MEM_SIZE_G(x) (((x) >> EXT_MEM_SIZE_S) & EXT_MEM_SIZE_M)
+
+#define MA_EXT_MEMORY1_BAR_A 0x7808
+
+#define EXT_MEM1_SIZE_S    0
+#define EXT_MEM1_SIZE_M    0xfffU
+#define EXT_MEM1_SIZE_V(x) ((x) << EXT_MEM1_SIZE_S)
+#define EXT_MEM1_SIZE_G(x) (((x) >> EXT_MEM1_SIZE_S) & EXT_MEM1_SIZE_M)
+
+#define MA_EXT_MEMORY0_BAR_A 0x77c8
+
+#define EXT_MEM0_SIZE_S    0
+#define EXT_MEM0_SIZE_M    0xfffU
+#define EXT_MEM0_SIZE_V(x) ((x) << EXT_MEM0_SIZE_S)
+#define EXT_MEM0_SIZE_G(x) (((x) >> EXT_MEM0_SIZE_S) & EXT_MEM0_SIZE_M)
+
+#define MA_TARGET_MEM_ENABLE_A 0x77d8
+
+#define EXT_MEM_ENABLE_S    2
+#define EXT_MEM_ENABLE_V(x) ((x) << EXT_MEM_ENABLE_S)
+#define EXT_MEM_ENABLE_F    EXT_MEM_ENABLE_V(1U)
+
+#define EDRAM1_ENABLE_S    1
+#define EDRAM1_ENABLE_V(x) ((x) << EDRAM1_ENABLE_S)
+#define EDRAM1_ENABLE_F    EDRAM1_ENABLE_V(1U)
+
+#define EDRAM0_ENABLE_S    0
+#define EDRAM0_ENABLE_V(x) ((x) << EDRAM0_ENABLE_S)
+#define EDRAM0_ENABLE_F    EDRAM0_ENABLE_V(1U)
+
+#define EXT_MEM1_ENABLE_S    4
+#define EXT_MEM1_ENABLE_V(x) ((x) << EXT_MEM1_ENABLE_S)
+#define EXT_MEM1_ENABLE_F    EXT_MEM1_ENABLE_V(1U)
+
+#define EXT_MEM0_ENABLE_S    2
+#define EXT_MEM0_ENABLE_V(x) ((x) << EXT_MEM0_ENABLE_S)
+#define EXT_MEM0_ENABLE_F    EXT_MEM0_ENABLE_V(1U)
 
 #define MA_INT_CAUSE 0x77e0
 #define  MEM_PERR_INT_CAUSE 0x00000002U
 #define MA_PARITY_ERROR_STATUS 0x77f4
 #define MA_PARITY_ERROR_STATUS2 0x7804
 
-#define MA_EXT_MEMORY1_BAR 0x7808
 #define EDC_0_BASE_ADDR 0x7900
 
 #define EDC_BIST_CMD 0x7904
index 3409756a85b95586f7640033dc06bb274c4db139..7cca67fde4f4d1800d14ce690c43f8ace24ae29a 100644 (file)
@@ -109,18 +109,49 @@ struct fw_wr_hdr {
        __be32 lo;
 };
 
-#define FW_WR_OP(x)     ((x) << 24)
-#define FW_WR_OP_GET(x)         (((x) >> 24) & 0xff)
-#define FW_WR_ATOMIC(x)         ((x) << 23)
-#define FW_WR_FLUSH(x)   ((x) << 22)
-#define FW_WR_COMPL(x)   ((x) << 21)
-#define FW_WR_IMMDLEN_MASK 0xff
-#define FW_WR_IMMDLEN(x) ((x) << 0)
-
-#define FW_WR_EQUIQ    (1U << 31)
-#define FW_WR_EQUEQ    (1U << 30)
-#define FW_WR_FLOWID(x)        ((x) << 8)
-#define FW_WR_LEN16(x) ((x) << 0)
+/* work request opcode (hi) */
+#define FW_WR_OP_S     24
+#define FW_WR_OP_M      0xff
+#define FW_WR_OP_V(x)   ((x) << FW_WR_OP_S)
+#define FW_WR_OP_G(x)   (((x) >> FW_WR_OP_S) & FW_WR_OP_M)
+
+/* atomic flag (hi) - firmware encapsulates CPLs in CPL_BARRIER */
+#define FW_WR_ATOMIC_S         23
+#define FW_WR_ATOMIC_V(x)      ((x) << FW_WR_ATOMIC_S)
+
+/* flush flag (hi) - firmware flushes flushable work request buffered
+ * in the flow context.
+ */
+#define FW_WR_FLUSH_S     22
+#define FW_WR_FLUSH_V(x)  ((x) << FW_WR_FLUSH_S)
+
+/* completion flag (hi) - firmware generates a cpl_fw6_ack */
+#define FW_WR_COMPL_S     21
+#define FW_WR_COMPL_V(x)  ((x) << FW_WR_COMPL_S)
+#define FW_WR_COMPL_F     FW_WR_COMPL_V(1U)
+
+/* work request immediate data length (hi) */
+#define FW_WR_IMMDLEN_S 0
+#define FW_WR_IMMDLEN_M 0xff
+#define FW_WR_IMMDLEN_V(x)      ((x) << FW_WR_IMMDLEN_S)
+
+/* egress queue status update to associated ingress queue entry (lo) */
+#define FW_WR_EQUIQ_S           31
+#define FW_WR_EQUIQ_V(x)        ((x) << FW_WR_EQUIQ_S)
+#define FW_WR_EQUIQ_F           FW_WR_EQUIQ_V(1U)
+
+/* egress queue status update to egress queue status entry (lo) */
+#define FW_WR_EQUEQ_S           30
+#define FW_WR_EQUEQ_V(x)        ((x) << FW_WR_EQUEQ_S)
+#define FW_WR_EQUEQ_F           FW_WR_EQUEQ_V(1U)
+
+/* flow context identifier (lo) */
+#define FW_WR_FLOWID_S          8
+#define FW_WR_FLOWID_V(x)       ((x) << FW_WR_FLOWID_S)
+
+/* length in units of 16-bytes (lo) */
+#define FW_WR_LEN16_S           0
+#define FW_WR_LEN16_V(x)        ((x) << FW_WR_LEN16_S)
 
 #define HW_TPL_FR_MT_PR_IV_P_FC         0X32B
 #define HW_TPL_FR_MT_PR_OV_P_FC         0X327
@@ -539,26 +570,47 @@ struct fw_flowc_mnemval {
 
 struct fw_flowc_wr {
        __be32 op_to_nparams;
-#define FW_FLOWC_WR_NPARAMS(x) ((x) << 0)
        __be32 flowid_len16;
        struct fw_flowc_mnemval mnemval[0];
 };
 
+#define FW_FLOWC_WR_NPARAMS_S           0
+#define FW_FLOWC_WR_NPARAMS_V(x)        ((x) << FW_FLOWC_WR_NPARAMS_S)
+
 struct fw_ofld_tx_data_wr {
        __be32 op_to_immdlen;
        __be32 flowid_len16;
        __be32 plen;
        __be32 tunnel_to_proxy;
-#define FW_OFLD_TX_DATA_WR_TUNNEL(x)    ((x) << 19)
-#define FW_OFLD_TX_DATA_WR_SAVE(x)      ((x) << 18)
-#define FW_OFLD_TX_DATA_WR_FLUSH(x)     ((x) << 17)
-#define FW_OFLD_TX_DATA_WR_URGENT(x)    ((x) << 16)
-#define FW_OFLD_TX_DATA_WR_MORE(x)      ((x) << 15)
-#define FW_OFLD_TX_DATA_WR_SHOVE(x)     ((x) << 14)
-#define FW_OFLD_TX_DATA_WR_ULPMODE(x)   ((x) << 10)
-#define FW_OFLD_TX_DATA_WR_ULPSUBMODE(x) ((x) << 6)
 };
 
+#define FW_OFLD_TX_DATA_WR_TUNNEL_S     19
+#define FW_OFLD_TX_DATA_WR_TUNNEL_V(x)  ((x) << FW_OFLD_TX_DATA_WR_TUNNEL_S)
+
+#define FW_OFLD_TX_DATA_WR_SAVE_S       18
+#define FW_OFLD_TX_DATA_WR_SAVE_V(x)    ((x) << FW_OFLD_TX_DATA_WR_SAVE_S)
+
+#define FW_OFLD_TX_DATA_WR_FLUSH_S      17
+#define FW_OFLD_TX_DATA_WR_FLUSH_V(x)   ((x) << FW_OFLD_TX_DATA_WR_FLUSH_S)
+#define FW_OFLD_TX_DATA_WR_FLUSH_F      FW_OFLD_TX_DATA_WR_FLUSH_V(1U)
+
+#define FW_OFLD_TX_DATA_WR_URGENT_S     16
+#define FW_OFLD_TX_DATA_WR_URGENT_V(x)  ((x) << FW_OFLD_TX_DATA_WR_URGENT_S)
+
+#define FW_OFLD_TX_DATA_WR_MORE_S       15
+#define FW_OFLD_TX_DATA_WR_MORE_V(x)    ((x) << FW_OFLD_TX_DATA_WR_MORE_S)
+
+#define FW_OFLD_TX_DATA_WR_SHOVE_S      14
+#define FW_OFLD_TX_DATA_WR_SHOVE_V(x)   ((x) << FW_OFLD_TX_DATA_WR_SHOVE_S)
+#define FW_OFLD_TX_DATA_WR_SHOVE_F      FW_OFLD_TX_DATA_WR_SHOVE_V(1U)
+
+#define FW_OFLD_TX_DATA_WR_ULPMODE_S    10
+#define FW_OFLD_TX_DATA_WR_ULPMODE_V(x) ((x) << FW_OFLD_TX_DATA_WR_ULPMODE_S)
+
+#define FW_OFLD_TX_DATA_WR_ULPSUBMODE_S         6
+#define FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(x)      \
+       ((x) << FW_OFLD_TX_DATA_WR_ULPSUBMODE_S)
+
 struct fw_cmd_wr {
        __be32 op_dma;
 #define FW_CMD_WR_DMA (1U << 17)
@@ -566,6 +618,9 @@ struct fw_cmd_wr {
        __be64 cookie_daddr;
 };
 
+#define FW_CMD_WR_DMA_S         17
+#define FW_CMD_WR_DMA_V(x)      ((x) << FW_CMD_WR_DMA_S)
+
 struct fw_eth_tx_pkt_vm_wr {
        __be32 op_immdlen;
        __be32 equiq_to_len16;
@@ -641,18 +696,39 @@ struct fw_cmd_hdr {
        __be32 lo;
 };
 
-#define FW_CMD_OP(x)           ((x) << 24)
-#define FW_CMD_OP_GET(x)        (((x) >> 24) & 0xff)
-#define FW_CMD_REQUEST          (1U << 23)
-#define FW_CMD_REQUEST_GET(x)   (((x) >> 23) & 0x1)
-#define FW_CMD_READ            (1U << 22)
-#define FW_CMD_WRITE           (1U << 21)
-#define FW_CMD_EXEC            (1U << 20)
-#define FW_CMD_RAMASK(x)       ((x) << 20)
-#define FW_CMD_RETVAL(x)       ((x) << 8)
-#define FW_CMD_RETVAL_GET(x)   (((x) >> 8) & 0xff)
-#define FW_CMD_LEN16(x)         ((x) << 0)
-#define FW_LEN16(fw_struct)    FW_CMD_LEN16(sizeof(fw_struct) / 16)
+#define FW_CMD_OP_S             24
+#define FW_CMD_OP_M             0xff
+#define FW_CMD_OP_V(x)          ((x) << FW_CMD_OP_S)
+#define FW_CMD_OP_G(x)          (((x) >> FW_CMD_OP_S) & FW_CMD_OP_M)
+
+#define FW_CMD_REQUEST_S        23
+#define FW_CMD_REQUEST_V(x)     ((x) << FW_CMD_REQUEST_S)
+#define FW_CMD_REQUEST_F        FW_CMD_REQUEST_V(1U)
+
+#define FW_CMD_READ_S           22
+#define FW_CMD_READ_V(x)        ((x) << FW_CMD_READ_S)
+#define FW_CMD_READ_F           FW_CMD_READ_V(1U)
+
+#define FW_CMD_WRITE_S          21
+#define FW_CMD_WRITE_V(x)       ((x) << FW_CMD_WRITE_S)
+#define FW_CMD_WRITE_F          FW_CMD_WRITE_V(1U)
+
+#define FW_CMD_EXEC_S           20
+#define FW_CMD_EXEC_V(x)        ((x) << FW_CMD_EXEC_S)
+#define FW_CMD_EXEC_F           FW_CMD_EXEC_V(1U)
+
+#define FW_CMD_RAMASK_S         20
+#define FW_CMD_RAMASK_V(x)      ((x) << FW_CMD_RAMASK_S)
+
+#define FW_CMD_RETVAL_S         8
+#define FW_CMD_RETVAL_M         0xff
+#define FW_CMD_RETVAL_V(x)      ((x) << FW_CMD_RETVAL_S)
+#define FW_CMD_RETVAL_G(x)      (((x) >> FW_CMD_RETVAL_S) & FW_CMD_RETVAL_M)
+
+#define FW_CMD_LEN16_S          0
+#define FW_CMD_LEN16_V(x)       ((x) << FW_CMD_LEN16_S)
+
+#define FW_LEN16(fw_struct)    FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
 
 enum fw_ldst_addrspc {
        FW_LDST_ADDRSPC_FIRMWARE  = 0x0001,
index 85036e6b42c4cd4f7663ef2487948448d2d04be8..0e8d5b72c9cc589ab52448ca81bbb105d30f18b9 100644 (file)
@@ -132,7 +132,7 @@ enum {
         * we can specify for immediate data in the firmware Ethernet TX
         * Work Request.
         */
-       MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_MASK,
+       MAX_IMM_TX_PKT_LEN = FW_WR_IMMDLEN_M,
 
        /*
         * Max size of a WR sent through a control TX queue.
@@ -1149,7 +1149,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                goto out_free;
        }
 
-       wr_mid = FW_WR_LEN16(DIV_ROUND_UP(flits, 2));
+       wr_mid = FW_WR_LEN16_V(DIV_ROUND_UP(flits, 2));
        if (unlikely(credits < ETHTXQ_STOP_THRES)) {
                /*
                 * After we're done injecting the Work Request for this
@@ -1161,7 +1161,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                 * has opened up.
                 */
                txq_stop(txq);
-               wr_mid |= FW_WR_EQUEQ | FW_WR_EQUIQ;
+               wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
        }
 
        /*
@@ -1191,9 +1191,9 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
 
                wr->op_immdlen =
-                       cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
-                                   FW_WR_IMMDLEN(sizeof(*lso) +
-                                                 sizeof(*cpl)));
+                       cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) |
+                                   FW_WR_IMMDLEN_V(sizeof(*lso) +
+                                                   sizeof(*cpl)));
                /*
                 * Fill in the LSO CPL message.
                 */
@@ -1228,8 +1228,8 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 
                len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl);
                wr->op_immdlen =
-                       cpu_to_be32(FW_WR_OP(FW_ETH_TX_PKT_VM_WR) |
-                                   FW_WR_IMMDLEN(len));
+                       cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_PKT_VM_WR) |
+                                   FW_WR_IMMDLEN_V(len));
 
                /*
                 * Set up TX Packet CPL pointer, control word and perform
@@ -2084,10 +2084,10 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
         * into OS-independent common code ...
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_WRITE |
-                                   FW_CMD_EXEC);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_WRITE_F |
+                                   FW_CMD_EXEC_F);
        cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_ALLOC |
                                         FW_IQ_CMD_IQSTART(1) |
                                         FW_LEN16(cmd));
@@ -2246,10 +2246,10 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
         * into the common code ...
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_WRITE |
-                                   FW_CMD_EXEC);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_WRITE_F |
+                                   FW_CMD_EXEC_F);
        cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_ALLOC |
                                         FW_EQ_ETH_CMD_EQSTART |
                                         FW_LEN16(cmd));
index 95df61dcb4ce57021237a15013bfdc8e88c0fa5d..2cfa4396b0030c95a9a5ca3370e4ce279c7fe7ba 100644 (file)
@@ -67,7 +67,7 @@ enum chip_type {
 /*
  * The "len16" field of a Firmware Command Structure ...
  */
-#define FW_LEN16(fw_struct) FW_CMD_LEN16(sizeof(fw_struct) / 16)
+#define FW_LEN16(fw_struct) FW_CMD_LEN16_V(sizeof(fw_struct) / 16)
 
 /*
  * Per-VF statistics.
index e984fdc48ba2e326a738e6f5bfa14e1bfda73f02..570b895ae06f299c44465abf35b44cd87c60ade8 100644 (file)
@@ -204,20 +204,20 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
 
                        /* return value in low-order little-endian word */
                        v = t4_read_reg(adapter, mbox_data);
-                       if (FW_CMD_RETVAL_GET(v))
+                       if (FW_CMD_RETVAL_G(v))
                                dump_mbox(adapter, "FW Error", mbox_data);
 
                        if (rpl) {
                                /* request bit in high-order BE word */
                                WARN_ON((be32_to_cpu(*(const u32 *)cmd)
-                                        & FW_CMD_REQUEST) == 0);
+                                        & FW_CMD_REQUEST_F) == 0);
                                get_mbox_rpl(adapter, rpl, size, mbox_data);
                                WARN_ON((be32_to_cpu(*(u32 *)rpl)
-                                        & FW_CMD_REQUEST) != 0);
+                                        & FW_CMD_REQUEST_F) != 0);
                        }
                        t4_write_reg(adapter, mbox_ctl,
                                     MBOWNER(MBOX_OWNER_NONE));
-                       return -FW_CMD_RETVAL_GET(v);
+                       return -FW_CMD_RETVAL_G(v);
                }
        }
 
@@ -287,9 +287,9 @@ int t4vf_port_init(struct adapter *adapter, int pidx)
         * like MAC address, etc.
         */
        memset(&vi_cmd, 0, sizeof(vi_cmd));
-       vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
-                                      FW_CMD_REQUEST |
-                                      FW_CMD_READ);
+       vi_cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+                                      FW_CMD_REQUEST_F |
+                                      FW_CMD_READ_F);
        vi_cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(vi_cmd));
        vi_cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(pi->viid));
        v = t4vf_wr_mbox(adapter, &vi_cmd, sizeof(vi_cmd), &vi_rpl);
@@ -308,9 +308,9 @@ int t4vf_port_init(struct adapter *adapter, int pidx)
                return 0;
 
        memset(&port_cmd, 0, sizeof(port_cmd));
-       port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP(FW_PORT_CMD) |
-                                           FW_CMD_REQUEST |
-                                           FW_CMD_READ |
+       port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
+                                           FW_CMD_REQUEST_F |
+                                           FW_CMD_READ_F |
                                            FW_PORT_CMD_PORTID(pi->port_id));
        port_cmd.action_to_len16 =
                cpu_to_be32(FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
@@ -349,8 +349,8 @@ int t4vf_fw_reset(struct adapter *adapter)
        struct fw_reset_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) |
-                                     FW_CMD_WRITE);
+       cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RESET_CMD) |
+                                     FW_CMD_WRITE_F);
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
        return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
 }
@@ -377,12 +377,12 @@ static int t4vf_query_params(struct adapter *adapter, unsigned int nparams,
                return -EINVAL;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_READ);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_READ_F);
        len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
                                      param[nparams].mnem), 16);
-       cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+       cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
        for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++)
                p->mnem = htonl(*params++);
 
@@ -415,12 +415,12 @@ int t4vf_set_params(struct adapter *adapter, unsigned int nparams,
                return -EINVAL;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PARAMS_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_WRITE);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_WRITE_F);
        len16 = DIV_ROUND_UP(offsetof(struct fw_params_cmd,
                                      param[nparams]), 16);
-       cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+       cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
        for (i = 0, p = &cmd.param[0]; i < nparams; i++, p++) {
                p->mnem = cpu_to_be32(*params++);
                p->val = cpu_to_be32(*vals++);
@@ -545,9 +545,9 @@ int t4vf_get_rss_glb_config(struct adapter *adapter)
         * our RSS configuration.
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
-                                     FW_CMD_REQUEST |
-                                     FW_CMD_READ);
+       cmd.op_to_write = cpu_to_be32(FW_CMD_OP_V(FW_RSS_GLB_CONFIG_CMD) |
+                                     FW_CMD_REQUEST_F |
+                                     FW_CMD_READ_F);
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
        v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
        if (v)
@@ -621,9 +621,9 @@ int t4vf_get_vfres(struct adapter *adapter)
         * with error on command failure.
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_PFVF_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_READ);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_PFVF_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_READ_F);
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
        v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
        if (v)
@@ -669,9 +669,9 @@ int t4vf_read_rss_vi_config(struct adapter *adapter, unsigned int viid,
        int v;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_READ |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_READ_F |
                                     FW_RSS_VI_CONFIG_CMD_VIID(viid));
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
        v = t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), &rpl);
@@ -719,9 +719,9 @@ int t4vf_write_rss_vi_config(struct adapter *adapter, unsigned int viid,
        struct fw_rss_vi_config_cmd cmd, rpl;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_WRITE |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_VI_CONFIG_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
                                     FW_RSS_VI_CONFIG_CMD_VIID(viid));
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
        switch (adapter->params.rss.mode) {
@@ -777,9 +777,9 @@ int t4vf_config_rss_range(struct adapter *adapter, unsigned int viid,
         * Initialize firmware command template to write the RSS table.
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_WRITE |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_RSS_IND_TBL_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
                                     FW_RSS_IND_TBL_CMD_VIID(viid));
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
 
@@ -866,10 +866,10 @@ int t4vf_alloc_vi(struct adapter *adapter, int port_id)
         * VIID.
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_WRITE |
-                                   FW_CMD_EXEC);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_WRITE_F |
+                                   FW_CMD_EXEC_F);
        cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
                                         FW_VI_CMD_ALLOC);
        cmd.portid_pkd = FW_VI_CMD_PORTID(port_id);
@@ -896,9 +896,9 @@ int t4vf_free_vi(struct adapter *adapter, int viid)
         * Execute a VI command to free the Virtual Interface.
         */
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_VI_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_EXEC);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_VI_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_EXEC_F);
        cmd.alloc_to_len16 = cpu_to_be32(FW_LEN16(cmd) |
                                         FW_VI_CMD_FREE);
        cmd.type_viid = cpu_to_be16(FW_VI_CMD_VIID(viid));
@@ -920,9 +920,9 @@ int t4vf_enable_vi(struct adapter *adapter, unsigned int viid,
        struct fw_vi_enable_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_EXEC |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_EXEC_F |
                                     FW_VI_ENABLE_CMD_VIID(viid));
        cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_IEN(rx_en) |
                                       FW_VI_ENABLE_CMD_EEN(tx_en) |
@@ -944,9 +944,9 @@ int t4vf_identify_port(struct adapter *adapter, unsigned int viid,
        struct fw_vi_enable_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_ENABLE_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_EXEC |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_ENABLE_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_EXEC_F |
                                     FW_VI_ENABLE_CMD_VIID(viid));
        cmd.ien_to_len16 = cpu_to_be32(FW_VI_ENABLE_CMD_LED |
                                       FW_LEN16(cmd));
@@ -986,9 +986,9 @@ int t4vf_set_rxmode(struct adapter *adapter, unsigned int viid,
                vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_RXMODE_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_WRITE |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_RXMODE_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
                                     FW_VI_RXMODE_CMD_VIID(viid));
        cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
        cmd.mtu_to_vlanexen =
@@ -1046,14 +1046,14 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
                int i;
 
                memset(&cmd, 0, sizeof(cmd));
-               cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
-                                            FW_CMD_REQUEST |
-                                            FW_CMD_WRITE |
-                                            (free ? FW_CMD_EXEC : 0) |
+               cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+                                            FW_CMD_REQUEST_F |
+                                            FW_CMD_WRITE_F |
+                                            (free ? FW_CMD_EXEC_F : 0) |
                                             FW_VI_MAC_CMD_VIID(viid));
                cmd.freemacs_to_len16 =
                        cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
-                                   FW_CMD_LEN16(len16));
+                                   FW_CMD_LEN16_V(len16));
 
                for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
                        p->valid_to_idx = cpu_to_be16(
@@ -1135,11 +1135,11 @@ int t4vf_change_mac(struct adapter *adapter, unsigned int viid,
                idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_WRITE |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
                                     FW_VI_MAC_CMD_VIID(viid));
-       cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+       cmd.freemacs_to_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
        p->valid_to_idx = cpu_to_be16(FW_VI_MAC_CMD_VALID |
                                      FW_VI_MAC_CMD_IDX(idx));
        memcpy(p->macaddr, addr, sizeof(p->macaddr));
@@ -1172,13 +1172,13 @@ int t4vf_set_addr_hash(struct adapter *adapter, unsigned int viid,
                                             u.exact[0]), 16);
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_WRITE |
+       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_MAC_CMD) |
+                                    FW_CMD_REQUEST_F |
+                                    FW_CMD_WRITE_F |
                                     FW_VI_ENABLE_CMD_VIID(viid));
        cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_HASHVECEN |
                                            FW_VI_MAC_CMD_HASHUNIEN(ucast) |
-                                           FW_CMD_LEN16(len16));
+                                           FW_CMD_LEN16_V(len16));
        cmd.u.hash.hashvec = cpu_to_be64(vec);
        return t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), NULL, sleep_ok);
 }
@@ -1214,11 +1214,11 @@ int t4vf_get_port_stats(struct adapter *adapter, int pidx,
                int ret;
 
                memset(&cmd, 0, sizeof(cmd));
-               cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_STATS_CMD) |
+               cmd.op_to_viid = cpu_to_be32(FW_CMD_OP_V(FW_VI_STATS_CMD) |
                                             FW_VI_STATS_CMD_VIID(pi->viid) |
-                                            FW_CMD_REQUEST |
-                                            FW_CMD_READ);
-               cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16(len16));
+                                            FW_CMD_REQUEST_F |
+                                            FW_CMD_READ_F);
+               cmd.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(len16));
                cmd.u.ctl.nstats_ix =
                        cpu_to_be16(FW_VI_STATS_CMD_IX(ix) |
                                    FW_VI_STATS_CMD_NSTATS(nstats));
@@ -1273,9 +1273,9 @@ int t4vf_iq_free(struct adapter *adapter, unsigned int iqtype,
        struct fw_iq_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_IQ_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_EXEC);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_IQ_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_EXEC_F);
        cmd.alloc_to_len16 = cpu_to_be32(FW_IQ_CMD_FREE |
                                         FW_LEN16(cmd));
        cmd.type_to_iqandstindex =
@@ -1299,9 +1299,9 @@ int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
        struct fw_eq_eth_cmd cmd;
 
        memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP(FW_EQ_ETH_CMD) |
-                                   FW_CMD_REQUEST |
-                                   FW_CMD_EXEC);
+       cmd.op_to_vfn = cpu_to_be32(FW_CMD_OP_V(FW_EQ_ETH_CMD) |
+                                   FW_CMD_REQUEST_F |
+                                   FW_CMD_EXEC_F);
        cmd.alloc_to_len16 = cpu_to_be32(FW_EQ_ETH_CMD_FREE |
                                         FW_LEN16(cmd));
        cmd.eqid_pkd = cpu_to_be32(FW_EQ_ETH_CMD_EQID(eqid));
@@ -1318,7 +1318,7 @@ int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
 int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
 {
        const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl;
-       u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi));
+       u8 opcode = FW_CMD_OP_G(be32_to_cpu(cmd_hdr->hi));
 
        switch (opcode) {
        case FW_PORT_CMD: {
index 8ea4d5be7376fc0892930e6f701c78676f5bb0e0..6c643230a5ed657d48e8ab1624f222dc844580f1 100644 (file)
@@ -115,7 +115,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
        "tso_packets",
        "xmit_more",
        "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed",
-       "rx_csum_good", "rx_csum_none", "tx_chksum_offload",
+       "rx_csum_good", "rx_csum_none", "rx_csum_complete", "tx_chksum_offload",
 
        /* packet statistics */
        "broadcast", "rx_prio_0", "rx_prio_1", "rx_prio_2", "rx_prio_3",
index 0efbae90f1bafd556e9a963a3dd557272475c2ea..d1eb25dbff56160e895816bac7007c97448ff9fd 100644 (file)
@@ -1893,6 +1893,7 @@ static void mlx4_en_clear_stats(struct net_device *dev)
                priv->rx_ring[i]->packets = 0;
                priv->rx_ring[i]->csum_ok = 0;
                priv->rx_ring[i]->csum_none = 0;
+               priv->rx_ring[i]->csum_complete = 0;
        }
 }
 
@@ -2503,6 +2504,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        /* Query for default mac and max mtu */
        priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
 
+       if (mdev->dev->caps.rx_checksum_flags_port[priv->port] &
+           MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP)
+               priv->flags |= MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP;
+
        /* Set default MAC */
        dev->addr_len = ETH_ALEN;
        mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
index 134b12e17da5f09ff7fa3367fd0094634b23c070..6cb80072af6c16b33f832a06a67d7e379ecb2f1f 100644 (file)
@@ -155,11 +155,13 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
        stats->rx_bytes = 0;
        priv->port_stats.rx_chksum_good = 0;
        priv->port_stats.rx_chksum_none = 0;
+       priv->port_stats.rx_chksum_complete = 0;
        for (i = 0; i < priv->rx_ring_num; i++) {
                stats->rx_packets += priv->rx_ring[i]->packets;
                stats->rx_bytes += priv->rx_ring[i]->bytes;
                priv->port_stats.rx_chksum_good += priv->rx_ring[i]->csum_ok;
                priv->port_stats.rx_chksum_none += priv->rx_ring[i]->csum_none;
+               priv->port_stats.rx_chksum_complete += priv->rx_ring[i]->csum_complete;
        }
        stats->tx_packets = 0;
        stats->tx_bytes = 0;
index b173a0cf44e065f9bc43dec4581c483fa222de13..ccd95177ea7c5d294b4c19f3c756d9ba309217c1 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/irq.h>
 
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/ip6_checksum.h>
+#endif
+
 #include "mlx4_en.h"
 
 static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
@@ -643,6 +647,86 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv,
        }
 }
 
+/* When hardware doesn't strip the vlan, we need to calculate the checksum
+ * over it and add it to the hardware's checksum calculation
+ */
+static inline __wsum get_fixed_vlan_csum(__wsum hw_checksum,
+                                        struct vlan_hdr *vlanh)
+{
+       return csum_add(hw_checksum, *(__wsum *)vlanh);
+}
+
+/* Although the stack expects checksum which doesn't include the pseudo
+ * header, the HW adds it. To address that, we are subtracting the pseudo
+ * header checksum from the checksum value provided by the HW.
+ */
+static void get_fixed_ipv4_csum(__wsum hw_checksum, struct sk_buff *skb,
+                               struct iphdr *iph)
+{
+       __u16 length_for_csum = 0;
+       __wsum csum_pseudo_header = 0;
+
+       length_for_csum = (be16_to_cpu(iph->tot_len) - (iph->ihl << 2));
+       csum_pseudo_header = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+                                               length_for_csum, iph->protocol, 0);
+       skb->csum = csum_sub(hw_checksum, csum_pseudo_header);
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+/* In IPv6 packets, besides subtracting the pseudo header checksum,
+ * we also compute/add the IP header checksum which
+ * is not added by the HW.
+ */
+static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
+                              struct ipv6hdr *ipv6h)
+{
+       __wsum csum_pseudo_hdr = 0;
+
+       if (ipv6h->nexthdr == IPPROTO_FRAGMENT || ipv6h->nexthdr == IPPROTO_HOPOPTS)
+               return -1;
+       hw_checksum = csum_add(hw_checksum, (__force __wsum)(ipv6h->nexthdr << 8));
+
+       csum_pseudo_hdr = csum_partial(&ipv6h->saddr,
+                                      sizeof(ipv6h->saddr) + sizeof(ipv6h->daddr), 0);
+       csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ipv6h->payload_len);
+       csum_pseudo_hdr = csum_add(csum_pseudo_hdr, (__force __wsum)ntohs(ipv6h->nexthdr));
+
+       skb->csum = csum_sub(hw_checksum, csum_pseudo_hdr);
+       skb->csum = csum_add(skb->csum, csum_partial(ipv6h, sizeof(struct ipv6hdr), 0));
+       return 0;
+}
+#endif
+static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
+                     int hwtstamp_rx_filter)
+{
+       __wsum hw_checksum = 0;
+
+       void *hdr = (u8 *)va + sizeof(struct ethhdr);
+
+       hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
+
+       if (((struct ethhdr *)va)->h_proto == htons(ETH_P_8021Q) &&
+           hwtstamp_rx_filter != HWTSTAMP_FILTER_NONE) {
+               /* next protocol non IPv4 or IPv6 */
+               if (((struct vlan_hdr *)hdr)->h_vlan_encapsulated_proto
+                   != htons(ETH_P_IP) &&
+                   ((struct vlan_hdr *)hdr)->h_vlan_encapsulated_proto
+                   != htons(ETH_P_IPV6))
+                       return -1;
+               hw_checksum = get_fixed_vlan_csum(hw_checksum, hdr);
+               hdr += sizeof(struct vlan_hdr);
+       }
+
+       if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4))
+               get_fixed_ipv4_csum(hw_checksum, skb, hdr);
+#if IS_ENABLED(CONFIG_IPV6)
+       else if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV6))
+               if (get_fixed_ipv6_csum(hw_checksum, skb, hdr))
+                       return -1;
+#endif
+       return 0;
+}
+
 int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
@@ -744,73 +828,95 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                        (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_L2_TUNNEL));
 
                if (likely(dev->features & NETIF_F_RXCSUM)) {
-                       if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
-                           (cqe->checksum == cpu_to_be16(0xffff))) {
-                               ring->csum_ok++;
-                               /* This packet is eligible for GRO if it is:
-                                * - DIX Ethernet (type interpretation)
-                                * - TCP/IP (v4)
-                                * - without IP options
-                                * - not an IP fragment
-                                * - no LLS polling in progress
-                                */
-                               if (!mlx4_en_cq_busy_polling(cq) &&
-                                   (dev->features & NETIF_F_GRO)) {
-                                       struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
-                                       if (!gro_skb)
-                                               goto next;
-
-                                       nr = mlx4_en_complete_rx_desc(priv,
-                                               rx_desc, frags, gro_skb,
-                                               length);
-                                       if (!nr)
-                                               goto next;
-
-                                       skb_shinfo(gro_skb)->nr_frags = nr;
-                                       gro_skb->len = length;
-                                       gro_skb->data_len = length;
-                                       gro_skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       if (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
+                                                     MLX4_CQE_STATUS_UDP)) {
+                               if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
+                                   cqe->checksum == cpu_to_be16(0xffff)) {
+                                       ip_summed = CHECKSUM_UNNECESSARY;
+                                       ring->csum_ok++;
+                               } else {
+                                       ip_summed = CHECKSUM_NONE;
+                                       ring->csum_none++;
+                               }
+                       } else {
+                               if (priv->flags & MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP &&
+                                   (cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPV4 |
+                                                              MLX4_CQE_STATUS_IPV6))) {
+                                       ip_summed = CHECKSUM_COMPLETE;
+                                       ring->csum_complete++;
+                               } else {
+                                       ip_summed = CHECKSUM_NONE;
+                                       ring->csum_none++;
+                               }
+                       }
+               } else {
+                       ip_summed = CHECKSUM_NONE;
+                       ring->csum_none++;
+               }
 
-                                       if (l2_tunnel)
-                                               gro_skb->csum_level = 1;
-                                       if ((cqe->vlan_my_qpn &
-                                           cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
-                                           (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
-                                               u16 vid = be16_to_cpu(cqe->sl_vid);
+               /* This packet is eligible for GRO if it is:
+                * - DIX Ethernet (type interpretation)
+                * - TCP/IP (v4)
+                * - without IP options
+                * - not an IP fragment
+                * - no LLS polling in progress
+                */
+               if (!mlx4_en_cq_busy_polling(cq) &&
+                   (dev->features & NETIF_F_GRO)) {
+                       struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
+                       if (!gro_skb)
+                               goto next;
+
+                       nr = mlx4_en_complete_rx_desc(priv,
+                               rx_desc, frags, gro_skb,
+                               length);
+                       if (!nr)
+                               goto next;
+
+                       if (ip_summed == CHECKSUM_COMPLETE) {
+                               void *va = skb_frag_address(skb_shinfo(gro_skb)->frags);
+                               if (check_csum(cqe, gro_skb, va, ring->hwtstamp_rx_filter)) {
+                                       ip_summed = CHECKSUM_NONE;
+                                       ring->csum_none++;
+                                       ring->csum_complete--;
+                               }
+                       }
 
-                                               __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid);
-                                       }
+                       skb_shinfo(gro_skb)->nr_frags = nr;
+                       gro_skb->len = length;
+                       gro_skb->data_len = length;
+                       gro_skb->ip_summed = ip_summed;
 
-                                       if (dev->features & NETIF_F_RXHASH)
-                                               skb_set_hash(gro_skb,
-                                                            be32_to_cpu(cqe->immed_rss_invalid),
-                                                            PKT_HASH_TYPE_L3);
+                       if (l2_tunnel && ip_summed == CHECKSUM_UNNECESSARY)
+                               gro_skb->encapsulation = 1;
+                       if ((cqe->vlan_my_qpn &
+                           cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) &&
+                           (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
+                               u16 vid = be16_to_cpu(cqe->sl_vid);
 
-                                       skb_record_rx_queue(gro_skb, cq->ring);
-                                       skb_mark_napi_id(gro_skb, &cq->napi);
+                               __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid);
+                       }
 
-                                       if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
-                                               timestamp = mlx4_en_get_cqe_ts(cqe);
-                                               mlx4_en_fill_hwtstamps(mdev,
-                                                                      skb_hwtstamps(gro_skb),
-                                                                      timestamp);
-                                       }
+                       if (dev->features & NETIF_F_RXHASH)
+                               skb_set_hash(gro_skb,
+                                            be32_to_cpu(cqe->immed_rss_invalid),
+                                            PKT_HASH_TYPE_L3);
 
-                                       napi_gro_frags(&cq->napi);
-                                       goto next;
-                               }
+                       skb_record_rx_queue(gro_skb, cq->ring);
+                       skb_mark_napi_id(gro_skb, &cq->napi);
 
-                               /* GRO not possible, complete processing here */
-                               ip_summed = CHECKSUM_UNNECESSARY;
-                       } else {
-                               ip_summed = CHECKSUM_NONE;
-                               ring->csum_none++;
+                       if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) {
+                               timestamp = mlx4_en_get_cqe_ts(cqe);
+                               mlx4_en_fill_hwtstamps(mdev,
+                                                      skb_hwtstamps(gro_skb),
+                                                      timestamp);
                        }
-               } else {
-                       ip_summed = CHECKSUM_NONE;
-                       ring->csum_none++;
+
+                       napi_gro_frags(&cq->napi);
+                       goto next;
                }
 
+               /* GRO not possible, complete processing here */
                skb = mlx4_en_rx_skb(priv, rx_desc, frags, length);
                if (!skb) {
                        priv->stats.rx_dropped++;
@@ -822,6 +928,14 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                        goto next;
                }
 
+               if (ip_summed == CHECKSUM_COMPLETE) {
+                       if (check_csum(cqe, skb, skb->data, ring->hwtstamp_rx_filter)) {
+                               ip_summed = CHECKSUM_NONE;
+                               ring->csum_complete--;
+                               ring->csum_none++;
+                       }
+               }
+
                skb->ip_summed = ip_summed;
                skb->protocol = eth_type_trans(skb, dev);
                skb_record_rx_queue(skb, cq->ring);
@@ -910,20 +1024,18 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget)
                cpu_curr = smp_processor_id();
                aff = irq_desc_get_irq_data(cq->irq_desc)->affinity;
 
-               if (unlikely(!cpumask_test_cpu(cpu_curr, aff))) {
-                       /* Current cpu is not according to smp_irq_affinity -
-                        * probably affinity changed. need to stop this NAPI
-                        * poll, and restart it on the right CPU
-                        */
-                       napi_complete(napi);
-                       mlx4_en_arm_cq(priv, cq);
-                       return 0;
-               }
-       } else {
-               /* Done for now */
-               napi_complete(napi);
-               mlx4_en_arm_cq(priv, cq);
+               if (likely(cpumask_test_cpu(cpu_curr, aff)))
+                       return budget;
+
+               /* Current cpu is not according to smp_irq_affinity -
+                * probably affinity changed. need to stop this NAPI
+                * poll, and restart it on the right CPU
+                */
+               done = 0;
        }
+       /* Done for now */
+       napi_complete_done(napi, done);
+       mlx4_en_arm_cq(priv, cq);
        return done;
 }
 
index 9f821964a1b9e01c94c3f068f83b3c3d2a9c265a..2f6ba420ac030332fef8abca98c2782f80e575c6 100644 (file)
@@ -1629,6 +1629,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
        struct mlx4_init_hca_param init_hca;
        u64 icm_size;
        int err;
+       struct mlx4_config_dev_params params;
 
        if (!mlx4_is_slave(dev)) {
                err = mlx4_QUERY_FW(dev);
@@ -1762,6 +1763,14 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
                goto unmap_bf;
        }
 
+       /* Query CONFIG_DEV parameters */
+       err = mlx4_config_dev_retrieval(dev, &params);
+       if (err && err != -ENOTSUPP) {
+               mlx4_err(dev, "Failed to query CONFIG_DEV parameters\n");
+       } else if (!err) {
+               dev->caps.rx_checksum_flags_port[1] = params.rx_csum_flags_port_1;
+               dev->caps.rx_checksum_flags_port[2] = params.rx_csum_flags_port_2;
+       }
        priv->eq_table.inta_pin = adapter.inta_pin;
        memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
 
index ef83d127f406aa06ded84d7394e577ca07b3fe8d..de456749ffae56eafa6c5b5e3464868dc75d4ed0 100644 (file)
@@ -326,6 +326,7 @@ struct mlx4_en_rx_ring {
 #endif
        unsigned long csum_ok;
        unsigned long csum_none;
+       unsigned long csum_complete;
        int hwtstamp_rx_filter;
        cpumask_var_t affinity_mask;
 };
@@ -449,6 +450,7 @@ struct mlx4_en_port_stats {
        unsigned long rx_alloc_failed;
        unsigned long rx_chksum_good;
        unsigned long rx_chksum_none;
+       unsigned long rx_chksum_complete;
        unsigned long tx_chksum_offload;
 #define NUM_PORT_STATS         9
 };
@@ -507,7 +509,8 @@ enum {
        MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
        /* whether we need to drop packets that hardware loopback-ed */
        MLX4_EN_FLAG_RX_FILTER_NEEDED   = (1 << 3),
-       MLX4_EN_FLAG_FORCE_PROMISC      = (1 << 4)
+       MLX4_EN_FLAG_FORCE_PROMISC      = (1 << 4),
+       MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP        = (1 << 5),
 };
 
 #define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
index 007b38cce69a0b3bde4472ab5eef75989cf0dd6c..e157541b842be3bd80a1c229188c68d2b15ecd65 100644 (file)
@@ -183,7 +183,10 @@ static int debug = -1;
 #define NUM_TX_DESC    4
 
 /* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE     1536
+#define MAX_ETH_FRAME_SIZE     1792
+
+/* max supported payload size */
+#define MAX_ETH_DATA_SIZE      (MAX_ETH_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN)
 
 /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
 #define TX_BUF_SIZE    MAX_ETH_FRAME_SIZE
@@ -920,11 +923,19 @@ static int rtl8139_set_features(struct net_device *dev, netdev_features_t featur
        return 0;
 }
 
+static int rtl8139_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if (new_mtu < 68 || new_mtu > MAX_ETH_DATA_SIZE)
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 static const struct net_device_ops rtl8139_netdev_ops = {
        .ndo_open               = rtl8139_open,
        .ndo_stop               = rtl8139_close,
        .ndo_get_stats64        = rtl8139_get_stats64,
-       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_change_mtu         = rtl8139_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = rtl8139_set_mac_address,
        .ndo_start_xmit         = rtl8139_start_xmit,
index 5c5fb59adf765475e5cbfa82fa42c6145c0ebfc4..55d66c9a6627be1a6ddc712c7bc81d38653ef887 100644 (file)
@@ -559,18 +559,20 @@ static int vnet_ack(struct vnet_port *port, void *msgbuf)
                return 0;
 
        end = pkt->end_idx;
-       if (unlikely(!idx_is_pending(dr, end)))
-               return 0;
-
        vp = port->vp;
        dev = vp->dev;
+       netif_tx_lock(dev);
+       if (unlikely(!idx_is_pending(dr, end))) {
+               netif_tx_unlock(dev);
+               return 0;
+       }
+
        /* sync for race conditions with vnet_start_xmit() and tell xmit it
         * is time to send a trigger.
         */
-       netif_tx_lock(dev);
        dr->cons = next_idx(end, dr);
        desc = vio_dring_entry(dr, dr->cons);
-       if (desc->hdr.state == VIO_DESC_READY && port->start_cons) {
+       if (desc->hdr.state == VIO_DESC_READY && !port->start_cons) {
                /* vnet_start_xmit() just populated this dring but missed
                 * sending the "start" LDC message to the consumer.
                 * Send a "start" trigger on its behalf.
@@ -979,8 +981,10 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        rcu_read_lock();
        port = __tx_port_find(vp, skb);
-       if (unlikely(!port))
+       if (unlikely(!port)) {
+               rcu_read_unlock();
                goto out_dropped;
+       }
 
        if (skb->len > port->rmtu) {
                unsigned long localmtu = port->rmtu - ETH_HLEN;
index 391a916622a94d0354968ef4c1627c918fcf234d..1a3c3e57aa0b67750eccb0d2fc62eefb4eef0050 100644 (file)
@@ -10,16 +10,6 @@ menuconfig IEEE802154_DRIVERS
          If you say N, all options in this submenu will be skipped and
          disabled.
 
-config IEEE802154_FAKEHARD
-       tristate "Fake LR-WPAN driver with several interconnected devices"
-       depends on  IEEE802154_DRIVERS
-       ---help---
-         Say Y here to enable the fake driver that serves as an example
-         of HardMAC device driver.
-
-         This driver can also be built as a module. To do so say M here.
-         The module will be called 'fakehard'.
-
 config IEEE802154_FAKELB
        depends on IEEE802154_DRIVERS && MAC802154
        tristate "IEEE 802.15.4 loopback driver"
index 655cb95e6e247b42764151ed6a5768bd5f58d9b8..d77fa4d77e27d8e19e43f29f2161633c6754dd84 100644 (file)
@@ -1,4 +1,3 @@
-obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o
 obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o
 obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
 obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
index c9d2a752abd7b176e2f4889d3fc9a9cf4d8fd322..9ad2d432ef4301e170104f0cefabd8e97781e637 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
 #include <linux/regmap.h>
 #include <linux/skbuff.h>
 #include <linux/of_gpio.h>
+#include <linux/ieee802154.h>
 
-#include <net/ieee802154.h>
 #include <net/mac802154.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 
 struct at86rf230_local;
 /* at86rf2xx chip depend data.
@@ -58,7 +54,7 @@ struct at86rf2xx_chip_data {
        u16 t_tx_timeout;
        int rssi_base_val;
 
-       int (*set_channel)(struct at86rf230_local *, int, int);
+       int (*set_channel)(struct at86rf230_local *, u8, u8);
        int (*get_desense_steps)(struct at86rf230_local *, s32);
 };
 
@@ -74,12 +70,14 @@ struct at86rf230_state_change {
        void (*complete)(void *context);
        u8 from_state;
        u8 to_state;
+
+       bool irq_enable;
 };
 
 struct at86rf230_local {
        struct spi_device *spi;
 
-       struct ieee802154_dev *dev;
+       struct ieee802154_hw *hw;
        struct at86rf2xx_chip_data *data;
        struct regmap *regmap;
 
@@ -89,10 +87,10 @@ struct at86rf230_local {
        struct at86rf230_state_change irq;
 
        bool tx_aret;
+       s8 max_frame_retries;
        bool is_tx;
        /* spinlock for is_tx protection */
        spinlock_t lock;
-       struct completion tx_complete;
        struct sk_buff *tx_skb;
        struct at86rf230_state_change tx;
 };
@@ -291,10 +289,11 @@ struct at86rf230_local {
 
 #define AT86RF2XX_NUMREGS 0x3F
 
-static int
+static void
 at86rf230_async_state_change(struct at86rf230_local *lp,
                             struct at86rf230_state_change *ctx,
-                            const u8 state, void (*complete)(void *context));
+                            const u8 state, void (*complete)(void *context),
+                            const bool irq_enable);
 
 static inline int
 __at86rf230_write(struct at86rf230_local *lp,
@@ -451,7 +450,8 @@ at86rf230_async_error_recover(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
 
-       at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL);
+       at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false);
+       ieee802154_wake_queue(lp->hw);
 }
 
 static void
@@ -461,21 +461,31 @@ at86rf230_async_error(struct at86rf230_local *lp,
        dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
 
        at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
-                                    at86rf230_async_error_recover);
+                                    at86rf230_async_error_recover, false);
 }
 
 /* Generic function to get some register value in async mode */
-static int
+static void
 at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg,
                         struct at86rf230_state_change *ctx,
-                        void (*complete)(void *context))
+                        void (*complete)(void *context),
+                        const bool irq_enable)
 {
+       int rc;
+
        u8 *tx_buf = ctx->buf;
 
        tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
        ctx->trx.len = 2;
        ctx->msg.complete = complete;
-       return spi_async(lp->spi, &ctx->msg);
+       ctx->irq_enable = irq_enable;
+       rc = spi_async(lp->spi, &ctx->msg);
+       if (rc) {
+               if (irq_enable)
+                       enable_irq(lp->spi->irq);
+
+               at86rf230_async_error(lp, ctx, rc);
+       }
 }
 
 static void
@@ -512,7 +522,8 @@ at86rf230_async_state_assert(void *context)
                        if (ctx->to_state == STATE_TX_ON) {
                                at86rf230_async_state_change(lp, ctx,
                                                             STATE_FORCE_TX_ON,
-                                                            ctx->complete);
+                                                            ctx->complete,
+                                                            ctx->irq_enable);
                                return;
                        }
                }
@@ -535,7 +546,6 @@ at86rf230_async_state_delay(void *context)
        struct at86rf230_local *lp = ctx->lp;
        struct at86rf2xx_chip_data *c = lp->data;
        bool force = false;
-       int rc;
 
        /* The force state changes are will show as normal states in the
         * state status subregister. We change the to_state to the
@@ -604,10 +614,9 @@ at86rf230_async_state_delay(void *context)
        udelay(1);
 
 change:
-       rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-                                     at86rf230_async_state_assert);
-       if (rc)
-               dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+       at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+                                at86rf230_async_state_assert,
+                                ctx->irq_enable);
 }
 
 static void
@@ -622,10 +631,9 @@ at86rf230_async_state_change_start(void *context)
        /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
        if (trx_state == STATE_TRANSITION_IN_PROGRESS) {
                udelay(1);
-               rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-                                             at86rf230_async_state_change_start);
-               if (rc)
-                       dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+               at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+                                        at86rf230_async_state_change_start,
+                                        ctx->irq_enable);
                return;
        }
 
@@ -647,20 +655,27 @@ at86rf230_async_state_change_start(void *context)
        ctx->trx.len = 2;
        ctx->msg.complete = at86rf230_async_state_delay;
        rc = spi_async(lp->spi, &ctx->msg);
-       if (rc)
-               dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+       if (rc) {
+               if (ctx->irq_enable)
+                       enable_irq(lp->spi->irq);
+
+               at86rf230_async_error(lp, &lp->state, rc);
+       }
 }
 
-static int
+static void
 at86rf230_async_state_change(struct at86rf230_local *lp,
                             struct at86rf230_state_change *ctx,
-                            const u8 state, void (*complete)(void *context))
+                            const u8 state, void (*complete)(void *context),
+                            const bool irq_enable)
 {
        /* Initialization for the state change context */
        ctx->to_state = state;
        ctx->complete = complete;
-       return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-                                       at86rf230_async_state_change_start);
+       ctx->irq_enable = irq_enable;
+       at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+                                at86rf230_async_state_change_start,
+                                irq_enable);
 }
 
 static void
@@ -681,17 +696,16 @@ at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state)
 {
        int rc;
 
-       rc = at86rf230_async_state_change(lp, &lp->state, state,
-                                         at86rf230_sync_state_change_complete);
-       if (rc) {
-               at86rf230_async_error(lp, &lp->state, rc);
-               return rc;
-       }
+       at86rf230_async_state_change(lp, &lp->state, state,
+                                    at86rf230_sync_state_change_complete,
+                                    false);
 
        rc = wait_for_completion_timeout(&lp->state_complete,
                                         msecs_to_jiffies(100));
-       if (!rc)
+       if (!rc) {
+               at86rf230_async_error(lp, &lp->state, -ETIMEDOUT);
                return -ETIMEDOUT;
+       }
 
        return 0;
 }
@@ -701,8 +715,23 @@ at86rf230_tx_complete(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
+       struct sk_buff *skb = lp->tx_skb;
+
+       enable_irq(lp->spi->irq);
+
+       if (lp->max_frame_retries <= 0) {
+               /* Interfame spacing time, which is phy depend.
+                * TODO
+                * Move this handling in MAC 802.15.4 layer.
+                * This is currently a workaround to avoid fragmenation issues.
+                */
+               if (skb->len > 18)
+                       udelay(lp->data->t_lifs);
+               else
+                       udelay(lp->data->t_sifs);
+       }
 
-       complete(&lp->tx_complete);
+       ieee802154_xmit_complete(lp->hw, skb);
 }
 
 static void
@@ -710,12 +739,9 @@ at86rf230_tx_on(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
-                                         at86rf230_tx_complete);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
+                                    at86rf230_tx_complete, true);
 }
 
 static void
@@ -723,12 +749,9 @@ at86rf230_tx_trac_error(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
-                                         at86rf230_tx_on);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
+                                    at86rf230_tx_on, true);
 }
 
 static void
@@ -738,17 +761,14 @@ at86rf230_tx_trac_check(void *context)
        struct at86rf230_local *lp = ctx->lp;
        const u8 *buf = ctx->buf;
        const u8 trac = (buf[1] & 0xe0) >> 5;
-       int rc;
 
        /* If trac status is different than zero we need to do a state change
         * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver
         * state to TX_ON.
         */
        if (trac) {
-               rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
-                                                 at86rf230_tx_trac_error);
-               if (rc)
-                       at86rf230_async_error(lp, ctx, rc);
+               at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
+                                            at86rf230_tx_trac_error, true);
                return;
        }
 
@@ -761,51 +781,29 @@ at86rf230_tx_trac_status(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
-                                     at86rf230_tx_trac_check);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
+                                at86rf230_tx_trac_check, true);
 }
 
 static void
 at86rf230_rx(struct at86rf230_local *lp,
-            const u8 *data, u8 len)
+            const u8 *data, const u8 len, const u8 lqi)
 {
-       u8 lqi;
        struct sk_buff *skb;
        u8 rx_local_buf[AT86RF2XX_MAX_BUF];
 
-       if (len < 2)
-               return;
-
-       /* read full frame buffer and invalid lqi value to lowest
-        * indicator if frame was is in a corrupted state.
-        */
-       if (len > IEEE802154_MTU) {
-               lqi = 0;
-               len = IEEE802154_MTU;
-               dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
-       } else {
-               lqi = data[len];
-       }
-
        memcpy(rx_local_buf, data, len);
        enable_irq(lp->spi->irq);
 
-       skb = alloc_skb(IEEE802154_MTU, GFP_ATOMIC);
+       skb = dev_alloc_skb(IEEE802154_MTU);
        if (!skb) {
                dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n");
                return;
        }
 
        memcpy(skb_put(skb, len), rx_local_buf, len);
-
-       /* We do not put CRC into the frame */
-       skb_trim(skb, len - 2);
-
-       ieee802154_rx_irqsafe(lp->dev, skb, lqi);
+       ieee802154_rx_irqsafe(lp->hw, skb, lqi);
 }
 
 static void
@@ -814,20 +812,31 @@ at86rf230_rx_read_frame_complete(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
        const u8 *buf = lp->irq.buf;
-       const u8 len = buf[1];
+       u8 len = buf[1];
 
-       at86rf230_rx(lp, buf + 2, len);
+       if (!ieee802154_is_valid_psdu_len(len)) {
+               dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
+               len = IEEE802154_MTU;
+       }
+
+       at86rf230_rx(lp, buf + 2, len, buf[2 + len]);
 }
 
-static int
+static void
 at86rf230_rx_read_frame(struct at86rf230_local *lp)
 {
+       int rc;
+
        u8 *buf = lp->irq.buf;
 
        buf[0] = CMD_FB;
        lp->irq.trx.len = AT86RF2XX_MAX_BUF;
        lp->irq.msg.complete = at86rf230_rx_read_frame_complete;
-       return spi_async(lp->spi, &lp->irq.msg);
+       rc = spi_async(lp->spi, &lp->irq.msg);
+       if (rc) {
+               enable_irq(lp->spi->irq);
+               at86rf230_async_error(lp, &lp->irq, rc);
+       }
 }
 
 static void
@@ -835,7 +844,6 @@ at86rf230_rx_trac_check(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
        /* Possible check on trac status here. This could be useful to make
         * some stats why receive is failed. Not used at the moment, but it's
@@ -843,34 +851,31 @@ at86rf230_rx_trac_check(void *context)
         * The programming guide say do it so.
         */
 
-       rc = at86rf230_rx_read_frame(lp);
-       if (rc) {
-               enable_irq(lp->spi->irq);
-               at86rf230_async_error(lp, ctx, rc);
-       }
+       at86rf230_rx_read_frame(lp);
 }
 
-static int
+static void
 at86rf230_irq_trx_end(struct at86rf230_local *lp)
 {
        spin_lock(&lp->lock);
        if (lp->is_tx) {
                lp->is_tx = 0;
                spin_unlock(&lp->lock);
-               enable_irq(lp->spi->irq);
 
                if (lp->tx_aret)
-                       return at86rf230_async_state_change(lp, &lp->irq,
-                                                           STATE_FORCE_TX_ON,
-                                                           at86rf230_tx_trac_status);
+                       at86rf230_async_state_change(lp, &lp->irq,
+                                                    STATE_FORCE_TX_ON,
+                                                    at86rf230_tx_trac_status,
+                                                    true);
                else
-                       return at86rf230_async_state_change(lp, &lp->irq,
-                                                           STATE_RX_AACK_ON,
-                                                           at86rf230_tx_complete);
+                       at86rf230_async_state_change(lp, &lp->irq,
+                                                    STATE_RX_AACK_ON,
+                                                    at86rf230_tx_complete,
+                                                    true);
        } else {
                spin_unlock(&lp->lock);
-               return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
-                                               at86rf230_rx_trac_check);
+               at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
+                                        at86rf230_rx_trac_check, true);
        }
 }
 
@@ -881,12 +886,9 @@ at86rf230_irq_status(void *context)
        struct at86rf230_local *lp = ctx->lp;
        const u8 *buf = lp->irq.buf;
        const u8 irq = buf[1];
-       int rc;
 
        if (irq & IRQ_TRX_END) {
-               rc = at86rf230_irq_trx_end(lp);
-               if (rc)
-                       at86rf230_async_error(lp, ctx, rc);
+               at86rf230_irq_trx_end(lp);
        } else {
                enable_irq(lp->spi->irq);
                dev_err(&lp->spi->dev, "not supported irq %02x received\n",
@@ -901,13 +903,14 @@ static irqreturn_t at86rf230_isr(int irq, void *data)
        u8 *buf = ctx->buf;
        int rc;
 
-       disable_irq_nosync(lp->spi->irq);
+       disable_irq_nosync(irq);
 
        buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG;
        ctx->trx.len = 2;
        ctx->msg.complete = at86rf230_irq_status;
        rc = spi_async(lp->spi, &ctx->msg);
        if (rc) {
+               enable_irq(irq);
                at86rf230_async_error(lp, ctx, rc);
                return IRQ_NONE;
        }
@@ -960,22 +963,18 @@ at86rf230_xmit_tx_on(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
-                                         at86rf230_write_frame);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
+                                    at86rf230_write_frame, false);
 }
 
 static int
-at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
        struct at86rf230_state_change *ctx = &lp->tx;
 
        void (*tx_complete)(void *context) = at86rf230_write_frame;
-       int rc;
 
        lp->tx_skb = skb;
 
@@ -986,61 +985,39 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        if (lp->tx_aret)
                tx_complete = at86rf230_xmit_tx_on;
 
-       rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
-                                         tx_complete);
-       if (rc) {
-               at86rf230_async_error(lp, ctx, rc);
-               return rc;
-       }
-       rc = wait_for_completion_interruptible_timeout(&lp->tx_complete,
-                                                      msecs_to_jiffies(lp->data->t_tx_timeout));
-       if (!rc) {
-               at86rf230_async_error(lp, ctx, rc);
-               return -ETIMEDOUT;
-       }
-
-       /* Interfame spacing time, which is phy depend.
-        * TODO
-        * Move this handling in MAC 802.15.4 layer.
-        * This is currently a workaround to avoid fragmenation issues.
-        */
-       if (skb->len > 18)
-               usleep_range(lp->data->t_lifs, lp->data->t_lifs + 10);
-       else
-               usleep_range(lp->data->t_sifs, lp->data->t_sifs + 10);
+       at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false);
 
        return 0;
 }
 
 static int
-at86rf230_ed(struct ieee802154_dev *dev, u8 *level)
+at86rf230_ed(struct ieee802154_hw *hw, u8 *level)
 {
-       might_sleep();
        BUG_ON(!level);
        *level = 0xbe;
        return 0;
 }
 
 static int
-at86rf230_start(struct ieee802154_dev *dev)
+at86rf230_start(struct ieee802154_hw *hw)
 {
-       return at86rf230_sync_state_change(dev->priv, STATE_RX_AACK_ON);
+       return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON);
 }
 
 static void
-at86rf230_stop(struct ieee802154_dev *dev)
+at86rf230_stop(struct ieee802154_hw *hw)
 {
-       at86rf230_sync_state_change(dev->priv, STATE_FORCE_TRX_OFF);
+       at86rf230_sync_state_change(hw->priv, STATE_FORCE_TRX_OFF);
 }
 
 static int
-at86rf23x_set_channel(struct at86rf230_local *lp, int page, int channel)
+at86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
 {
        return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
 }
 
 static int
-at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
+at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
 {
        int rc;
 
@@ -1065,15 +1042,13 @@ at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
 }
 
 static int
-at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
+at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
        int rc;
 
-       might_sleep();
-
        if (page < 0 || page > 31 ||
-           !(lp->dev->phy->channels_supported[page] & BIT(channel))) {
+           !(lp->hw->phy->channels_supported[page] & BIT(channel))) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -1085,20 +1060,20 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
        /* Wait for PLL */
        usleep_range(lp->data->t_channel_switch,
                     lp->data->t_channel_switch + 10);
-       dev->phy->current_channel = channel;
-       dev->phy->current_page = page;
+       hw->phy->current_channel = channel;
+       hw->phy->current_page = page;
 
        return 0;
 }
 
 static int
-at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
+at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
                           struct ieee802154_hw_addr_filt *filt,
                           unsigned long changed)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
 
-       if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
                u16 addr = le16_to_cpu(filt->short_addr);
 
                dev_vdbg(&lp->spi->dev,
@@ -1107,7 +1082,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
                __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
        }
 
-       if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANID_CHANGED) {
                u16 pan = le16_to_cpu(filt->pan_id);
 
                dev_vdbg(&lp->spi->dev,
@@ -1116,7 +1091,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
                __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
        }
 
-       if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
                u8 i, addr[8];
 
                memcpy(addr, &filt->ieee_addr, 8);
@@ -1126,7 +1101,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
                        __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
        }
 
-       if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANC_CHANGED) {
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for panc change\n");
                if (filt->pan_coord)
@@ -1139,9 +1114,9 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
 }
 
 static int
-at86rf230_set_txpower(struct ieee802154_dev *dev, int db)
+at86rf230_set_txpower(struct ieee802154_hw *hw, int db)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
 
        /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
         * bits decrease power in 1dB steps. 0x60 represents extra PA gain of
@@ -1158,17 +1133,17 @@ at86rf230_set_txpower(struct ieee802154_dev *dev, int db)
 }
 
 static int
-at86rf230_set_lbt(struct ieee802154_dev *dev, bool on)
+at86rf230_set_lbt(struct ieee802154_hw *hw, bool on)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
 
        return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
 }
 
 static int
-at86rf230_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
+at86rf230_set_cca_mode(struct ieee802154_hw *hw, u8 mode)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
 
        return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
 }
@@ -1186,9 +1161,9 @@ at86rf23x_get_desens_steps(struct at86rf230_local *lp, s32 level)
 }
 
 static int
-at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
+at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 level)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
 
        if (level < lp->data->rssi_base_val || level > 30)
                return -EINVAL;
@@ -1198,10 +1173,10 @@ at86rf230_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
 }
 
 static int
-at86rf230_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
+at86rf230_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be,
                          u8 retries)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
        int rc;
 
        if (min_be > max_be || max_be > 8 || retries > 5)
@@ -1219,15 +1194,16 @@ at86rf230_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
 }
 
 static int
-at86rf230_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
+at86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
 {
-       struct at86rf230_local *lp = dev->priv;
+       struct at86rf230_local *lp = hw->priv;
        int rc = 0;
 
        if (retries < -1 || retries > 15)
                return -EINVAL;
 
        lp->tx_aret = retries >= 0;
+       lp->max_frame_retries = retries;
 
        if (retries >= 0)
                rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
@@ -1235,9 +1211,36 @@ at86rf230_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
        return rc;
 }
 
-static struct ieee802154_ops at86rf230_ops = {
+static int
+at86rf230_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
+{
+       struct at86rf230_local *lp = hw->priv;
+       int rc;
+
+       if (on) {
+               rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 1);
+               if (rc < 0)
+                       return rc;
+
+               rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 1);
+               if (rc < 0)
+                       return rc;
+       } else {
+               rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 0);
+               if (rc < 0)
+                       return rc;
+
+               rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 0);
+               if (rc < 0)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static const struct ieee802154_ops at86rf230_ops = {
        .owner = THIS_MODULE,
-       .xmit = at86rf230_xmit,
+       .xmit_async = at86rf230_xmit,
        .ed = at86rf230_ed,
        .set_channel = at86rf230_channel,
        .start = at86rf230_start,
@@ -1249,6 +1252,7 @@ static struct ieee802154_ops at86rf230_ops = {
        .set_cca_ed_level = at86rf230_set_cca_ed_level,
        .set_csma_params = at86rf230_set_csma_params,
        .set_frame_retries = at86rf230_set_frame_retries,
+       .set_promiscuous_mode = at86rf230_set_promiscuous_mode,
 };
 
 static struct at86rf2xx_chip_data at86rf233_data = {
@@ -1260,7 +1264,7 @@ static struct at86rf2xx_chip_data at86rf233_data = {
        .t_frame = 4096,
        .t_p_ack = 545,
        .t_sifs = 192,
-       .t_lifs = 480,
+       .t_lifs = 640,
        .t_tx_timeout = 2000,
        .rssi_base_val = -91,
        .set_channel = at86rf23x_set_channel,
@@ -1276,7 +1280,7 @@ static struct at86rf2xx_chip_data at86rf231_data = {
        .t_frame = 4096,
        .t_p_ack = 545,
        .t_sifs = 192,
-       .t_lifs = 480,
+       .t_lifs = 640,
        .t_tx_timeout = 2000,
        .rssi_base_val = -91,
        .set_channel = at86rf23x_set_channel,
@@ -1292,7 +1296,7 @@ static struct at86rf2xx_chip_data at86rf212_data = {
        .t_frame = 4096,
        .t_p_ack = 545,
        .t_sifs = 192,
-       .t_lifs = 480,
+       .t_lifs = 640,
        .t_tx_timeout = 2000,
        .rssi_base_val = -100,
        .set_channel = at86rf212_set_channel,
@@ -1409,9 +1413,10 @@ at86rf230_detect_device(struct at86rf230_local *lp)
                return -EINVAL;
        }
 
-       lp->dev->extra_tx_headroom = 0;
-       lp->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
-                        IEEE802154_HW_TXPOWER | IEEE802154_HW_CSMA;
+       lp->hw->extra_tx_headroom = 0;
+       lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK |
+                       IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET |
+                       IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS;
 
        switch (part) {
        case 2:
@@ -1421,15 +1426,15 @@ at86rf230_detect_device(struct at86rf230_local *lp)
        case 3:
                chip = "at86rf231";
                lp->data = &at86rf231_data;
-               lp->dev->phy->channels_supported[0] = 0x7FFF800;
+               lp->hw->phy->channels_supported[0] = 0x7FFF800;
                break;
        case 7:
                chip = "at86rf212";
                if (version == 1) {
                        lp->data = &at86rf212_data;
-                       lp->dev->flags |= IEEE802154_HW_LBT;
-                       lp->dev->phy->channels_supported[0] = 0x00007FF;
-                       lp->dev->phy->channels_supported[2] = 0x00007FF;
+                       lp->hw->flags |= IEEE802154_HW_LBT;
+                       lp->hw->phy->channels_supported[0] = 0x00007FF;
+                       lp->hw->phy->channels_supported[2] = 0x00007FF;
                } else {
                        rc = -ENOTSUPP;
                }
@@ -1437,7 +1442,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
        case 11:
                chip = "at86rf233";
                lp->data = &at86rf233_data;
-               lp->dev->phy->channels_supported[0] = 0x7FFF800;
+               lp->hw->phy->channels_supported[0] = 0x7FFF800;
                break;
        default:
                chip = "unkown";
@@ -1478,7 +1483,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp)
 static int at86rf230_probe(struct spi_device *spi)
 {
        struct at86rf230_platform_data *pdata;
-       struct ieee802154_dev *dev;
+       struct ieee802154_hw *hw;
        struct at86rf230_local *lp;
        unsigned int status;
        int rc, irq_type;
@@ -1517,14 +1522,14 @@ static int at86rf230_probe(struct spi_device *spi)
                usleep_range(120, 240);
        }
 
-       dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
-       if (!dev)
+       hw = ieee802154_alloc_hw(sizeof(*lp), &at86rf230_ops);
+       if (!hw)
                return -ENOMEM;
 
-       lp = dev->priv;
-       lp->dev = dev;
+       lp = hw->priv;
+       lp->hw = hw;
        lp->spi = spi;
-       dev->parent = &spi->dev;
+       hw->parent = &spi->dev;
 
        lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
        if (IS_ERR(lp->regmap)) {
@@ -1541,7 +1546,6 @@ static int at86rf230_probe(struct spi_device *spi)
                goto free_dev;
 
        spin_lock_init(&lp->lock);
-       init_completion(&lp->tx_complete);
        init_completion(&lp->state_complete);
 
        spi_set_drvdata(spi, lp);
@@ -1564,14 +1568,14 @@ static int at86rf230_probe(struct spi_device *spi)
        if (rc)
                goto free_dev;
 
-       rc = ieee802154_register_device(lp->dev);
+       rc = ieee802154_register_hw(lp->hw);
        if (rc)
                goto free_dev;
 
        return rc;
 
 free_dev:
-       ieee802154_free_device(lp->dev);
+       ieee802154_free_hw(lp->hw);
 
        return rc;
 }
@@ -1582,8 +1586,8 @@ static int at86rf230_remove(struct spi_device *spi)
 
        /* mask all at86rf230 irq's */
        at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
-       ieee802154_unregister_device(lp->dev);
-       ieee802154_free_device(lp->dev);
+       ieee802154_unregister_hw(lp->hw);
+       ieee802154_free_hw(lp->hw);
        dev_dbg(&spi->dev, "unregistered at86rf230\n");
 
        return 0;
index 8a5ac7ab2300008ef2c8839272eb72b5eae1759c..340671b747b1ae57704fd2edda226027254a08ff 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/of_gpio.h>
+#include <linux/ieee802154.h>
 
 #include <net/mac802154.h>
-#include <net/wpan-phy.h>
-#include <net/ieee802154.h>
+#include <net/cfg802154.h>
 
 #define        SPI_COMMAND_BUFFER      3
 #define        HIGH                    1
 /* Driver private information */
 struct cc2520_private {
        struct spi_device *spi;         /* SPI device structure */
-       struct ieee802154_dev *dev;     /* IEEE-802.15.4 device */
+       struct ieee802154_hw *hw;       /* IEEE-802.15.4 device */
        u8 *buf;                        /* SPI TX/Rx data buffer */
        struct mutex buffer_mutex;      /* SPI buffer mutex */
        bool is_tx;                     /* Flag for sync b/w Tx and Rx */
@@ -453,20 +453,20 @@ cc2520_read_rxfifo(struct cc2520_private *priv, u8 *data, u8 len, u8 *lqi)
        return status;
 }
 
-static int cc2520_start(struct ieee802154_dev *dev)
+static int cc2520_start(struct ieee802154_hw *hw)
 {
-       return cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRXON);
+       return cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRXON);
 }
 
-static void cc2520_stop(struct ieee802154_dev *dev)
+static void cc2520_stop(struct ieee802154_hw *hw)
 {
-       cc2520_cmd_strobe(dev->priv, CC2520_CMD_SRFOFF);
+       cc2520_cmd_strobe(hw->priv, CC2520_CMD_SRFOFF);
 }
 
 static int
-cc2520_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
 {
-       struct cc2520_private *priv = dev->priv;
+       struct cc2520_private *priv = hw->priv;
        unsigned long flags;
        int rc;
        u8 status = 0;
@@ -524,7 +524,7 @@ static int cc2520_rx(struct cc2520_private *priv)
        if (len < 2 || len > IEEE802154_MTU)
                return -EINVAL;
 
-       skb = alloc_skb(len, GFP_KERNEL);
+       skb = dev_alloc_skb(len);
        if (!skb)
                return -ENOMEM;
 
@@ -536,7 +536,7 @@ static int cc2520_rx(struct cc2520_private *priv)
 
        skb_trim(skb, skb->len - 2);
 
-       ieee802154_rx_irqsafe(priv->dev, skb, lqi);
+       ieee802154_rx_irqsafe(priv->hw, skb, lqi);
 
        dev_vdbg(&priv->spi->dev, "RXFIFO: %x %x\n", len, lqi);
 
@@ -544,9 +544,9 @@ static int cc2520_rx(struct cc2520_private *priv)
 }
 
 static int
-cc2520_ed(struct ieee802154_dev *dev, u8 *level)
+cc2520_ed(struct ieee802154_hw *hw, u8 *level)
 {
-       struct cc2520_private *priv = dev->priv;
+       struct cc2520_private *priv = hw->priv;
        u8 status = 0xff;
        u8 rssi;
        int ret;
@@ -569,12 +569,11 @@ cc2520_ed(struct ieee802154_dev *dev, u8 *level)
 }
 
 static int
-cc2520_set_channel(struct ieee802154_dev *dev, int page, int channel)
+cc2520_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
 {
-       struct cc2520_private *priv = dev->priv;
+       struct cc2520_private *priv = hw->priv;
        int ret;
 
-       might_sleep();
        dev_dbg(&priv->spi->dev, "trying to set channel\n");
 
        BUG_ON(page != 0);
@@ -588,12 +587,12 @@ cc2520_set_channel(struct ieee802154_dev *dev, int page, int channel)
 }
 
 static int
-cc2520_filter(struct ieee802154_dev *dev,
+cc2520_filter(struct ieee802154_hw *hw,
              struct ieee802154_hw_addr_filt *filt, unsigned long changed)
 {
-       struct cc2520_private *priv = dev->priv;
+       struct cc2520_private *priv = hw->priv;
 
-       if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANID_CHANGED) {
                u16 panid = le16_to_cpu(filt->pan_id);
 
                dev_vdbg(&priv->spi->dev,
@@ -602,7 +601,7 @@ cc2520_filter(struct ieee802154_dev *dev,
                                 sizeof(panid), (u8 *)&panid);
        }
 
-       if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
                dev_vdbg(&priv->spi->dev,
                         "cc2520_filter called for IEEE addr\n");
                cc2520_write_ram(priv, CC2520RAM_IEEEADDR,
@@ -610,7 +609,7 @@ cc2520_filter(struct ieee802154_dev *dev,
                                 (u8 *)&filt->ieee_addr);
        }
 
-       if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
                u16 addr = le16_to_cpu(filt->short_addr);
 
                dev_vdbg(&priv->spi->dev,
@@ -619,7 +618,7 @@ cc2520_filter(struct ieee802154_dev *dev,
                                 sizeof(addr), (u8 *)&addr);
        }
 
-       if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANC_CHANGED) {
                dev_vdbg(&priv->spi->dev,
                         "cc2520_filter called for panc change\n");
                if (filt->pan_coord)
@@ -631,11 +630,11 @@ cc2520_filter(struct ieee802154_dev *dev,
        return 0;
 }
 
-static struct ieee802154_ops cc2520_ops = {
+static const struct ieee802154_ops cc2520_ops = {
        .owner = THIS_MODULE,
        .start = cc2520_start,
        .stop = cc2520_stop,
-       .xmit = cc2520_tx,
+       .xmit_sync = cc2520_tx,
        .ed = cc2520_ed,
        .set_channel = cc2520_set_channel,
        .set_hw_addr_filt = cc2520_filter,
@@ -645,27 +644,28 @@ static int cc2520_register(struct cc2520_private *priv)
 {
        int ret = -ENOMEM;
 
-       priv->dev = ieee802154_alloc_device(sizeof(*priv), &cc2520_ops);
-       if (!priv->dev)
+       priv->hw = ieee802154_alloc_hw(sizeof(*priv), &cc2520_ops);
+       if (!priv->hw)
                goto err_ret;
 
-       priv->dev->priv = priv;
-       priv->dev->parent = &priv->spi->dev;
-       priv->dev->extra_tx_headroom = 0;
+       priv->hw->priv = priv;
+       priv->hw->parent = &priv->spi->dev;
+       priv->hw->extra_tx_headroom = 0;
 
        /* We do support only 2.4 Ghz */
-       priv->dev->phy->channels_supported[0] = 0x7FFF800;
-       priv->dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
+       priv->hw->phy->channels_supported[0] = 0x7FFF800;
+       priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
+                         IEEE802154_HW_AFILT;
 
        dev_vdbg(&priv->spi->dev, "registered cc2520\n");
-       ret = ieee802154_register_device(priv->dev);
+       ret = ieee802154_register_hw(priv->hw);
        if (ret)
                goto err_free_device;
 
        return 0;
 
 err_free_device:
-       ieee802154_free_device(priv->dev);
+       ieee802154_free_hw(priv->hw);
 err_ret:
        return ret;
 }
@@ -1002,8 +1002,8 @@ static int cc2520_remove(struct spi_device *spi)
        mutex_destroy(&priv->buffer_mutex);
        flush_work(&priv->fifop_irqwork);
 
-       ieee802154_unregister_device(priv->dev);
-       ieee802154_free_device(priv->dev);
+       ieee802154_unregister_hw(priv->hw);
+       ieee802154_free_hw(priv->hw);
 
        return 0;
 }
diff --git a/drivers/net/ieee802154/fakehard.c b/drivers/net/ieee802154/fakehard.c
deleted file mode 100644 (file)
index 9ce854f..0000000
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Sample driver for HardMAC IEEE 802.15.4 devices
- *
- * Copyright (C) 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com>
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-
-#include <net/af_ieee802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/ieee802154.h>
-#include <net/nl802154.h>
-#include <net/wpan-phy.h>
-
-struct fakehard_priv {
-       struct wpan_phy *phy;
-};
-
-static struct wpan_phy *fake_to_phy(const struct net_device *dev)
-{
-       struct fakehard_priv *priv = netdev_priv(dev);
-       return priv->phy;
-}
-
-/**
- * fake_get_phy - Return a phy corresponding to this device.
- * @dev: The network device for which to return the wan-phy object
- *
- * This function returns a wpan-phy object corresponding to the passed
- * network device. Reference counter for wpan-phy object is incremented,
- * so when the wpan-phy isn't necessary, you should drop the reference
- * via @wpan_phy_put() call.
- */
-static struct wpan_phy *fake_get_phy(const struct net_device *dev)
-{
-       struct wpan_phy *phy = fake_to_phy(dev);
-       return to_phy(get_device(&phy->dev));
-}
-
-/**
- * fake_get_pan_id - Retrieve the PAN ID of the device.
- * @dev: The network device to retrieve the PAN of.
- *
- * Return the ID of the PAN from the PIB.
- */
-static __le16 fake_get_pan_id(const struct net_device *dev)
-{
-       BUG_ON(dev->type != ARPHRD_IEEE802154);
-
-       return cpu_to_le16(0xeba1);
-}
-
-/**
- * fake_get_short_addr - Retrieve the short address of the device.
- * @dev: The network device to retrieve the short address of.
- *
- * Returns the IEEE 802.15.4 short-form address cached for this
- * device. If the device has not yet had a short address assigned
- * then this should return 0xFFFF to indicate a lack of association.
- */
-static __le16 fake_get_short_addr(const struct net_device *dev)
-{
-       BUG_ON(dev->type != ARPHRD_IEEE802154);
-
-       return cpu_to_le16(0x1);
-}
-
-/**
- * fake_get_dsn - Retrieve the DSN of the device.
- * @dev: The network device to retrieve the DSN for.
- *
- * Returns the IEEE 802.15.4 DSN for the network device.
- * The DSN is the sequence number which will be added to each
- * packet or MAC command frame by the MAC during transmission.
- *
- * DSN means 'Data Sequence Number'.
- *
- * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
- *       document.
- */
-static u8 fake_get_dsn(const struct net_device *dev)
-{
-       BUG_ON(dev->type != ARPHRD_IEEE802154);
-
-       return 0x00; /* DSN are implemented in HW, so return just 0 */
-}
-
-/**
- * fake_assoc_req - Make an association request to the HW.
- * @dev: The network device which we are associating to a network.
- * @addr: The coordinator with which we wish to associate.
- * @channel: The channel on which to associate.
- * @cap: The capability information field to use in the association.
- *
- * Start an association with a coordinator. The coordinator's address
- * and PAN ID can be found in @addr.
- *
- * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
- *       802.15.4-2006 document.
- */
-static int fake_assoc_req(struct net_device *dev,
-               struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
-{
-       struct wpan_phy *phy = fake_to_phy(dev);
-
-       mutex_lock(&phy->pib_lock);
-       phy->current_channel = channel;
-       phy->current_page = page;
-       mutex_unlock(&phy->pib_lock);
-
-       /* We simply emulate it here */
-       return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
-                       IEEE802154_SUCCESS);
-}
-
-/**
- * fake_assoc_resp - Send an association response to a device.
- * @dev: The network device on which to send the response.
- * @addr: The address of the device to respond to.
- * @short_addr: The assigned short address for the device (if any).
- * @status: The result of the association request.
- *
- * Queue the association response of the coordinator to another
- * device's attempt to associate with the network which we
- * coordinate. This is then added to the indirect-send queue to be
- * transmitted to the end device when it polls for data.
- *
- * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
- *       802.15.4-2006 document.
- */
-static int fake_assoc_resp(struct net_device *dev,
-               struct ieee802154_addr *addr, __le16 short_addr, u8 status)
-{
-       return 0;
-}
-
-/**
- * fake_disassoc_req - Disassociate a device from a network.
- * @dev: The network device on which we're disassociating a device.
- * @addr: The device to disassociate from the network.
- * @reason: The reason to give to the device for being disassociated.
- *
- * This sends a disassociation notification to the device being
- * disassociated from the network.
- *
- * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
- *       document, with the reason described in 7.3.3.2.
- */
-static int fake_disassoc_req(struct net_device *dev,
-               struct ieee802154_addr *addr, u8 reason)
-{
-       return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
-}
-
-/**
- * fake_start_req - Start an IEEE 802.15.4 PAN.
- * @dev: The network device on which to start the PAN.
- * @addr: The coordinator address to use when starting the PAN.
- * @channel: The channel on which to start the PAN.
- * @bcn_ord: Beacon order.
- * @sf_ord: Superframe order.
- * @pan_coord: Whether or not we are the PAN coordinator or just
- *             requesting a realignment perhaps?
- * @blx: Battery Life Extension feature bitfield.
- * @coord_realign: Something to realign something else.
- *
- * If pan_coord is non-zero then this starts a network with the
- * provided parameters, otherwise it attempts a coordinator
- * realignment of the stated network instead.
- *
- * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
- * document, with 7.3.8 describing coordinator realignment.
- */
-static int fake_start_req(struct net_device *dev,
-                         struct ieee802154_addr *addr, u8 channel, u8 page,
-                         u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
-                         u8 coord_realign)
-{
-       struct wpan_phy *phy = fake_to_phy(dev);
-
-       mutex_lock(&phy->pib_lock);
-       phy->current_channel = channel;
-       phy->current_page = page;
-       mutex_unlock(&phy->pib_lock);
-
-       /* We don't emulate beacons here at all, so START should fail */
-       ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
-       return 0;
-}
-
-/**
- * fake_scan_req - Start a channel scan.
- * @dev: The network device on which to perform a channel scan.
- * @type: The type of scan to perform.
- * @channels: The channel bitmask to scan.
- * @duration: How long to spend on each channel.
- *
- * This starts either a passive (energy) scan or an active (PAN) scan
- * on the channels indicated in the @channels bitmask. The duration of
- * the scan is measured in terms of superframe duration. Specifically,
- * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
- * channel.
- *
- * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
- */
-static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
-               u8 page, u8 duration)
-{
-       u8 edl[27] = {};
-       return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
-                       channels, page,
-                       type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
-}
-
-static struct ieee802154_mlme_ops fake_mlme = {
-       .assoc_req = fake_assoc_req,
-       .assoc_resp = fake_assoc_resp,
-       .disassoc_req = fake_disassoc_req,
-       .start_req = fake_start_req,
-       .scan_req = fake_scan_req,
-
-       .get_phy = fake_get_phy,
-
-       .get_pan_id = fake_get_pan_id,
-       .get_short_addr = fake_get_short_addr,
-       .get_dsn = fake_get_dsn,
-};
-
-static int ieee802154_fake_open(struct net_device *dev)
-{
-       netif_start_queue(dev);
-       return 0;
-}
-
-static int ieee802154_fake_close(struct net_device *dev)
-{
-       netif_stop_queue(dev);
-       return 0;
-}
-
-static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb,
-                                             struct net_device *dev)
-{
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       /* FIXME: do hardware work here ... */
-
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-
-static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
-               int cmd)
-{
-       struct sockaddr_ieee802154 *sa =
-               (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
-       u16 pan_id, short_addr;
-
-       switch (cmd) {
-       case SIOCGIFADDR:
-               /* FIXME: fixed here, get from device IRL */
-               pan_id = le16_to_cpu(fake_get_pan_id(dev));
-               short_addr = le16_to_cpu(fake_get_short_addr(dev));
-               if (pan_id == IEEE802154_PANID_BROADCAST ||
-                   short_addr == IEEE802154_ADDR_BROADCAST)
-                       return -EADDRNOTAVAIL;
-
-               sa->family = AF_IEEE802154;
-               sa->addr.addr_type = IEEE802154_ADDR_SHORT;
-               sa->addr.pan_id = pan_id;
-               sa->addr.short_addr = short_addr;
-               return 0;
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int ieee802154_fake_mac_addr(struct net_device *dev, void *p)
-{
-       return -EBUSY; /* HW address is built into the device */
-}
-
-static const struct net_device_ops fake_ops = {
-       .ndo_open               = ieee802154_fake_open,
-       .ndo_stop               = ieee802154_fake_close,
-       .ndo_start_xmit         = ieee802154_fake_xmit,
-       .ndo_do_ioctl           = ieee802154_fake_ioctl,
-       .ndo_set_mac_address    = ieee802154_fake_mac_addr,
-};
-
-static void ieee802154_fake_destruct(struct net_device *dev)
-{
-       struct wpan_phy *phy = fake_to_phy(dev);
-
-       wpan_phy_unregister(phy);
-       free_netdev(dev);
-       wpan_phy_free(phy);
-}
-
-static void ieee802154_fake_setup(struct net_device *dev)
-{
-       dev->addr_len           = IEEE802154_ADDR_LEN;
-       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
-       dev->features           = NETIF_F_HW_CSUM;
-       dev->needed_tailroom    = 2; /* FCS */
-       dev->mtu                = 127;
-       dev->tx_queue_len       = 10;
-       dev->type               = ARPHRD_IEEE802154;
-       dev->flags              = IFF_NOARP | IFF_BROADCAST;
-       dev->watchdog_timeo     = 0;
-       dev->destructor         = ieee802154_fake_destruct;
-}
-
-
-static int ieee802154fake_probe(struct platform_device *pdev)
-{
-       struct net_device *dev;
-       struct fakehard_priv *priv;
-       struct wpan_phy *phy = wpan_phy_alloc(0);
-       int err;
-
-       if (!phy)
-               return -ENOMEM;
-
-       dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d",
-                          NET_NAME_UNKNOWN, ieee802154_fake_setup);
-       if (!dev) {
-               wpan_phy_free(phy);
-               return -ENOMEM;
-       }
-
-       memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
-                       dev->addr_len);
-
-       /*
-        * For now we'd like to emulate 2.4 GHz-only device,
-        * both O-QPSK and CSS
-        */
-       /* 2.4 GHz O-QPSK 802.15.4-2003 */
-       phy->channels_supported[0] |= 0x7FFF800;
-       /* 2.4 GHz CSS 802.15.4a-2007 */
-       phy->channels_supported[3] |= 0x3fff;
-
-       phy->transmit_power = 0xbf;
-
-       dev->netdev_ops = &fake_ops;
-       dev->ml_priv = &fake_mlme;
-
-       priv = netdev_priv(dev);
-       priv->phy = phy;
-
-       wpan_phy_set_dev(phy, &pdev->dev);
-       SET_NETDEV_DEV(dev, &phy->dev);
-
-       platform_set_drvdata(pdev, dev);
-
-       err = wpan_phy_register(phy);
-       if (err)
-               goto out;
-
-       err = register_netdev(dev);
-       if (err < 0)
-               goto out;
-
-       dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
-       return 0;
-
-out:
-       unregister_netdev(dev);
-       return err;
-}
-
-static int ieee802154fake_remove(struct platform_device *pdev)
-{
-       struct net_device *dev = platform_get_drvdata(pdev);
-       unregister_netdev(dev);
-       return 0;
-}
-
-static struct platform_device *ieee802154fake_dev;
-
-static struct platform_driver ieee802154fake_driver = {
-       .probe = ieee802154fake_probe,
-       .remove = ieee802154fake_remove,
-       .driver = {
-                       .name = "ieee802154hardmac",
-                       .owner = THIS_MODULE,
-       },
-};
-
-static __init int fake_init(void)
-{
-       ieee802154fake_dev = platform_device_register_simple(
-                       "ieee802154hardmac", -1, NULL, 0);
-       return platform_driver_register(&ieee802154fake_driver);
-}
-
-static __exit void fake_exit(void)
-{
-       platform_driver_unregister(&ieee802154fake_driver);
-       platform_device_unregister(ieee802154fake_dev);
-}
-
-module_init(fake_init);
-module_exit(fake_exit);
-MODULE_LICENSE("GPL");
index 27d83207d24ce0de722144c74e98ce65601fcfc0..6e62286cef7849c4523e1334015729ca7f8fa39a 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 #include <linux/device.h>
 #include <linux/spinlock.h>
 #include <net/mac802154.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 
 static int numlbs = 1;
 
 struct fakelb_dev_priv {
-       struct ieee802154_dev *dev;
+       struct ieee802154_hw *hw;
 
        struct list_head list;
        struct fakelb_priv *fake;
@@ -49,9 +45,8 @@ struct fakelb_priv {
 };
 
 static int
-fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
+fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)
 {
-       might_sleep();
        BUG_ON(!level);
        *level = 0xbe;
 
@@ -59,13 +54,12 @@ fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level)
 }
 
 static int
-fakelb_hw_channel(struct ieee802154_dev *dev, int page, int channel)
+fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
 {
        pr_debug("set channel to %d\n", channel);
 
-       might_sleep();
-       dev->phy->current_page = page;
-       dev->phy->current_channel = channel;
+       hw->phy->current_page = page;
+       hw->phy->current_channel = channel;
 
        return 0;
 }
@@ -78,19 +72,17 @@ fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb)
        spin_lock(&priv->lock);
        if (priv->working) {
                newskb = pskb_copy(skb, GFP_ATOMIC);
-               ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc);
+               ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc);
        }
        spin_unlock(&priv->lock);
 }
 
 static int
-fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
+fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
 {
-       struct fakelb_dev_priv *priv = dev->priv;
+       struct fakelb_dev_priv *priv = hw->priv;
        struct fakelb_priv *fake = priv->fake;
 
-       might_sleep();
-
        read_lock_bh(&fake->lock);
        if (priv->list.next == priv->list.prev) {
                /* we are the only one device */
@@ -99,8 +91,8 @@ fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
                struct fakelb_dev_priv *dp;
                list_for_each_entry(dp, &priv->fake->list, list) {
                        if (dp != priv &&
-                           (dp->dev->phy->current_channel ==
-                            priv->dev->phy->current_channel))
+                           (dp->hw->phy->current_channel ==
+                            priv->hw->phy->current_channel))
                                fakelb_hw_deliver(dp, skb);
                }
        }
@@ -110,8 +102,8 @@ fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
 }
 
 static int
-fakelb_hw_start(struct ieee802154_dev *dev) {
-       struct fakelb_dev_priv *priv = dev->priv;
+fakelb_hw_start(struct ieee802154_hw *hw) {
+       struct fakelb_dev_priv *priv = hw->priv;
        int ret = 0;
 
        spin_lock(&priv->lock);
@@ -125,17 +117,17 @@ fakelb_hw_start(struct ieee802154_dev *dev) {
 }
 
 static void
-fakelb_hw_stop(struct ieee802154_dev *dev) {
-       struct fakelb_dev_priv *priv = dev->priv;
+fakelb_hw_stop(struct ieee802154_hw *hw) {
+       struct fakelb_dev_priv *priv = hw->priv;
 
        spin_lock(&priv->lock);
        priv->working = 0;
        spin_unlock(&priv->lock);
 }
 
-static struct ieee802154_ops fakelb_ops = {
+static const struct ieee802154_ops fakelb_ops = {
        .owner = THIS_MODULE,
-       .xmit = fakelb_hw_xmit,
+       .xmit_sync = fakelb_hw_xmit,
        .ed = fakelb_hw_ed,
        .set_channel = fakelb_hw_channel,
        .start = fakelb_hw_start,
@@ -150,54 +142,54 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
 {
        struct fakelb_dev_priv *priv;
        int err;
-       struct ieee802154_dev *ieee;
+       struct ieee802154_hw *hw;
 
-       ieee = ieee802154_alloc_device(sizeof(*priv), &fakelb_ops);
-       if (!ieee)
+       hw = ieee802154_alloc_hw(sizeof(*priv), &fakelb_ops);
+       if (!hw)
                return -ENOMEM;
 
-       priv = ieee->priv;
-       priv->dev = ieee;
+       priv = hw->priv;
+       priv->hw = hw;
 
        /* 868 MHz BPSK 802.15.4-2003 */
-       ieee->phy->channels_supported[0] |= 1;
+       hw->phy->channels_supported[0] |= 1;
        /* 915 MHz BPSK 802.15.4-2003 */
-       ieee->phy->channels_supported[0] |= 0x7fe;
+       hw->phy->channels_supported[0] |= 0x7fe;
        /* 2.4 GHz O-QPSK 802.15.4-2003 */
-       ieee->phy->channels_supported[0] |= 0x7FFF800;
+       hw->phy->channels_supported[0] |= 0x7FFF800;
        /* 868 MHz ASK 802.15.4-2006 */
-       ieee->phy->channels_supported[1] |= 1;
+       hw->phy->channels_supported[1] |= 1;
        /* 915 MHz ASK 802.15.4-2006 */
-       ieee->phy->channels_supported[1] |= 0x7fe;
+       hw->phy->channels_supported[1] |= 0x7fe;
        /* 868 MHz O-QPSK 802.15.4-2006 */
-       ieee->phy->channels_supported[2] |= 1;
+       hw->phy->channels_supported[2] |= 1;
        /* 915 MHz O-QPSK 802.15.4-2006 */
-       ieee->phy->channels_supported[2] |= 0x7fe;
+       hw->phy->channels_supported[2] |= 0x7fe;
        /* 2.4 GHz CSS 802.15.4a-2007 */
-       ieee->phy->channels_supported[3] |= 0x3fff;
+       hw->phy->channels_supported[3] |= 0x3fff;
        /* UWB Sub-gigahertz 802.15.4a-2007 */
-       ieee->phy->channels_supported[4] |= 1;
+       hw->phy->channels_supported[4] |= 1;
        /* UWB Low band 802.15.4a-2007 */
-       ieee->phy->channels_supported[4] |= 0x1e;
+       hw->phy->channels_supported[4] |= 0x1e;
        /* UWB High band 802.15.4a-2007 */
-       ieee->phy->channels_supported[4] |= 0xffe0;
+       hw->phy->channels_supported[4] |= 0xffe0;
        /* 750 MHz O-QPSK 802.15.4c-2009 */
-       ieee->phy->channels_supported[5] |= 0xf;
+       hw->phy->channels_supported[5] |= 0xf;
        /* 750 MHz MPSK 802.15.4c-2009 */
-       ieee->phy->channels_supported[5] |= 0xf0;
+       hw->phy->channels_supported[5] |= 0xf0;
        /* 950 MHz BPSK 802.15.4d-2009 */
-       ieee->phy->channels_supported[6] |= 0x3ff;
+       hw->phy->channels_supported[6] |= 0x3ff;
        /* 950 MHz GFSK 802.15.4d-2009 */
-       ieee->phy->channels_supported[6] |= 0x3ffc00;
+       hw->phy->channels_supported[6] |= 0x3ffc00;
 
        INIT_LIST_HEAD(&priv->list);
        priv->fake = fake;
 
        spin_lock_init(&priv->lock);
 
-       ieee->parent = dev;
+       hw->parent = dev;
 
-       err = ieee802154_register_device(ieee);
+       err = ieee802154_register_hw(hw);
        if (err)
                goto err_reg;
 
@@ -208,7 +200,7 @@ static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake)
        return 0;
 
 err_reg:
-       ieee802154_free_device(priv->dev);
+       ieee802154_free_hw(priv->hw);
        return err;
 }
 
@@ -218,8 +210,8 @@ static void fakelb_del(struct fakelb_dev_priv *priv)
        list_del(&priv->list);
        write_unlock_bh(&priv->fake->lock);
 
-       ieee802154_unregister_device(priv->dev);
-       ieee802154_free_device(priv->dev);
+       ieee802154_unregister_hw(priv->hw);
+       ieee802154_free_hw(priv->hw);
 }
 
 static int fakelb_probe(struct platform_device *pdev)
index 07e0b887c350f07bb125b88479626187f814e828..a200fa16beae406757095f0f7090999b7a596b9c 100644 (file)
  * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/spi/spi.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
-#include <net/wpan-phy.h>
+#include <linux/ieee802154.h>
+#include <net/cfg802154.h>
 #include <net/mac802154.h>
-#include <net/ieee802154.h>
 
 /* MRF24J40 Short Address Registers */
 #define REG_RXMCR    0x00  /* Receive MAC control */
@@ -43,6 +39,8 @@
 #define REG_TXSTBL   0x2E  /* TX Stabilization */
 #define REG_INTSTAT  0x31  /* Interrupt Status */
 #define REG_INTCON   0x32  /* Interrupt Control */
+#define REG_GPIO     0x33  /* GPIO */
+#define REG_TRISGPIO 0x34  /* GPIO direction */
 #define REG_RFCTL    0x36  /* RF Control Mode Register */
 #define REG_BBREG1   0x39  /* Baseband Registers */
 #define REG_BBREG2   0x3A  /* */
@@ -63,6 +61,7 @@
 #define REG_SLPCON1    0x220
 #define REG_WAKETIMEL  0x222  /* Wake-up Time Match Value Low */
 #define REG_WAKETIMEH  0x223  /* Wake-up Time Match Value High */
+#define REG_TESTMODE   0x22F  /* Test mode */
 #define REG_RX_FIFO    0x300  /* Receive FIFO */
 
 /* Device configuration: Only channels 11-26 on page 0 are supported. */
 #define RX_FIFO_SIZE 144 /* From datasheet */
 #define SET_CHANNEL_DELAY_US 192 /* From datasheet */
 
+enum mrf24j40_modules { MRF24J40, MRF24J40MA, MRF24J40MC };
+
 /* Device Private Data */
 struct mrf24j40 {
        struct spi_device *spi;
-       struct ieee802154_dev *dev;
+       struct ieee802154_hw *hw;
 
        struct mutex buffer_mutex; /* only used to protect buf */
        struct completion tx_complete;
@@ -331,9 +332,9 @@ out:
        return ret;
 }
 
-static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
+static int mrf24j40_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret = 0;
 
@@ -382,7 +383,7 @@ err:
        return ret;
 }
 
-static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
+static int mrf24j40_ed(struct ieee802154_hw *hw, u8 *level)
 {
        /* TODO: */
        pr_warn("mrf24j40: ed not implemented\n");
@@ -390,9 +391,9 @@ static int mrf24j40_ed(struct ieee802154_dev *dev, u8 *level)
        return 0;
 }
 
-static int mrf24j40_start(struct ieee802154_dev *dev)
+static int mrf24j40_start(struct ieee802154_hw *hw)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret;
 
@@ -407,9 +408,9 @@ static int mrf24j40_start(struct ieee802154_dev *dev)
        return 0;
 }
 
-static void mrf24j40_stop(struct ieee802154_dev *dev)
+static void mrf24j40_stop(struct ieee802154_hw *hw)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret;
 
@@ -422,10 +423,9 @@ static void mrf24j40_stop(struct ieee802154_dev *dev)
        write_short_reg(devrec, REG_INTCON, val);
 }
 
-static int mrf24j40_set_channel(struct ieee802154_dev *dev,
-                               int page, int channel)
+static int mrf24j40_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
        u8 val;
        int ret;
 
@@ -453,15 +453,15 @@ static int mrf24j40_set_channel(struct ieee802154_dev *dev,
        return 0;
 }
 
-static int mrf24j40_filter(struct ieee802154_dev *dev,
+static int mrf24j40_filter(struct ieee802154_hw *hw,
                           struct ieee802154_hw_addr_filt *filt,
                           unsigned long changed)
 {
-       struct mrf24j40 *devrec = dev->priv;
+       struct mrf24j40 *devrec = hw->priv;
 
        dev_dbg(printdev(devrec), "filter\n");
 
-       if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
                /* Short Addr */
                u8 addrh, addrl;
 
@@ -474,7 +474,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
                        "Set short addr to %04hx\n", filt->short_addr);
        }
 
-       if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+       if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
                /* Device Address */
                u8 i, addr[8];
 
@@ -490,7 +490,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
 #endif
        }
 
-       if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANID_CHANGED) {
                /* PAN ID */
                u8 panidl, panidh;
 
@@ -502,7 +502,7 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
                dev_dbg(printdev(devrec), "Set PANID to %04hx\n", filt->pan_id);
        }
 
-       if (changed & IEEE802515_AFILT_PANC_CHANGED) {
+       if (changed & IEEE802154_AFILT_PANC_CHANGED) {
                /* Pan Coordinator */
                u8 val;
                int ret;
@@ -543,7 +543,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
        val |= 4; /* SET RXDECINV */
        write_short_reg(devrec, REG_BBREG1, val);
 
-       skb = alloc_skb(len, GFP_KERNEL);
+       skb = dev_alloc_skb(len);
        if (!skb) {
                ret = -ENOMEM;
                goto out;
@@ -563,7 +563,7 @@ static int mrf24j40_handle_rx(struct mrf24j40 *devrec)
        /* TODO: Other drivers call ieee20154_rx_irqsafe() here (eg: cc2040,
         * also from a workqueue).  I think irqsafe is not necessary here.
         * Can someone confirm? */
-       ieee802154_rx_irqsafe(devrec->dev, skb, lqi);
+       ieee802154_rx_irqsafe(devrec->hw, skb, lqi);
 
        dev_dbg(printdev(devrec), "RX Handled\n");
 
@@ -578,9 +578,9 @@ out:
        return ret;
 }
 
-static struct ieee802154_ops mrf24j40_ops = {
+static const struct ieee802154_ops mrf24j40_ops = {
        .owner = THIS_MODULE,
-       .xmit = mrf24j40_tx,
+       .xmit_sync = mrf24j40_tx,
        .ed = mrf24j40_ed,
        .start = mrf24j40_start,
        .stop = mrf24j40_stop,
@@ -691,6 +691,28 @@ static int mrf24j40_hw_init(struct mrf24j40 *devrec)
        if (ret)
                goto err_ret;
 
+       if (spi_get_device_id(devrec->spi)->driver_data == MRF24J40MC) {
+               /* Enable external amplifier.
+                * From MRF24J40MC datasheet section 1.3: Operation.
+                */
+               read_long_reg(devrec, REG_TESTMODE, &val);
+               val |= 0x7; /* Configure GPIO 0-2 to control amplifier */
+               write_long_reg(devrec, REG_TESTMODE, val);
+
+               read_short_reg(devrec, REG_TRISGPIO, &val);
+               val |= 0x8; /* Set GPIO3 as output. */
+               write_short_reg(devrec, REG_TRISGPIO, val);
+
+               read_short_reg(devrec, REG_GPIO, &val);
+               val |= 0x8; /* Set GPIO3 HIGH to enable U5 voltage regulator */
+               write_short_reg(devrec, REG_GPIO, val);
+
+               /* Reduce TX pwr to meet FCC requirements.
+                * From MRF24J40MC datasheet section 3.1.1
+                */
+               write_long_reg(devrec, REG_RFCON3, 0x28);
+       }
+
        return 0;
 
 err_ret:
@@ -722,17 +744,18 @@ static int mrf24j40_probe(struct spi_device *spi)
 
        /* Register with the 802154 subsystem */
 
-       devrec->dev = ieee802154_alloc_device(0, &mrf24j40_ops);
-       if (!devrec->dev)
+       devrec->hw = ieee802154_alloc_hw(0, &mrf24j40_ops);
+       if (!devrec->hw)
                goto err_ret;
 
-       devrec->dev->priv = devrec;
-       devrec->dev->parent = &devrec->spi->dev;
-       devrec->dev->phy->channels_supported[0] = CHANNEL_MASK;
-       devrec->dev->flags = IEEE802154_HW_OMIT_CKSUM|IEEE802154_HW_AACK;
+       devrec->hw->priv = devrec;
+       devrec->hw->parent = &devrec->spi->dev;
+       devrec->hw->phy->channels_supported[0] = CHANNEL_MASK;
+       devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK |
+                           IEEE802154_HW_AFILT;
 
        dev_dbg(printdev(devrec), "registered mrf24j40\n");
-       ret = ieee802154_register_device(devrec->dev);
+       ret = ieee802154_register_hw(devrec->hw);
        if (ret)
                goto err_register_device;
 
@@ -757,9 +780,9 @@ static int mrf24j40_probe(struct spi_device *spi)
 
 err_irq:
 err_hw_init:
-       ieee802154_unregister_device(devrec->dev);
+       ieee802154_unregister_hw(devrec->hw);
 err_register_device:
-       ieee802154_free_device(devrec->dev);
+       ieee802154_free_hw(devrec->hw);
 err_ret:
        return ret;
 }
@@ -770,8 +793,8 @@ static int mrf24j40_remove(struct spi_device *spi)
 
        dev_dbg(printdev(devrec), "remove\n");
 
-       ieee802154_unregister_device(devrec->dev);
-       ieee802154_free_device(devrec->dev);
+       ieee802154_unregister_hw(devrec->hw);
+       ieee802154_free_hw(devrec->hw);
        /* TODO: Will ieee802154_free_device() wait until ->xmit() is
         * complete? */
 
@@ -779,8 +802,9 @@ static int mrf24j40_remove(struct spi_device *spi)
 }
 
 static const struct spi_device_id mrf24j40_ids[] = {
-       { "mrf24j40", 0 },
-       { "mrf24j40ma", 0 },
+       { "mrf24j40", MRF24J40 },
+       { "mrf24j40ma", MRF24J40MA },
+       { "mrf24j40mc", MRF24J40MC },
        { },
 };
 MODULE_DEVICE_TABLE(spi, mrf24j40_ids);
index 86907e5ba6ca21a5e7e6d8ff8b6b20499e004cce..999d24ff242f9a0fa0ce2ea77f52529be73c1126 100644 (file)
@@ -148,7 +148,7 @@ struct ath_common {
        u16 cachelsz;
        u16 curaid;
        u8 macaddr[ETH_ALEN];
-       u8 curbssid[ETH_ALEN];
+       u8 curbssid[ETH_ALEN] __aligned(2);
        u8 bssidmask[ETH_ALEN];
 
        u32 rx_bufsize;
index 101cadb6e4ba8c3659200093f5da739c4a501236..9b89ac133946122d72a84fa26fb5c9bf443ec965 100644 (file)
@@ -443,12 +443,12 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr)
  * Guts of ath10k_ce_completed_recv_next.
  * The caller takes responsibility for any necessary locking.
  */
-static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
-                                               void **per_transfer_contextp,
-                                               u32 *bufferp,
-                                               unsigned int *nbytesp,
-                                               unsigned int *transfer_idp,
-                                               unsigned int *flagsp)
+int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
+                                        void **per_transfer_contextp,
+                                        u32 *bufferp,
+                                        unsigned int *nbytesp,
+                                        unsigned int *transfer_idp,
+                                        unsigned int *flagsp)
 {
        struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
        unsigned int nentries_mask = dest_ring->nentries_mask;
@@ -576,11 +576,11 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
  * Guts of ath10k_ce_completed_send_next.
  * The caller takes responsibility for any necessary locking.
  */
-static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
-                                               void **per_transfer_contextp,
-                                               u32 *bufferp,
-                                               unsigned int *nbytesp,
-                                               unsigned int *transfer_idp)
+int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
+                                        void **per_transfer_contextp,
+                                        u32 *bufferp,
+                                        unsigned int *nbytesp,
+                                        unsigned int *transfer_idp)
 {
        struct ath10k_ce_ring *src_ring = ce_state->src_ring;
        u32 ctrl_addr = ce_state->ctrl_addr;
@@ -817,7 +817,10 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar)
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        int ce_id;
 
-       for (ce_id = 0; ce_id < CE_COUNT; ce_id++)
+       /* 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]);
 }
 
@@ -1020,37 +1023,10 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
  * initialized by software/firmware.
  */
 int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
-                       const struct ce_attr *attr,
-                       void (*send_cb)(struct ath10k_ce_pipe *),
-                       void (*recv_cb)(struct ath10k_ce_pipe *))
+                       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];
        int ret;
 
-       /*
-        * Make sure there's enough CE ringbuffer entries for HTT TX to avoid
-        * additional TX locking checks.
-        *
-        * For the lack of a better place do the check here.
-        */
-       BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
-                    (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
-       BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
-                    (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
-
-       spin_lock_bh(&ar_pci->ce_lock);
-       ce_state->ar = ar;
-       ce_state->id = ce_id;
-       ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
-       ce_state->attr_flags = attr->flags;
-       ce_state->src_sz_max = attr->src_sz_max;
-       if (attr->src_nentries)
-               ce_state->send_cb = send_cb;
-       if (attr->dest_nentries)
-               ce_state->recv_cb = recv_cb;
-       spin_unlock_bh(&ar_pci->ce_lock);
-
        if (attr->src_nentries) {
                ret = ath10k_ce_init_src_ring(ar, ce_id, attr);
                if (ret) {
@@ -1098,12 +1074,37 @@ 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)
+                        const struct ce_attr *attr,
+                        void (*send_cb)(struct ath10k_ce_pipe *),
+                        void (*recv_cb)(struct ath10k_ce_pipe *))
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
        int ret;
 
+       /*
+        * Make sure there's enough CE ringbuffer entries for HTT TX to avoid
+        * additional TX locking checks.
+        *
+        * For the lack of a better place do the check here.
+        */
+       BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
+                    (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
+       BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
+                    (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
+
+       ce_state->ar = ar;
+       ce_state->id = ce_id;
+       ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
+       ce_state->attr_flags = attr->flags;
+       ce_state->src_sz_max = attr->src_sz_max;
+
+       if (attr->src_nentries)
+               ce_state->send_cb = send_cb;
+
+       if (attr->dest_nentries)
+               ce_state->recv_cb = recv_cb;
+
        if (attr->src_nentries) {
                ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr);
                if (IS_ERR(ce_state->src_ring)) {
index 329b7340fa72cc5157dec176686f4f19a5099629..617a151e8ce4e7f9217d836d1dcfc0483dc966d0 100644 (file)
@@ -192,15 +192,21 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
                                  unsigned int *nbytesp,
                                  unsigned int *transfer_idp);
 
+int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
+                                        void **per_transfer_contextp,
+                                        u32 *bufferp,
+                                        unsigned int *nbytesp,
+                                        unsigned int *transfer_idp);
+
 /*==================CE Engine Initialization=======================*/
 
 int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
-                       const struct ce_attr *attr,
-                       void (*send_cb)(struct ath10k_ce_pipe *),
-                       void (*recv_cb)(struct ath10k_ce_pipe *));
+                       const struct ce_attr *attr);
 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);
+                        const struct ce_attr *attr,
+                        void (*send_cb)(struct ath10k_ce_pipe *),
+                        void (*recv_cb)(struct ath10k_ce_pipe *));
 void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
 
 /*==================CE Engine Shutdown=======================*/
@@ -213,6 +219,13 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
                               void **per_transfer_contextp,
                               u32 *bufferp);
 
+int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
+                                        void **per_transfer_contextp,
+                                        u32 *bufferp,
+                                        unsigned int *nbytesp,
+                                        unsigned int *transfer_idp,
+                                        unsigned int *flagsp);
+
 /*
  * Support clean shutdown by allowing the caller to cancel
  * pending sends.  Target DMA must be stopped before using
index cee18c89d7f23ef77ad7a8a2265ca8efa887f9dd..5c23d00f7d609d900e975e311ebceefc81cdfe5b 100644 (file)
@@ -138,7 +138,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
        return fw;
 }
 
-static int ath10k_push_board_ext_data(struct ath10k *ar)
+static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
+                                     size_t data_len)
 {
        u32 board_data_size = QCA988X_BOARD_DATA_SZ;
        u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
@@ -159,14 +160,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
        if (board_ext_data_addr == 0)
                return 0;
 
-       if (ar->board_len != (board_data_size + board_ext_data_size)) {
+       if (data_len != (board_data_size + board_ext_data_size)) {
                ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",
-                          ar->board_len, board_data_size, board_ext_data_size);
+                          data_len, board_data_size, board_ext_data_size);
                return -EINVAL;
        }
 
        ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
-                                     ar->board_data + board_data_size,
+                                     data + board_data_size,
                                      board_ext_data_size);
        if (ret) {
                ath10k_err(ar, "could not write board ext data (%d)\n", ret);
@@ -184,13 +185,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar)
        return 0;
 }
 
-static int ath10k_download_board_data(struct ath10k *ar)
+static int ath10k_download_board_data(struct ath10k *ar, const void *data,
+                                     size_t data_len)
 {
        u32 board_data_size = QCA988X_BOARD_DATA_SZ;
        u32 address;
        int ret;
 
-       ret = ath10k_push_board_ext_data(ar);
+       ret = ath10k_push_board_ext_data(ar, data, data_len);
        if (ret) {
                ath10k_err(ar, "could not push board ext data (%d)\n", ret);
                goto exit;
@@ -202,9 +204,9 @@ static int ath10k_download_board_data(struct ath10k *ar)
                goto exit;
        }
 
-       ret = ath10k_bmi_write_memory(ar, address, ar->board_data,
+       ret = ath10k_bmi_write_memory(ar, address, data,
                                      min_t(u32, board_data_size,
-                                           ar->board_len));
+                                           data_len));
        if (ret) {
                ath10k_err(ar, "could not write board data (%d)\n", ret);
                goto exit;
@@ -220,11 +222,39 @@ exit:
        return ret;
 }
 
+static int ath10k_download_cal_file(struct ath10k *ar)
+{
+       int ret;
+
+       if (!ar->cal_file)
+               return -ENOENT;
+
+       if (IS_ERR(ar->cal_file))
+               return PTR_ERR(ar->cal_file);
+
+       ret = ath10k_download_board_data(ar, ar->cal_file->data,
+                                        ar->cal_file->size);
+       if (ret) {
+               ath10k_err(ar, "failed to download cal_file data: %d\n", ret);
+               return ret;
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");
+
+       return 0;
+}
+
 static int ath10k_download_and_run_otp(struct ath10k *ar)
 {
        u32 result, address = ar->hw_params.patch_load_addr;
        int ret;
 
+       ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len);
+       if (ret) {
+               ath10k_err(ar, "failed to download board data: %d\n", ret);
+               return ret;
+       }
+
        /* OTP is optional */
 
        if (!ar->otp_data || !ar->otp_len) {
@@ -308,6 +338,9 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
        if (ar->firmware && !IS_ERR(ar->firmware))
                release_firmware(ar->firmware);
 
+       if (ar->cal_file && !IS_ERR(ar->cal_file))
+               release_firmware(ar->cal_file);
+
        ar->board = NULL;
        ar->board_data = NULL;
        ar->board_len = 0;
@@ -319,6 +352,27 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
        ar->firmware = NULL;
        ar->firmware_data = NULL;
        ar->firmware_len = 0;
+
+       ar->cal_file = NULL;
+}
+
+static int ath10k_fetch_cal_file(struct ath10k *ar)
+{
+       char filename[100];
+
+       /* cal-<bus>-<id>.bin */
+       scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",
+                 ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
+
+       ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);
+       if (IS_ERR(ar->cal_file))
+               /* calibration file is optional, don't print any warnings */
+               return PTR_ERR(ar->cal_file);
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",
+                  ATH10K_FW_DIR, filename);
+
+       return 0;
 }
 
 static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
@@ -562,6 +616,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
 {
        int ret;
 
+       /* calibration file is optional, don't check for any errors */
+       ath10k_fetch_cal_file(ar);
+
        ar->fw_api = 3;
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
@@ -589,30 +646,32 @@ success:
        return 0;
 }
 
-static int ath10k_init_download_firmware(struct ath10k *ar,
-                                        enum ath10k_firmware_mode mode)
+static int ath10k_download_cal_data(struct ath10k *ar)
 {
        int ret;
 
-       ret = ath10k_download_board_data(ar);
-       if (ret) {
-               ath10k_err(ar, "failed to download board data: %d\n", ret);
-               return ret;
+       ret = ath10k_download_cal_file(ar);
+       if (ret == 0) {
+               ar->cal_mode = ATH10K_CAL_MODE_FILE;
+               goto done;
        }
 
+       ath10k_dbg(ar, ATH10K_DBG_BOOT,
+                  "boot did not find a calibration file, try OTP next: %d\n",
+                  ret);
+
        ret = ath10k_download_and_run_otp(ar);
        if (ret) {
                ath10k_err(ar, "failed to run otp: %d\n", ret);
                return ret;
        }
 
-       ret = ath10k_download_fw(ar, mode);
-       if (ret) {
-               ath10k_err(ar, "failed to download firmware: %d\n", ret);
-               return ret;
-       }
+       ar->cal_mode = ATH10K_CAL_MODE_OTP;
 
-       return ret;
+done:
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",
+                  ath10k_cal_mode_str(ar->cal_mode));
+       return 0;
 }
 
 static int ath10k_init_uart(struct ath10k *ar)
@@ -729,7 +788,11 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
                goto err;
        }
 
-       status = ath10k_init_download_firmware(ar, mode);
+       status = ath10k_download_cal_data(ar);
+       if (status)
+               goto err;
+
+       status = ath10k_download_fw(ar, mode);
        if (status)
                goto err;
 
@@ -846,9 +909,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
                goto err_hif_stop;
 
        if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-               ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1;
+               ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1;
        else
-               ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
+               ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
 
        INIT_LIST_HEAD(&ar->arvifs);
 
@@ -1084,6 +1147,7 @@ void ath10k_core_unregister(struct ath10k *ar)
 EXPORT_SYMBOL(ath10k_core_unregister);
 
 struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
+                                 enum ath10k_bus bus,
                                  const struct ath10k_hif_ops *hif_ops)
 {
        struct ath10k *ar;
@@ -1100,6 +1164,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
        ar->dev = dev;
 
        ar->hif.ops = hif_ops;
+       ar->hif.bus = bus;
 
        init_completion(&ar->scan.started);
        init_completion(&ar->scan.completed);
index fe531ea6926cce4fc2076dd132455440cb647454..4ca6dc94dd05870678958fafeeeae6d981144745 100644 (file)
 
 struct ath10k;
 
+enum ath10k_bus {
+       ATH10K_BUS_PCI,
+};
+
+static inline const char *ath10k_bus_str(enum ath10k_bus bus)
+{
+       switch (bus) {
+       case ATH10K_BUS_PCI:
+               return "pci";
+       }
+
+       return "unknown";
+}
+
 struct ath10k_skb_cb {
        dma_addr_t paddr;
        u8 vdev_id;
@@ -96,8 +110,6 @@ struct ath10k_bmi {
        bool done_sent;
 };
 
-#define ATH10K_MAX_MEM_REQS 16
-
 struct ath10k_mem_chunk {
        void *vaddr;
        dma_addr_t paddr;
@@ -115,17 +127,21 @@ struct ath10k_wmi {
        struct wmi_pdev_param_map *pdev_param;
 
        u32 num_mem_chunks;
-       struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS];
+       struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
 };
 
-struct ath10k_peer_stat {
+struct ath10k_fw_stats_peer {
+       struct list_head list;
+
        u8 peer_macaddr[ETH_ALEN];
        u32 peer_rssi;
        u32 peer_tx_rate;
        u32 peer_rx_rate; /* 10x only */
 };
 
-struct ath10k_target_stats {
+struct ath10k_fw_stats_pdev {
+       struct list_head list;
+
        /* PDEV stats */
        s32 ch_noise_floor;
        u32 tx_frame_count;
@@ -180,15 +196,11 @@ struct ath10k_target_stats {
        s32 phy_errs;
        s32 phy_err_drop;
        s32 mpdu_errs;
+};
 
-       /* VDEV STATS */
-
-       /* PEER STATS */
-       u8 peers;
-       struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS];
-
-       /* TODO: Beacon filter stats */
-
+struct ath10k_fw_stats {
+       struct list_head pdevs;
+       struct list_head peers;
 };
 
 struct ath10k_dfs_stats {
@@ -234,6 +246,8 @@ struct ath10k_vif {
        struct sk_buff *beacon;
        /* protected by data_lock */
        bool beacon_sent;
+       void *beacon_buf;
+       dma_addr_t beacon_paddr;
 
        struct ath10k *ar;
        struct ieee80211_vif *vif;
@@ -273,6 +287,7 @@ struct ath10k_vif {
        u8 force_sgi;
        bool use_cts_prot;
        int num_legacy_stations;
+       int txpower;
 };
 
 struct ath10k_vif_iter {
@@ -292,17 +307,19 @@ struct ath10k_fw_crash_data {
 struct ath10k_debug {
        struct dentry *debugfs_phy;
 
-       struct ath10k_target_stats target_stats;
+       struct ath10k_fw_stats fw_stats;
+       struct completion fw_stats_complete;
+       bool fw_stats_done;
        DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX);
 
-       struct completion event_stats_compl;
-
        unsigned long htt_stats_mask;
        struct delayed_work htt_stats_dwork;
        struct ath10k_dfs_stats dfs_stats;
        struct ath_dfs_pool_stats dfs_pool_stats;
 
+       /* protected by conf_mutex */
        u32 fw_dbglog_mask;
+       u32 pktlog_filter;
 
        u8 htt_max_amsdu;
        u8 htt_max_ampdu;
@@ -321,7 +338,7 @@ enum ath10k_state {
         * stopped in ath10k_core_restart() work holding conf_mutex. The state
         * RESTARTED means that the device is up and mac80211 has started hw
         * reconfiguration. Once mac80211 is done with the reconfiguration we
-        * set the state to STATE_ON in restart_complete(). */
+        * set the state to STATE_ON in reconfig_complete(). */
        ATH10K_STATE_RESTARTING,
        ATH10K_STATE_RESTARTED,
 
@@ -371,6 +388,23 @@ enum ath10k_dev_flags {
        ATH10K_FLAG_CORE_REGISTERED,
 };
 
+enum ath10k_cal_mode {
+       ATH10K_CAL_MODE_FILE,
+       ATH10K_CAL_MODE_OTP,
+};
+
+static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
+{
+       switch (mode) {
+       case ATH10K_CAL_MODE_FILE:
+               return "file";
+       case ATH10K_CAL_MODE_OTP:
+               return "otp";
+       }
+
+       return "unknown";
+}
+
 enum ath10k_scan_state {
        ATH10K_SCAN_IDLE,
        ATH10K_SCAN_STARTING,
@@ -421,6 +455,7 @@ struct ath10k {
        bool p2p;
 
        struct {
+               enum ath10k_bus bus;
                const struct ath10k_hif_ops *ops;
        } hif;
 
@@ -456,7 +491,10 @@ struct ath10k {
        const void *firmware_data;
        size_t firmware_len;
 
+       const struct firmware *cal_file;
+
        int fw_api;
+       enum ath10k_cal_mode cal_mode;
 
        struct {
                struct completion started;
@@ -482,7 +520,7 @@ struct ath10k {
        /* current operating channel definition */
        struct cfg80211_chan_def chandef;
 
-       int free_vdev_map;
+       unsigned long long free_vdev_map;
        bool monitor;
        int monitor_vdev_id;
        bool monitor_started;
@@ -563,11 +601,19 @@ struct ath10k {
                bool utf_monitor;
        } testmode;
 
+       struct {
+               /* protected by data_lock */
+               u32 fw_crash_counter;
+               u32 fw_warm_reset_counter;
+               u32 fw_cold_reset_counter;
+       } stats;
+
        /* must be last */
        u8 drv_priv[0] __aligned(sizeof(void *));
 };
 
 struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
+                                 enum ath10k_bus bus,
                                  const struct ath10k_hif_ops *hif_ops);
 void ath10k_core_destroy(struct ath10k *ar);
 
index 3756feba32231cffcddd112575163d1a7cf6cc67..9147dd36dcdd931de0a6ac6e38f016063751e5ae 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "core.h"
 #include "debug.h"
+#include "hif.h"
 
 /* ms */
 #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
@@ -106,34 +107,36 @@ struct ath10k_dump_file_data {
        u8 data[0];
 } __packed;
 
-int ath10k_info(struct ath10k *ar, const char *fmt, ...)
+void ath10k_info(struct ath10k *ar, const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
        };
        va_list args;
-       int ret;
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = dev_info(ar->dev, "%pV", &vaf);
+       dev_info(ar->dev, "%pV", &vaf);
        trace_ath10k_log_info(ar, &vaf);
        va_end(args);
-
-       return ret;
 }
 EXPORT_SYMBOL(ath10k_info);
 
 void ath10k_print_driver_info(struct ath10k *ar)
 {
-       ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n",
+       ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n",
                    ar->hw_params.name,
                    ar->target_version,
                    ar->chip_id,
                    ar->hw->wiphy->fw_version,
                    ar->fw_api,
                    ar->htt.target_version_major,
-                   ar->htt.target_version_minor);
+                   ar->htt.target_version_minor,
+                   ar->fw_version_major,
+                   ar->fw_version_minor,
+                   ar->fw_version_release,
+                   ar->fw_version_build,
+                   ath10k_cal_mode_str(ar->cal_mode));
        ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
                    config_enabled(CONFIG_ATH10K_DEBUG),
                    config_enabled(CONFIG_ATH10K_DEBUGFS),
@@ -143,25 +146,22 @@ void ath10k_print_driver_info(struct ath10k *ar)
 }
 EXPORT_SYMBOL(ath10k_print_driver_info);
 
-int ath10k_err(struct ath10k *ar, const char *fmt, ...)
+void ath10k_err(struct ath10k *ar, const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
        };
        va_list args;
-       int ret;
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = dev_err(ar->dev, "%pV", &vaf);
+       dev_err(ar->dev, "%pV", &vaf);
        trace_ath10k_log_err(ar, &vaf);
        va_end(args);
-
-       return ret;
 }
 EXPORT_SYMBOL(ath10k_err);
 
-int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
+void ath10k_warn(struct ath10k *ar, const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
@@ -174,15 +174,13 @@ int ath10k_warn(struct ath10k *ar, const char *fmt, ...)
        trace_ath10k_log_warn(ar, &vaf);
 
        va_end(args);
-
-       return 0;
 }
 EXPORT_SYMBOL(ath10k_warn);
 
 #ifdef CONFIG_ATH10K_DEBUGFS
 
 void ath10k_debug_read_service_map(struct ath10k *ar,
-                                  void *service_map,
+                                  const void *service_map,
                                   size_t map_size)
 {
        memcpy(ar->debug.wmi_service_bitmap, service_map, map_size);
@@ -242,169 +240,182 @@ static const struct file_operations fops_wmi_services = {
        .llseek = default_llseek,
 };
 
-void ath10k_debug_read_target_stats(struct ath10k *ar,
-                                   struct wmi_stats_event *ev)
+static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
 {
-       u8 *tmp = ev->data;
-       struct ath10k_target_stats *stats;
-       int num_pdev_stats, num_vdev_stats, num_peer_stats;
-       struct wmi_pdev_stats_10x *ps;
-       int i;
+       struct ath10k_fw_stats_pdev *i, *tmp;
+
+       list_for_each_entry_safe(i, tmp, head, list) {
+               list_del(&i->list);
+               kfree(i);
+       }
+}
+
+static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
+{
+       struct ath10k_fw_stats_peer *i, *tmp;
+
+       list_for_each_entry_safe(i, tmp, head, list) {
+               list_del(&i->list);
+               kfree(i);
+       }
+}
 
+static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
+{
        spin_lock_bh(&ar->data_lock);
+       ar->debug.fw_stats_done = false;
+       ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
+       ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
+       spin_unlock_bh(&ar->data_lock);
+}
 
-       stats = &ar->debug.target_stats;
-
-       num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */
-       num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */
-       num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */
-
-       if (num_pdev_stats) {
-               ps = (struct wmi_pdev_stats_10x *)tmp;
-
-               stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf);
-               stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count);
-               stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count);
-               stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count);
-               stats->cycle_count = __le32_to_cpu(ps->cycle_count);
-               stats->phy_err_count = __le32_to_cpu(ps->phy_err_count);
-               stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr);
-
-               stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued);
-               stats->comp_delivered =
-                       __le32_to_cpu(ps->wal.tx.comp_delivered);
-               stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued);
-               stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued);
-               stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop);
-               stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued);
-               stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed);
-               stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued);
-               stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped);
-               stats->underrun = __le32_to_cpu(ps->wal.tx.underrun);
-               stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort);
-               stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed);
-               stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko);
-               stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc);
-               stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers);
-               stats->sw_retry_failure =
-                       __le32_to_cpu(ps->wal.tx.sw_retry_failure);
-               stats->illgl_rate_phy_err =
-                       __le32_to_cpu(ps->wal.tx.illgl_rate_phy_err);
-               stats->pdev_cont_xretry =
-                       __le32_to_cpu(ps->wal.tx.pdev_cont_xretry);
-               stats->pdev_tx_timeout =
-                       __le32_to_cpu(ps->wal.tx.pdev_tx_timeout);
-               stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets);
-               stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun);
-               stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf);
-
-               stats->mid_ppdu_route_change =
-                       __le32_to_cpu(ps->wal.rx.mid_ppdu_route_change);
-               stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd);
-               stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags);
-               stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags);
-               stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags);
-               stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags);
-               stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus);
-               stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus);
-               stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus);
-               stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus);
-               stats->oversize_amsdu =
-                       __le32_to_cpu(ps->wal.rx.oversize_amsdu);
-               stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs);
-               stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop);
-               stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs);
-
-               if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
-                            ar->fw_features)) {
-                       stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad);
-                       stats->rts_bad = __le32_to_cpu(ps->rts_bad);
-                       stats->rts_good = __le32_to_cpu(ps->rts_good);
-                       stats->fcs_bad = __le32_to_cpu(ps->fcs_bad);
-                       stats->no_beacons = __le32_to_cpu(ps->no_beacons);
-                       stats->mib_int_count = __le32_to_cpu(ps->mib_int_count);
-                       tmp += sizeof(struct wmi_pdev_stats_10x);
-               } else {
-                       tmp += sizeof(struct wmi_pdev_stats_old);
-               }
+static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head)
+{
+       struct ath10k_fw_stats_peer *i;
+       size_t num = 0;
+
+       list_for_each_entry(i, head, list)
+               ++num;
+
+       return num;
+}
+
+void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
+{
+       struct ath10k_fw_stats stats = {};
+       bool is_start, is_started, is_end;
+       size_t num_peers;
+       int ret;
+
+       INIT_LIST_HEAD(&stats.pdevs);
+       INIT_LIST_HEAD(&stats.peers);
+
+       spin_lock_bh(&ar->data_lock);
+       ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
+       if (ret) {
+               ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);
+               goto unlock;
        }
 
-       /* 0 or max vdevs */
-       /* Currently firmware does not support VDEV stats */
-       if (num_vdev_stats) {
-               struct wmi_vdev_stats *vdev_stats;
+       /* Stat data may exceed htc-wmi buffer limit. In such case firmware
+        * splits the stats data and delivers it in a ping-pong fashion of
+        * request cmd-update event.
+        *
+        * However there is no explicit end-of-data. Instead start-of-data is
+        * used as an implicit one. This works as follows:
+        *  a) discard stat update events until one with pdev stats is
+        *     delivered - this skips session started at end of (b)
+        *  b) consume stat update events until another one with pdev stats is
+        *     delivered which is treated as end-of-data and is itself discarded
+        */
 
-               for (i = 0; i < num_vdev_stats; i++) {
-                       vdev_stats = (struct wmi_vdev_stats *)tmp;
-                       tmp += sizeof(struct wmi_vdev_stats);
-               }
+       if (ar->debug.fw_stats_done) {
+               ath10k_warn(ar, "received unsolicited stats update event\n");
+               goto free;
        }
 
-       if (num_peer_stats) {
-               struct wmi_peer_stats_10x *peer_stats;
-               struct ath10k_peer_stat *s;
-
-               stats->peers = num_peer_stats;
-
-               for (i = 0; i < num_peer_stats; i++) {
-                       peer_stats = (struct wmi_peer_stats_10x *)tmp;
-                       s = &stats->peer_stat[i];
-
-                       memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr,
-                              ETH_ALEN);
-                       s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi);
-                       s->peer_tx_rate =
-                               __le32_to_cpu(peer_stats->peer_tx_rate);
-                       if (test_bit(ATH10K_FW_FEATURE_WMI_10X,
-                                    ar->fw_features)) {
-                               s->peer_rx_rate =
-                                       __le32_to_cpu(peer_stats->peer_rx_rate);
-                               tmp += sizeof(struct wmi_peer_stats_10x);
-
-                       } else {
-                               tmp += sizeof(struct wmi_peer_stats_old);
-                       }
+       num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers);
+       is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
+                   !list_empty(&stats.pdevs));
+       is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
+                 !list_empty(&stats.pdevs));
+
+       if (is_start)
+               list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
+
+       if (is_end)
+               ar->debug.fw_stats_done = true;
+
+       is_started = !list_empty(&ar->debug.fw_stats.pdevs);
+
+       if (is_started && !is_end) {
+               if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) {
+                       /* Although this is unlikely impose a sane limit to
+                        * prevent firmware from DoS-ing the host.
+                        */
+                       ath10k_warn(ar, "dropping fw peer stats\n");
+                       goto free;
                }
+
+               list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
        }
 
+       complete(&ar->debug.fw_stats_complete);
+
+free:
+       /* In some cases lists have been spliced and cleared. Free up
+        * resources if that is not the case.
+        */
+       ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
+       ath10k_debug_fw_stats_peers_free(&stats.peers);
+
+unlock:
        spin_unlock_bh(&ar->data_lock);
-       complete(&ar->debug.event_stats_compl);
 }
 
-static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
-                                   size_t count, loff_t *ppos)
+static int ath10k_debug_fw_stats_request(struct ath10k *ar)
 {
-       struct ath10k *ar = file->private_data;
-       struct ath10k_target_stats *fw_stats;
-       char *buf = NULL;
-       unsigned int len = 0, buf_len = 8000;
-       ssize_t ret_cnt = 0;
-       long left;
-       int i;
+       unsigned long timeout;
        int ret;
 
-       fw_stats = &ar->debug.target_stats;
+       lockdep_assert_held(&ar->conf_mutex);
 
-       mutex_lock(&ar->conf_mutex);
+       timeout = jiffies + msecs_to_jiffies(1*HZ);
 
-       if (ar->state != ATH10K_STATE_ON)
-               goto exit;
+       ath10k_debug_fw_stats_reset(ar);
 
-       buf = kzalloc(buf_len, GFP_KERNEL);
-       if (!buf)
-               goto exit;
+       for (;;) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
 
-       ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
-       if (ret) {
-               ath10k_warn(ar, "could not request stats (%d)\n", ret);
-               goto exit;
+               reinit_completion(&ar->debug.fw_stats_complete);
+
+               ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT);
+               if (ret) {
+                       ath10k_warn(ar, "could not request stats (%d)\n", ret);
+                       return ret;
+               }
+
+               ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+                                                 1*HZ);
+               if (ret <= 0)
+                       return -ETIMEDOUT;
+
+               spin_lock_bh(&ar->data_lock);
+               if (ar->debug.fw_stats_done) {
+                       spin_unlock_bh(&ar->data_lock);
+                       break;
+               }
+               spin_unlock_bh(&ar->data_lock);
        }
 
-       left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ);
-       if (left <= 0)
-               goto exit;
+       return 0;
+}
+
+/* FIXME: How to calculate the buffer size sanely? */
+#define ATH10K_FW_STATS_BUF_SIZE (1024*1024)
+
+static void ath10k_fw_stats_fill(struct ath10k *ar,
+                                struct ath10k_fw_stats *fw_stats,
+                                char *buf)
+{
+       unsigned int len = 0;
+       unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
+       const struct ath10k_fw_stats_pdev *pdev;
+       const struct ath10k_fw_stats_peer *peer;
+       size_t num_peers;
 
        spin_lock_bh(&ar->data_lock);
+
+       pdev = list_first_entry_or_null(&fw_stats->pdevs,
+                                       struct ath10k_fw_stats_pdev, list);
+       if (!pdev) {
+               ath10k_warn(ar, "failed to get pdev stats\n");
+               goto unlock;
+       }
+
+       num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers);
+
        len += scnprintf(buf + len, buf_len - len, "\n");
        len += scnprintf(buf + len, buf_len - len, "%30s\n",
                         "ath10k PDEV stats");
@@ -412,29 +423,29 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
                                 "=================");
 
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Channel noise floor", fw_stats->ch_noise_floor);
+                        "Channel noise floor", pdev->ch_noise_floor);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "Channel TX power", fw_stats->chan_tx_power);
+                        "Channel TX power", pdev->chan_tx_power);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "TX frame count", fw_stats->tx_frame_count);
+                        "TX frame count", pdev->tx_frame_count);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "RX frame count", fw_stats->rx_frame_count);
+                        "RX frame count", pdev->rx_frame_count);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "RX clear count", fw_stats->rx_clear_count);
+                        "RX clear count", pdev->rx_clear_count);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "Cycle count", fw_stats->cycle_count);
+                        "Cycle count", pdev->cycle_count);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "PHY error count", fw_stats->phy_err_count);
+                        "PHY error count", pdev->phy_err_count);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "RTS bad count", fw_stats->rts_bad);
+                        "RTS bad count", pdev->rts_bad);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "RTS good count", fw_stats->rts_good);
+                        "RTS good count", pdev->rts_good);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "FCS bad count", fw_stats->fcs_bad);
+                        "FCS bad count", pdev->fcs_bad);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "No beacon count", fw_stats->no_beacons);
+                        "No beacon count", pdev->no_beacons);
        len += scnprintf(buf + len, buf_len - len, "%30s %10u\n",
-                        "MIB int count", fw_stats->mib_int_count);
+                        "MIB int count", pdev->mib_int_count);
 
        len += scnprintf(buf + len, buf_len - len, "\n");
        len += scnprintf(buf + len, buf_len - len, "%30s\n",
@@ -443,51 +454,51 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
                                 "=================");
 
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "HTT cookies queued", fw_stats->comp_queued);
+                        "HTT cookies queued", pdev->comp_queued);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "HTT cookies disp.", fw_stats->comp_delivered);
+                        "HTT cookies disp.", pdev->comp_delivered);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MSDU queued", fw_stats->msdu_enqued);
+                        "MSDU queued", pdev->msdu_enqued);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MPDU queued", fw_stats->mpdu_enqued);
+                        "MPDU queued", pdev->mpdu_enqued);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MSDUs dropped", fw_stats->wmm_drop);
+                        "MSDUs dropped", pdev->wmm_drop);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Local enqued", fw_stats->local_enqued);
+                        "Local enqued", pdev->local_enqued);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Local freed", fw_stats->local_freed);
+                        "Local freed", pdev->local_freed);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "HW queued", fw_stats->hw_queued);
+                        "HW queued", pdev->hw_queued);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "PPDUs reaped", fw_stats->hw_reaped);
+                        "PPDUs reaped", pdev->hw_reaped);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Num underruns", fw_stats->underrun);
+                        "Num underruns", pdev->underrun);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "PPDUs cleaned", fw_stats->tx_abort);
+                        "PPDUs cleaned", pdev->tx_abort);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MPDUs requed", fw_stats->mpdus_requed);
+                        "MPDUs requed", pdev->mpdus_requed);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Excessive retries", fw_stats->tx_ko);
+                        "Excessive retries", pdev->tx_ko);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "HW rate", fw_stats->data_rc);
+                        "HW rate", pdev->data_rc);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Sched self tiggers", fw_stats->self_triggers);
+                        "Sched self tiggers", pdev->self_triggers);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
                         "Dropped due to SW retries",
-                        fw_stats->sw_retry_failure);
+                        pdev->sw_retry_failure);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
                         "Illegal rate phy errors",
-                        fw_stats->illgl_rate_phy_err);
+                        pdev->illgl_rate_phy_err);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Pdev continous xretry", fw_stats->pdev_cont_xretry);
+                        "Pdev continous xretry", pdev->pdev_cont_xretry);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "TX timeout", fw_stats->pdev_tx_timeout);
+                        "TX timeout", pdev->pdev_tx_timeout);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "PDEV resets", fw_stats->pdev_resets);
+                        "PDEV resets", pdev->pdev_resets);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "PHY underrun", fw_stats->phy_underrun);
+                        "PHY underrun", pdev->phy_underrun);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MPDU is more than txop limit", fw_stats->txop_ovf);
+                        "MPDU is more than txop limit", pdev->txop_ovf);
 
        len += scnprintf(buf + len, buf_len - len, "\n");
        len += scnprintf(buf + len, buf_len - len, "%30s\n",
@@ -497,70 +508,161 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf,
 
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
                         "Mid PPDU route change",
-                        fw_stats->mid_ppdu_route_change);
+                        pdev->mid_ppdu_route_change);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Tot. number of statuses", fw_stats->status_rcvd);
+                        "Tot. number of statuses", pdev->status_rcvd);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Extra frags on rings 0", fw_stats->r0_frags);
+                        "Extra frags on rings 0", pdev->r0_frags);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Extra frags on rings 1", fw_stats->r1_frags);
+                        "Extra frags on rings 1", pdev->r1_frags);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Extra frags on rings 2", fw_stats->r2_frags);
+                        "Extra frags on rings 2", pdev->r2_frags);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Extra frags on rings 3", fw_stats->r3_frags);
+                        "Extra frags on rings 3", pdev->r3_frags);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MSDUs delivered to HTT", fw_stats->htt_msdus);
+                        "MSDUs delivered to HTT", pdev->htt_msdus);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MPDUs delivered to HTT", fw_stats->htt_mpdus);
+                        "MPDUs delivered to HTT", pdev->htt_mpdus);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MSDUs delivered to stack", fw_stats->loc_msdus);
+                        "MSDUs delivered to stack", pdev->loc_msdus);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MPDUs delivered to stack", fw_stats->loc_mpdus);
+                        "MPDUs delivered to stack", pdev->loc_mpdus);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "Oversized AMSUs", fw_stats->oversize_amsdu);
+                        "Oversized AMSUs", pdev->oversize_amsdu);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "PHY errors", fw_stats->phy_errs);
+                        "PHY errors", pdev->phy_errs);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "PHY errors drops", fw_stats->phy_err_drop);
+                        "PHY errors drops", pdev->phy_err_drop);
        len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
-                        "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs);
+                        "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
 
        len += scnprintf(buf + len, buf_len - len, "\n");
-       len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n",
-                        "ath10k PEER stats", fw_stats->peers);
+       len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
+                        "ath10k PEER stats", num_peers);
        len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
                                 "=================");
 
-       for (i = 0; i < fw_stats->peers; i++) {
+       list_for_each_entry(peer, &fw_stats->peers, list) {
                len += scnprintf(buf + len, buf_len - len, "%30s %pM\n",
-                                "Peer MAC address",
-                                fw_stats->peer_stat[i].peer_macaddr);
+                                "Peer MAC address", peer->peer_macaddr);
                len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
-                                "Peer RSSI", fw_stats->peer_stat[i].peer_rssi);
+                                "Peer RSSI", peer->peer_rssi);
                len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
-                                "Peer TX rate",
-                                fw_stats->peer_stat[i].peer_tx_rate);
+                                "Peer TX rate", peer->peer_tx_rate);
                len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
-                                "Peer RX rate",
-                                fw_stats->peer_stat[i].peer_rx_rate);
+                                "Peer RX rate", peer->peer_rx_rate);
                len += scnprintf(buf + len, buf_len - len, "\n");
        }
+
+unlock:
        spin_unlock_bh(&ar->data_lock);
 
-       if (len > buf_len)
-               len = buf_len;
+       if (len >= buf_len)
+               buf[len - 1] = 0;
+       else
+               buf[len] = 0;
+}
 
-       ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+static int ath10k_fw_stats_open(struct inode *inode, struct file *file)
+{
+       struct ath10k *ar = inode->i_private;
+       void *buf = NULL;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH10K_STATE_ON) {
+               ret = -ENETDOWN;
+               goto err_unlock;
+       }
+
+       buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err_unlock;
+       }
+
+       ret = ath10k_debug_fw_stats_request(ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to request fw stats: %d\n", ret);
+               goto err_free;
+       }
+
+       ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf);
+       file->private_data = buf;
 
-exit:
        mutex_unlock(&ar->conf_mutex);
-       kfree(buf);
-       return ret_cnt;
+       return 0;
+
+err_free:
+       vfree(buf);
+
+err_unlock:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       const char *buf = file->private_data;
+       unsigned int len = strlen(buf);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
 static const struct file_operations fops_fw_stats = {
-       .read = ath10k_read_fw_stats,
+       .open = ath10k_fw_stats_open,
+       .release = ath10k_fw_stats_release,
+       .read = ath10k_fw_stats_read,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       int ret, len, buf_len;
+       char *buf;
+
+       buf_len = 500;
+       buf = kmalloc(buf_len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       spin_lock_bh(&ar->data_lock);
+
+       len = 0;
+       len += scnprintf(buf + len, buf_len - len,
+                        "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);
+       len += scnprintf(buf + len, buf_len - len,
+                        "fw_warm_reset_counter\t\t%d\n",
+                        ar->stats.fw_warm_reset_counter);
+       len += scnprintf(buf + len, buf_len - len,
+                        "fw_cold_reset_counter\t\t%d\n",
+                        ar->stats.fw_cold_reset_counter);
+
+       spin_unlock_bh(&ar->data_lock);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+       kfree(buf);
+
+       return ret;
+}
+
+static const struct file_operations fops_fw_reset_stats = {
        .open = simple_open,
+       .read = ath10k_debug_fw_reset_stats_read,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
 };
@@ -1029,6 +1131,166 @@ exit:
        return ret;
 }
 
+/* TODO:  Would be nice to always support ethtool stats, would need to
+ * move the stats storage out of ath10k_debug, or always have ath10k_debug
+ * struct available..
+ */
+
+/* This generally cooresponds to the debugfs fw_stats file */
+static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
+       "tx_pkts_nic",
+       "tx_bytes_nic",
+       "rx_pkts_nic",
+       "rx_bytes_nic",
+       "d_noise_floor",
+       "d_cycle_count",
+       "d_phy_error",
+       "d_rts_bad",
+       "d_rts_good",
+       "d_tx_power", /* in .5 dbM I think */
+       "d_rx_crc_err", /* fcs_bad */
+       "d_no_beacon",
+       "d_tx_mpdus_queued",
+       "d_tx_msdu_queued",
+       "d_tx_msdu_dropped",
+       "d_local_enqued",
+       "d_local_freed",
+       "d_tx_ppdu_hw_queued",
+       "d_tx_ppdu_reaped",
+       "d_tx_fifo_underrun",
+       "d_tx_ppdu_abort",
+       "d_tx_mpdu_requed",
+       "d_tx_excessive_retries",
+       "d_tx_hw_rate",
+       "d_tx_dropped_sw_retries",
+       "d_tx_illegal_rate",
+       "d_tx_continuous_xretries",
+       "d_tx_timeout",
+       "d_tx_mpdu_txop_limit",
+       "d_pdev_resets",
+       "d_rx_mid_ppdu_route_change",
+       "d_rx_status",
+       "d_rx_extra_frags_ring0",
+       "d_rx_extra_frags_ring1",
+       "d_rx_extra_frags_ring2",
+       "d_rx_extra_frags_ring3",
+       "d_rx_msdu_htt",
+       "d_rx_mpdu_htt",
+       "d_rx_msdu_stack",
+       "d_rx_mpdu_stack",
+       "d_rx_phy_err",
+       "d_rx_phy_err_drops",
+       "d_rx_mpdu_errors", /* FCS, MIC, ENC */
+       "d_fw_crash_count",
+       "d_fw_warm_reset_count",
+       "d_fw_cold_reset_count",
+};
+
+#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
+
+void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                u32 sset, u8 *data)
+{
+       if (sset == ETH_SS_STATS)
+               memcpy(data, *ath10k_gstrings_stats,
+                      sizeof(ath10k_gstrings_stats));
+}
+
+int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif, int sset)
+{
+       if (sset == ETH_SS_STATS)
+               return ATH10K_SSTATS_LEN;
+
+       return 0;
+}
+
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ethtool_stats *stats, u64 *data)
+{
+       struct ath10k *ar = hw->priv;
+       static const struct ath10k_fw_stats_pdev zero_stats = {};
+       const struct ath10k_fw_stats_pdev *pdev_stats;
+       int i = 0, ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state == ATH10K_STATE_ON) {
+               ret = ath10k_debug_fw_stats_request(ar);
+               if (ret) {
+                       /* just print a warning and try to use older results */
+                       ath10k_warn(ar,
+                                   "failed to get fw stats for ethtool: %d\n",
+                                   ret);
+               }
+       }
+
+       pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs,
+                                             struct ath10k_fw_stats_pdev,
+                                             list);
+       if (!pdev_stats) {
+               /* no results available so just return zeroes */
+               pdev_stats = &zero_stats;
+       }
+
+       spin_lock_bh(&ar->data_lock);
+
+       data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
+       data[i++] = 0; /* tx bytes */
+       data[i++] = pdev_stats->htt_mpdus;
+       data[i++] = 0; /* rx bytes */
+       data[i++] = pdev_stats->ch_noise_floor;
+       data[i++] = pdev_stats->cycle_count;
+       data[i++] = pdev_stats->phy_err_count;
+       data[i++] = pdev_stats->rts_bad;
+       data[i++] = pdev_stats->rts_good;
+       data[i++] = pdev_stats->chan_tx_power;
+       data[i++] = pdev_stats->fcs_bad;
+       data[i++] = pdev_stats->no_beacons;
+       data[i++] = pdev_stats->mpdu_enqued;
+       data[i++] = pdev_stats->msdu_enqued;
+       data[i++] = pdev_stats->wmm_drop;
+       data[i++] = pdev_stats->local_enqued;
+       data[i++] = pdev_stats->local_freed;
+       data[i++] = pdev_stats->hw_queued;
+       data[i++] = pdev_stats->hw_reaped;
+       data[i++] = pdev_stats->underrun;
+       data[i++] = pdev_stats->tx_abort;
+       data[i++] = pdev_stats->mpdus_requed;
+       data[i++] = pdev_stats->tx_ko;
+       data[i++] = pdev_stats->data_rc;
+       data[i++] = pdev_stats->sw_retry_failure;
+       data[i++] = pdev_stats->illgl_rate_phy_err;
+       data[i++] = pdev_stats->pdev_cont_xretry;
+       data[i++] = pdev_stats->pdev_tx_timeout;
+       data[i++] = pdev_stats->txop_ovf;
+       data[i++] = pdev_stats->pdev_resets;
+       data[i++] = pdev_stats->mid_ppdu_route_change;
+       data[i++] = pdev_stats->status_rcvd;
+       data[i++] = pdev_stats->r0_frags;
+       data[i++] = pdev_stats->r1_frags;
+       data[i++] = pdev_stats->r2_frags;
+       data[i++] = pdev_stats->r3_frags;
+       data[i++] = pdev_stats->htt_msdus;
+       data[i++] = pdev_stats->htt_mpdus;
+       data[i++] = pdev_stats->loc_msdus;
+       data[i++] = pdev_stats->loc_mpdus;
+       data[i++] = pdev_stats->phy_errs;
+       data[i++] = pdev_stats->phy_err_drop;
+       data[i++] = pdev_stats->mpdu_errs;
+       data[i++] = ar->stats.fw_crash_counter;
+       data[i++] = ar->stats.fw_warm_reset_counter;
+       data[i++] = ar->stats.fw_cold_reset_counter;
+
+       spin_unlock_bh(&ar->data_lock);
+
+       mutex_unlock(&ar->conf_mutex);
+
+       WARN_ON(i != ATH10K_SSTATS_LEN);
+}
+
 static const struct file_operations fops_fw_dbglog = {
        .read = ath10k_read_fw_dbglog,
        .write = ath10k_write_fw_dbglog,
@@ -1037,6 +1299,84 @@ static const struct file_operations fops_fw_dbglog = {
        .llseek = default_llseek,
 };
 
+static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file)
+{
+       struct ath10k *ar = inode->i_private;
+       void *buf;
+       u32 hi_addr;
+       __le32 addr;
+       int ret;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH10K_STATE_ON &&
+           ar->state != ATH10K_STATE_UTF) {
+               ret = -ENETDOWN;
+               goto err;
+       }
+
+       buf = vmalloc(QCA988X_CAL_DATA_LEN);
+       if (!buf) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       hi_addr = host_interest_item_address(HI_ITEM(hi_board_data));
+
+       ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr));
+       if (ret) {
+               ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret);
+               goto err_vfree;
+       }
+
+       ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf,
+                                  QCA988X_CAL_DATA_LEN);
+       if (ret) {
+               ath10k_warn(ar, "failed to read calibration data: %d\n", ret);
+               goto err_vfree;
+       }
+
+       file->private_data = buf;
+
+       mutex_unlock(&ar->conf_mutex);
+
+       return 0;
+
+err_vfree:
+       vfree(buf);
+
+err:
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static ssize_t ath10k_debug_cal_data_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       void *buf = file->private_data;
+
+       return simple_read_from_buffer(user_buf, count, ppos,
+                                      buf, QCA988X_CAL_DATA_LEN);
+}
+
+static int ath10k_debug_cal_data_release(struct inode *inode,
+                                        struct file *file)
+{
+       vfree(file->private_data);
+
+       return 0;
+}
+
+static const struct file_operations fops_cal_data = {
+       .open = ath10k_debug_cal_data_open,
+       .read = ath10k_debug_cal_data_read,
+       .release = ath10k_debug_cal_data_release,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
 int ath10k_debug_start(struct ath10k *ar)
 {
        int ret;
@@ -1057,7 +1397,22 @@ int ath10k_debug_start(struct ath10k *ar)
                                    ret);
        }
 
-       return 0;
+       if (ar->debug.pktlog_filter) {
+               ret = ath10k_wmi_pdev_pktlog_enable(ar,
+                                                   ar->debug.pktlog_filter);
+               if (ret)
+                       /* not serious */
+                       ath10k_warn(ar,
+                                   "failed to enable pktlog filter %x: %d\n",
+                                   ar->debug.pktlog_filter, ret);
+       } else {
+               ret = ath10k_wmi_pdev_pktlog_disable(ar);
+               if (ret)
+                       /* not serious */
+                       ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
+       }
+
+       return ret;
 }
 
 void ath10k_debug_stop(struct ath10k *ar)
@@ -1072,6 +1427,8 @@ void ath10k_debug_stop(struct ath10k *ar)
 
        ar->debug.htt_max_amsdu = 0;
        ar->debug.htt_max_ampdu = 0;
+
+       ath10k_wmi_pdev_pktlog_disable(ar);
 }
 
 static ssize_t ath10k_write_simulate_radar(struct file *file,
@@ -1154,12 +1511,78 @@ static const struct file_operations fops_dfs_stats = {
        .llseek = default_llseek,
 };
 
+static ssize_t ath10k_write_pktlog_filter(struct file *file,
+                                         const char __user *ubuf,
+                                         size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       u32 filter;
+       int ret;
+
+       if (kstrtouint_from_user(ubuf, count, 0, &filter))
+               return -EINVAL;
+
+       mutex_lock(&ar->conf_mutex);
+
+       if (ar->state != ATH10K_STATE_ON) {
+               ar->debug.pktlog_filter = filter;
+               ret = count;
+               goto out;
+       }
+
+       if (filter && (filter != ar->debug.pktlog_filter)) {
+               ret = ath10k_wmi_pdev_pktlog_enable(ar, filter);
+               if (ret) {
+                       ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n",
+                                   ar->debug.pktlog_filter, ret);
+                       goto out;
+               }
+       } else {
+               ret = ath10k_wmi_pdev_pktlog_disable(ar);
+               if (ret) {
+                       ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
+                       goto out;
+               }
+       }
+
+       ar->debug.pktlog_filter = filter;
+       ret = count;
+
+out:
+       mutex_unlock(&ar->conf_mutex);
+       return ret;
+}
+
+static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf,
+                                        size_t count, loff_t *ppos)
+{
+       char buf[32];
+       struct ath10k *ar = file->private_data;
+       int len = 0;
+
+       mutex_lock(&ar->conf_mutex);
+       len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
+                       ar->debug.pktlog_filter);
+       mutex_unlock(&ar->conf_mutex);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pktlog_filter = {
+       .read = ath10k_read_pktlog_filter,
+       .write = ath10k_write_pktlog_filter,
+       .open = simple_open
+};
+
 int ath10k_debug_create(struct ath10k *ar)
 {
        ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data));
        if (!ar->debug.fw_crash_data)
                return -ENOMEM;
 
+       INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
+       INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
+
        return 0;
 }
 
@@ -1167,6 +1590,8 @@ void ath10k_debug_destroy(struct ath10k *ar)
 {
        vfree(ar->debug.fw_crash_data);
        ar->debug.fw_crash_data = NULL;
+
+       ath10k_debug_fw_stats_reset(ar);
 }
 
 int ath10k_debug_register(struct ath10k *ar)
@@ -1183,11 +1608,14 @@ int ath10k_debug_register(struct ath10k *ar)
        INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
                          ath10k_debug_htt_stats_dwork);
 
-       init_completion(&ar->debug.event_stats_compl);
+       init_completion(&ar->debug.fw_stats_complete);
 
        debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
                            &fops_fw_stats);
 
+       debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy,
+                           ar, &fops_fw_reset_stats);
+
        debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
                            &fops_wmi_services);
 
@@ -1210,6 +1638,9 @@ int ath10k_debug_register(struct ath10k *ar)
        debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
                            ar, &fops_fw_dbglog);
 
+       debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
+                           ar, &fops_cal_data);
+
        if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
                debugfs_create_file("dfs_simulate_radar", S_IWUSR,
                                    ar->debug.debugfs_phy, ar,
@@ -1224,6 +1655,9 @@ int ath10k_debug_register(struct ath10k *ar)
                                    &fops_dfs_stats);
        }
 
+       debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR,
+                           ar->debug.debugfs_phy, ar, &fops_pktlog_filter);
+
        return 0;
 }
 
@@ -1260,11 +1694,26 @@ void ath10k_dbg_dump(struct ath10k *ar,
                     const char *msg, const char *prefix,
                     const void *buf, size_t len)
 {
+       char linebuf[256];
+       unsigned int linebuflen;
+       const void *ptr;
+
        if (ath10k_debug_mask & mask) {
                if (msg)
                        ath10k_dbg(ar, mask, "%s\n", msg);
 
-               print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len);
+               for (ptr = buf; (ptr - buf) < len; ptr += 16) {
+                       linebuflen = 0;
+                       linebuflen += scnprintf(linebuf + linebuflen,
+                                               sizeof(linebuf) - linebuflen,
+                                               "%s%08x: ",
+                                               (prefix ? prefix : ""),
+                                               (unsigned int)(ptr - buf));
+                       hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1,
+                                          linebuf + linebuflen,
+                                          sizeof(linebuf) - linebuflen, true);
+                       dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf);
+               }
        }
 
        /* tracing code doesn't like null strings :/ */
index b3774f7f492c480d941a300a81b15a2c8a6cb234..0c934a8378dba315489df956626b284027f1a585 100644 (file)
@@ -38,11 +38,20 @@ enum ath10k_debug_mask {
        ATH10K_DBG_ANY          = 0xffffffff,
 };
 
+enum ath10k_pktlog_filter {
+       ATH10K_PKTLOG_RX         = 0x000000001,
+       ATH10K_PKTLOG_TX         = 0x000000002,
+       ATH10K_PKTLOG_RCFIND     = 0x000000004,
+       ATH10K_PKTLOG_RCUPDATE   = 0x000000008,
+       ATH10K_PKTLOG_DBG_PRINT  = 0x000000010,
+       ATH10K_PKTLOG_ANY        = 0x00000001f,
+};
+
 extern unsigned int ath10k_debug_mask;
 
-__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...);
-__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...);
-__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...);
+__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...);
 void ath10k_print_driver_info(struct ath10k *ar);
 
 #ifdef CONFIG_ATH10K_DEBUGFS
@@ -53,17 +62,24 @@ void ath10k_debug_destroy(struct ath10k *ar);
 int ath10k_debug_register(struct ath10k *ar);
 void ath10k_debug_unregister(struct ath10k *ar);
 void ath10k_debug_read_service_map(struct ath10k *ar,
-                                  void *service_map,
+                                  const void *service_map,
                                   size_t map_size);
-void ath10k_debug_read_target_stats(struct ath10k *ar,
-                                   struct wmi_stats_event *ev);
+void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
 struct ath10k_fw_crash_data *
 ath10k_debug_get_new_fw_crash_data(struct ath10k *ar);
 
 void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
-
 #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
 
+void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                u32 sset, u8 *data);
+int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif, int sset);
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ethtool_stats *stats, u64 *data);
+
 #else
 static inline int ath10k_debug_start(struct ath10k *ar)
 {
@@ -93,13 +109,13 @@ static inline void ath10k_debug_unregister(struct ath10k *ar)
 }
 
 static inline void ath10k_debug_read_service_map(struct ath10k *ar,
-                                                void *service_map,
+                                                const void *service_map,
                                                 size_t map_size)
 {
 }
 
-static inline void ath10k_debug_read_target_stats(struct ath10k *ar,
-                                                 struct wmi_stats_event *ev)
+static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
+                                                struct sk_buff *skb)
 {
 }
 
@@ -116,6 +132,10 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
 
 #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
 
+#define ath10k_debug_get_et_strings NULL
+#define ath10k_debug_get_et_sset_count NULL
+#define ath10k_debug_get_et_stats NULL
+
 #endif /* CONFIG_ATH10K_DEBUGFS */
 
 #ifdef CONFIG_ATH10K_DEBUG
index 62323fea27e136c9fdad3913dfcc36a712cd86ec..30301f5b60515303923d433a3a7cc1d8cf7c60c4 100644 (file)
@@ -43,6 +43,10 @@ struct ath10k_hif_ops {
        int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
                     struct ath10k_hif_sg_item *items, int n_items);
 
+       /* read firmware memory through the diagnose interface */
+       int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
+                        size_t buf_len);
+
        /*
         * API to handle HIF-specific BMI message exchanges, this API is
         * synchronous and only allowed to be called from a context that
@@ -98,6 +102,12 @@ static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
        return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
 }
 
+static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+                                      size_t buf_len)
+{
+       return ar->hif.ops->diag_read(ar, address, buf, buf_len);
+}
+
 static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
                                              void *request, u32 request_len,
                                              void *response, u32 *response_len)
index 3b44217a6c190b70749182037e051583983b6c48..15c58e884b6a3ed2a09f09cf318e9fd8f3bad1ce 100644 (file)
@@ -725,7 +725,7 @@ static inline u8 *htt_rx_test_get_chars(struct htt_rx_test *rx_test)
  */
 struct htt_pktlog_msg {
        u8 pad[3];
-       __le32 payload[1 /* or more */];
+       u8 payload[0];
 } __packed;
 
 struct htt_dbg_stats_rx_reorder_stats {
index 60d40a04508b1d8189f41dd88d417d76d68ac50a..fbb3175d4d6ecab613955435f33ba87098180905 100644 (file)
@@ -291,6 +291,9 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
        htt->rx_ring.sw_rd_idx.msdu_payld = idx;
        htt->rx_ring.fill_cnt--;
 
+       trace_ath10k_htt_rx_pop_msdu(ar, msdu->data, msdu->len +
+                                    skb_tailroom(msdu));
+
        return msdu;
 }
 
@@ -316,6 +319,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
        int msdu_len, msdu_chaining = 0;
        struct sk_buff *msdu, *next;
        struct htt_rx_desc *rx_desc;
+       u32 tsf;
 
        lockdep_assert_held(&htt->rx_ring.lock);
 
@@ -447,6 +451,9 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
                last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) &
                                RX_MSDU_END_INFO0_LAST_MSDU;
 
+               tsf = __le32_to_cpu(rx_desc->ppdu_end.tsf_timestamp);
+               trace_ath10k_htt_rx_desc(ar, tsf, &rx_desc->attention,
+                                        sizeof(*rx_desc) - sizeof(u32));
                if (last_msdu) {
                        msdu->next = NULL;
                        break;
@@ -1674,6 +1681,15 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
        case HTT_T2H_MSG_TYPE_RX_DELBA:
                ath10k_htt_rx_delba(ar, resp);
                break;
+       case HTT_T2H_MSG_TYPE_PKTLOG: {
+               struct ath10k_pktlog_hdr *hdr =
+                       (struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload;
+
+               trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload,
+                                       sizeof(*hdr) +
+                                       __le16_to_cpu(hdr->size));
+               break;
+       }
        case HTT_T2H_MSG_TYPE_RX_FLUSH: {
                /* Ignore this event because mac80211 takes care of Rx
                 * aggregation reordering.
@@ -1681,8 +1697,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                break;
        }
        default:
-               ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n",
-                          resp->hdr.msg_type);
+               ath10k_warn(ar, "htt event (%d) not handled\n",
+                           resp->hdr.msg_type);
                ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ",
                                skb->data, skb->len);
                break;
index bd87a35201d895856620719dc5477fbedb3d7062..b0df470250a2230c621d054c1bbb42ef0f44bfe7 100644 (file)
@@ -557,12 +557,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr);
        skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID);
 
+       trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
        ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n",
                   flags0, flags1, msdu->len, msdu_id, frags_paddr,
                   (u32)skb_cb->paddr, vdev_id, tid);
        ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
                        msdu->data, msdu->len);
+       trace_ath10k_htt_tx_msdu(ar, msdu->data, msdu->len);
 
        sg_items[0].transfer_id = 0;
        sg_items[0].transfer_context = NULL;
index 3cf5702c1e7ef7ee49fa2b6860b08854fc48b53b..392c2501d0a1d9c75a24af5297f73780f6e10a28 100644 (file)
 
 #include "targaddrs.h"
 
+#define ATH10K_FW_DIR                  "ath10k"
+
 /* QCA988X 1.0 definitions (unsupported) */
 #define QCA988X_HW_1_0_CHIP_ID_REV     0x0
 
 /* QCA988X 2.0 definitions */
 #define QCA988X_HW_2_0_VERSION         0x4100016c
 #define QCA988X_HW_2_0_CHIP_ID_REV     0x2
-#define QCA988X_HW_2_0_FW_DIR          "ath10k/QCA988X/hw2.0"
+#define QCA988X_HW_2_0_FW_DIR          ATH10K_FW_DIR "/QCA988X/hw2.0"
 #define QCA988X_HW_2_0_FW_FILE         "firmware.bin"
-#define QCA988X_HW_2_0_FW_3_FILE       "firmware-3.bin"
 #define QCA988X_HW_2_0_OTP_FILE                "otp.bin"
 #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
@@ -43,6 +44,8 @@
 
 #define REG_DUMP_COUNT_QCA988X 60
 
+#define QCA988X_CAL_DATA_LEN           2116
+
 struct ath10k_fw_ie {
        __le32 id;
        __le32 len;
@@ -78,6 +81,15 @@ enum ath10k_mcast2ucast_mode {
        ATH10K_MCAST2UCAST_ENABLED = 1,
 };
 
+struct ath10k_pktlog_hdr {
+       __le16 flags;
+       __le16 missed_cnt;
+       __le16 log_type;
+       __le16 size;
+       __le32 timestamp;
+       u8 payload[0];
+} __packed;
+
 /* Target specific defines for MAIN firmware */
 #define TARGET_NUM_VDEVS                       8
 #define TARGET_NUM_PEER_AST                    2
@@ -279,6 +291,7 @@ enum ath10k_mcast2ucast_mode {
 #define SI_RX_DATA1_OFFSET                     0x00000014
 
 #define CORE_CTRL_CPU_INTR_MASK                        0x00002000
+#define CORE_CTRL_PCIE_REG_31_MASK             0x00000800
 #define CORE_CTRL_ADDRESS                      0x0000
 #define PCIE_INTR_ENABLE_ADDRESS               0x0008
 #define PCIE_INTR_CAUSE_ADDRESS                        0x000c
index 46709301a51e1986bb4b505b659d7f94bbfca6d9..61b006f42f9512c191517272e90d9d85b3bcb7dc 100644 (file)
@@ -479,6 +479,40 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar)
 /* Interface management */
 /************************/
 
+void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->data_lock);
+
+       if (!arvif->beacon)
+               return;
+
+       if (!arvif->beacon_buf)
+               dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
+                                arvif->beacon->len, DMA_TO_DEVICE);
+
+       dev_kfree_skb_any(arvif->beacon);
+
+       arvif->beacon = NULL;
+       arvif->beacon_sent = false;
+}
+
+static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+
+       lockdep_assert_held(&ar->data_lock);
+
+       ath10k_mac_vif_beacon_free(arvif);
+
+       if (arvif->beacon_buf) {
+               dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+                                 arvif->beacon_buf, arvif->beacon_paddr);
+               arvif->beacon_buf = NULL;
+       }
+}
+
 static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
 {
        int ret;
@@ -590,9 +624,9 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
                return -ENOMEM;
        }
 
-       bit = ffs(ar->free_vdev_map);
+       bit = __ffs64(ar->free_vdev_map);
 
-       ar->monitor_vdev_id = bit - 1;
+       ar->monitor_vdev_id = bit;
 
        ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id,
                                     WMI_VDEV_TYPE_MONITOR,
@@ -603,7 +637,7 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar)
                return ret;
        }
 
-       ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id);
+       ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id);
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
                   ar->monitor_vdev_id);
 
@@ -623,7 +657,7 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar)
                return ret;
        }
 
-       ar->free_vdev_map |= 1 << ar->monitor_vdev_id;
+       ar->free_vdev_map |= 1LL << ar->monitor_vdev_id;
 
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
                   ar->monitor_vdev_id);
@@ -909,15 +943,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                arvif->is_up = false;
 
                spin_lock_bh(&arvif->ar->data_lock);
-               if (arvif->beacon) {
-                       dma_unmap_single(arvif->ar->dev,
-                                        ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                        arvif->beacon->len, DMA_TO_DEVICE);
-                       dev_kfree_skb_any(arvif->beacon);
-
-                       arvif->beacon = NULL;
-                       arvif->beacon_sent = false;
-               }
+               ath10k_mac_vif_beacon_free(arvif);
                spin_unlock_bh(&arvif->ar->data_lock);
 
                return;
@@ -966,14 +992,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
                if (is_zero_ether_addr(arvif->bssid))
                        return;
 
-               ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
-                                        arvif->bssid);
-               if (ret) {
-                       ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n",
-                                   arvif->bssid, arvif->vdev_id, ret);
-                       return;
-               }
-
                memset(arvif->bssid, 0, ETH_ALEN);
 
                return;
@@ -1042,51 +1060,45 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
 /* Station management */
 /**********************/
 
+static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar,
+                                            struct ieee80211_vif *vif)
+{
+       /* Some firmware revisions have unstable STA powersave when listen
+        * interval is set too high (e.g. 5). The symptoms are firmware doesn't
+        * generate NullFunc frames properly even if buffered frames have been
+        * indicated in Beacon TIM. Firmware would seldom wake up to pull
+        * buffered frames. Often pinging the device from AP would simply fail.
+        *
+        * As a workaround set it to 1.
+        */
+       if (vif->type == NL80211_IFTYPE_STATION)
+               return 1;
+
+       return ar->hw->conf.listen_interval;
+}
+
 static void ath10k_peer_assoc_h_basic(struct ath10k *ar,
-                                     struct ath10k_vif *arvif,
+                                     struct ieee80211_vif *vif,
                                      struct ieee80211_sta *sta,
-                                     struct ieee80211_bss_conf *bss_conf,
                                      struct wmi_peer_assoc_complete_arg *arg)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
        lockdep_assert_held(&ar->conf_mutex);
 
        ether_addr_copy(arg->addr, sta->addr);
        arg->vdev_id = arvif->vdev_id;
        arg->peer_aid = sta->aid;
        arg->peer_flags |= WMI_PEER_AUTH;
-
-       if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
-               /*
-                * Seems FW have problems with Power Save in STA
-                * mode when we setup this parameter to high (eg. 5).
-                * Often we see that FW don't send NULL (with clean P flags)
-                * frame even there is info about buffered frames in beacons.
-                * Sometimes we have to wait more than 10 seconds before FW
-                * will wakeup. Often sending one ping from AP to our device
-                * just fail (more than 50%).
-                *
-                * Seems setting this FW parameter to 1 couse FW
-                * will check every beacon and will wakup immediately
-                * after detection buffered data.
-                */
-               arg->peer_listen_intval = 1;
-       else
-               arg->peer_listen_intval = ar->hw->conf.listen_interval;
-
+       arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif);
        arg->peer_num_spatial_streams = 1;
-
-       /*
-        * The assoc capabilities are available only in managed mode.
-        */
-       if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf)
-               arg->peer_caps = bss_conf->assoc_capability;
+       arg->peer_caps = vif->bss_conf.assoc_capability;
 }
 
 static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
-                                      struct ath10k_vif *arvif,
+                                      struct ieee80211_vif *vif,
                                       struct wmi_peer_assoc_complete_arg *arg)
 {
-       struct ieee80211_vif *vif = arvif->vif;
        struct ieee80211_bss_conf *info = &vif->bss_conf;
        struct cfg80211_bss *bss;
        const u8 *rsnie = NULL;
@@ -1343,11 +1355,12 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
 }
 
 static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
-                                   struct ath10k_vif *arvif,
+                                   struct ieee80211_vif *vif,
                                    struct ieee80211_sta *sta,
-                                   struct ieee80211_bss_conf *bss_conf,
                                    struct wmi_peer_assoc_complete_arg *arg)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
        switch (arvif->vdev_type) {
        case WMI_VDEV_TYPE_AP:
                if (sta->wme)
@@ -1359,7 +1372,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
                }
                break;
        case WMI_VDEV_TYPE_STA:
-               if (bss_conf->qos)
+               if (vif->bss_conf.qos)
                        arg->peer_flags |= WMI_PEER_QOS;
                break;
        default:
@@ -1368,7 +1381,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
 }
 
 static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
-                                       struct ath10k_vif *arvif,
+                                       struct ieee80211_vif *vif,
                                        struct ieee80211_sta *sta,
                                        struct wmi_peer_assoc_complete_arg *arg)
 {
@@ -1419,22 +1432,21 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
 }
 
 static int ath10k_peer_assoc_prepare(struct ath10k *ar,
-                                    struct ath10k_vif *arvif,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_sta *sta,
-                                    struct ieee80211_bss_conf *bss_conf,
                                     struct wmi_peer_assoc_complete_arg *arg)
 {
        lockdep_assert_held(&ar->conf_mutex);
 
        memset(arg, 0, sizeof(*arg));
 
-       ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg);
-       ath10k_peer_assoc_h_crypto(ar, arvif, arg);
+       ath10k_peer_assoc_h_basic(ar, vif, sta, arg);
+       ath10k_peer_assoc_h_crypto(ar, vif, arg);
        ath10k_peer_assoc_h_rates(ar, sta, arg);
        ath10k_peer_assoc_h_ht(ar, sta, arg);
        ath10k_peer_assoc_h_vht(ar, sta, arg);
-       ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg);
-       ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg);
+       ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
+       ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
 
        return 0;
 }
@@ -1480,6 +1492,9 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n",
+                  arvif->vdev_id, arvif->bssid, arvif->aid);
+
        rcu_read_lock();
 
        ap_sta = ieee80211_find_sta(vif, bss_conf->bssid);
@@ -1494,8 +1509,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
         * before calling ath10k_setup_peer_smps() which might sleep. */
        ht_cap = ap_sta->ht_cap;
 
-       ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
-                                       bss_conf, &peer_arg);
+       ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
        if (ret) {
                ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n",
                            bss_conf->bssid, arvif->vdev_id, ret);
@@ -1523,6 +1537,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                   "mac vdev %d up (associated) bssid %pM aid %d\n",
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 
+       WARN_ON(arvif->is_up);
+
        arvif->aid = bss_conf->aid;
        ether_addr_copy(arvif->bssid, bss_conf->bssid);
 
@@ -1536,9 +1552,6 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
        arvif->is_up = true;
 }
 
-/*
- * FIXME: flush TIDs
- */
 static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif)
 {
@@ -1548,45 +1561,30 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       /*
-        * For some reason, calling VDEV-DOWN before VDEV-STOP
-        * makes the FW to send frames via HTT after disassociation.
-        * No idea why this happens, even though VDEV-DOWN is supposed
-        * to be analogous to link down, so just stop the VDEV.
-        */
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
-                  arvif->vdev_id);
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n",
+                  arvif->vdev_id, arvif->bssid);
 
-       /* FIXME: check return value */
-       ret = ath10k_vdev_stop(arvif);
-
-       /*
-        * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and
-        * report beacons from previously associated network through HTT.
-        * This in turn would spam mac80211 WARN_ON if we bring down all
-        * interfaces as it expects there is no rx when no interface is
-        * running.
-        */
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
-
-       /* FIXME: why don't we print error if wmi call fails? */
        ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+       if (ret)
+               ath10k_warn(ar, "faield to down vdev %i: %d\n",
+                           arvif->vdev_id, ret);
 
        arvif->def_wep_key_idx = 0;
-
-       arvif->is_started = false;
        arvif->is_up = false;
 }
 
-static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
-                               struct ieee80211_sta *sta, bool reassoc)
+static int ath10k_station_assoc(struct ath10k *ar,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_sta *sta,
+                               bool reassoc)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        struct wmi_peer_assoc_complete_arg peer_arg;
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg);
+       ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg);
        if (ret) {
                ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n",
                            sta->addr, arvif->vdev_id, ret);
@@ -1601,43 +1599,51 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
                return ret;
        }
 
-       ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
-       if (ret) {
-               ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
-                           arvif->vdev_id, ret);
-               return ret;
-       }
-
-       if (!sta->wme && !reassoc) {
-               arvif->num_legacy_stations++;
-               ret  = ath10k_recalc_rtscts_prot(arvif);
+       /* Re-assoc is run only to update supported rates for given station. It
+        * doesn't make much sense to reconfigure the peer completely.
+        */
+       if (!reassoc) {
+               ret = ath10k_setup_peer_smps(ar, arvif, sta->addr,
+                                            &sta->ht_cap);
                if (ret) {
-                       ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+                       ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
                        return ret;
                }
-       }
 
-       ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
-       if (ret) {
-               ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
-                           arvif->vdev_id, ret);
-               return ret;
-       }
+               ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
+               if (ret) {
+                       ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
+                                   sta->addr, arvif->vdev_id, ret);
+                       return ret;
+               }
 
-       ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta);
-       if (ret) {
-               ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n",
-                           sta->addr, arvif->vdev_id, ret);
-               return ret;
+               if (!sta->wme) {
+                       arvif->num_legacy_stations++;
+                       ret  = ath10k_recalc_rtscts_prot(arvif);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n",
+                                           arvif->vdev_id, ret);
+                               return ret;
+                       }
+               }
+
+               ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
+               if (ret) {
+                       ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
        }
 
        return ret;
 }
 
-static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
+static int ath10k_station_disassoc(struct ath10k *ar,
+                                  struct ieee80211_vif *vif,
                                   struct ieee80211_sta *sta)
 {
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -1729,6 +1735,7 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                        ch->passive = passive;
 
                        ch->freq = channel->center_freq;
+                       ch->band_center_freq1 = channel->center_freq;
                        ch->min_power = 0;
                        ch->max_power = channel->max_power * 2;
                        ch->max_reg_power = channel->max_reg_power * 2;
@@ -2376,16 +2383,8 @@ void ath10k_halt(struct ath10k *ar)
        ath10k_hif_power_down(ar);
 
        spin_lock_bh(&ar->data_lock);
-       list_for_each_entry(arvif, &ar->arvifs, list) {
-               if (!arvif->beacon)
-                       continue;
-
-               dma_unmap_single(arvif->ar->dev,
-                                ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                arvif->beacon->len, DMA_TO_DEVICE);
-               dev_kfree_skb_any(arvif->beacon);
-               arvif->beacon = NULL;
-       }
+       list_for_each_entry(arvif, &ar->arvifs, list)
+               ath10k_mac_vif_beacon_cleanup(arvif);
        spin_unlock_bh(&ar->data_lock);
 }
 
@@ -2677,12 +2676,68 @@ static void ath10k_config_chan(struct ath10k *ar)
        ath10k_monitor_recalc(ar);
 }
 
+static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower)
+{
+       int ret;
+       u32 param;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower);
+
+       param = ar->wmi.pdev_param->txpower_limit2g;
+       ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
+       if (ret) {
+               ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
+                           txpower, ret);
+               return ret;
+       }
+
+       param = ar->wmi.pdev_param->txpower_limit5g;
+       ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2);
+       if (ret) {
+               ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
+                           txpower, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ath10k_mac_txpower_recalc(struct ath10k *ar)
+{
+       struct ath10k_vif *arvif;
+       int ret, txpower = -1;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       list_for_each_entry(arvif, &ar->arvifs, list) {
+               WARN_ON(arvif->txpower < 0);
+
+               if (txpower == -1)
+                       txpower = arvif->txpower;
+               else
+                       txpower = min(txpower, arvif->txpower);
+       }
+
+       if (WARN_ON(txpower == -1))
+               return -EINVAL;
+
+       ret = ath10k_mac_txpower_setup(ar, txpower);
+       if (ret) {
+               ath10k_warn(ar, "failed to setup tx power %d: %d\n",
+                           txpower, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ath10k *ar = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
        int ret = 0;
-       u32 param;
 
        mutex_lock(&ar->conf_mutex);
 
@@ -2706,25 +2761,6 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_POWER) {
-               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n",
-                          hw->conf.power_level);
-
-               param = ar->wmi.pdev_param->txpower_limit2g;
-               ret = ath10k_wmi_pdev_set_param(ar, param,
-                                               hw->conf.power_level * 2);
-               if (ret)
-                       ath10k_warn(ar, "failed to set 2g txpower %d: %d\n",
-                                   hw->conf.power_level, ret);
-
-               param = ar->wmi.pdev_param->txpower_limit5g;
-               ret = ath10k_wmi_pdev_set_param(ar, param,
-                                               hw->conf.power_level * 2);
-               if (ret)
-                       ath10k_warn(ar, "failed to set 5g txpower %d: %d\n",
-                                   hw->conf.power_level, ret);
-       }
-
        if (changed & IEEE80211_CONF_CHANGE_PS)
                ath10k_config_ps(ar);
 
@@ -2772,9 +2808,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                ret = -EBUSY;
                goto err;
        }
-       bit = ffs(ar->free_vdev_map);
+       bit = __ffs64(ar->free_vdev_map);
+
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n",
+                  bit, ar->free_vdev_map);
 
-       arvif->vdev_id = bit - 1;
+       arvif->vdev_id = bit;
        arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
 
        if (ar->p2p)
@@ -2804,8 +2843,39 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                break;
        }
 
-       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
-                  arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
+       /* Some firmware revisions don't wait for beacon tx completion before
+        * sending another SWBA event. This could lead to hardware using old
+        * (freed) beacon data in some cases, e.g. tx credit starvation
+        * combined with missed TBTT. This is very very rare.
+        *
+        * On non-IOMMU-enabled hosts this could be a possible security issue
+        * because hw could beacon some random data on the air.  On
+        * IOMMU-enabled hosts DMAR faults would occur in most cases and target
+        * device would crash.
+        *
+        * Since there are no beacon tx completions (implicit nor explicit)
+        * propagated to host the only workaround for this is to allocate a
+        * DMA-coherent buffer for a lifetime of a vif and use it for all
+        * beacon tx commands. Worst case for this approach is some beacons may
+        * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC ||
+           vif->type == NL80211_IFTYPE_AP) {
+               arvif->beacon_buf = dma_zalloc_coherent(ar->dev,
+                                                       IEEE80211_MAX_FRAME_LEN,
+                                                       &arvif->beacon_paddr,
+                                                       GFP_ATOMIC);
+               if (!arvif->beacon_buf) {
+                       ret = -ENOMEM;
+                       ath10k_warn(ar, "failed to allocate beacon buffer: %d\n",
+                                   ret);
+                       goto err;
+               }
+       }
+
+       ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n",
+                  arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype,
+                  arvif->beacon_buf ? "single-buf" : "per-skb");
 
        ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
                                     arvif->vdev_subtype, vif->addr);
@@ -2815,7 +2885,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                goto err;
        }
 
-       ar->free_vdev_map &= ~(1 << arvif->vdev_id);
+       ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
        list_add(&arvif->list, &ar->arvifs);
 
        vdev_param = ar->wmi.vdev_param->def_keyid;
@@ -2899,6 +2969,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                goto err_peer_delete;
        }
 
+       arvif->txpower = vif->bss_conf.txpower;
+       ret = ath10k_mac_txpower_recalc(ar);
+       if (ret) {
+               ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+               goto err_peer_delete;
+       }
+
        mutex_unlock(&ar->conf_mutex);
        return 0;
 
@@ -2908,10 +2985,16 @@ err_peer_delete:
 
 err_vdev_delete:
        ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
-       ar->free_vdev_map |= 1 << arvif->vdev_id;
+       ar->free_vdev_map |= 1LL << arvif->vdev_id;
        list_del(&arvif->list);
 
 err:
+       if (arvif->beacon_buf) {
+               dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN,
+                                 arvif->beacon_buf, arvif->beacon_paddr);
+               arvif->beacon_buf = NULL;
+       }
+
        mutex_unlock(&ar->conf_mutex);
 
        return ret;
@@ -2929,14 +3012,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
        cancel_work_sync(&arvif->wep_key_work);
 
        spin_lock_bh(&ar->data_lock);
-       if (arvif->beacon) {
-               dma_unmap_single(arvif->ar->dev,
-                                ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                arvif->beacon->len, DMA_TO_DEVICE);
-               dev_kfree_skb_any(arvif->beacon);
-               arvif->beacon = NULL;
-       }
-
+       ath10k_mac_vif_beacon_cleanup(arvif);
        spin_unlock_bh(&ar->data_lock);
 
        ret = ath10k_spectral_vif_stop(arvif);
@@ -2944,7 +3020,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
                ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n",
                            arvif->vdev_id, ret);
 
-       ar->free_vdev_map |= 1 << arvif->vdev_id;
+       ar->free_vdev_map |= 1LL << arvif->vdev_id;
        list_del(&arvif->list);
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
@@ -3068,54 +3144,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                arvif->u.ap.hidden_ssid = info->hidden_ssid;
        }
 
-       /*
-        * Firmware manages AP self-peer internally so make sure to not create
-        * it in driver. Otherwise AP self-peer deletion may timeout later.
-        */
-       if (changed & BSS_CHANGED_BSSID &&
-           vif->type != NL80211_IFTYPE_AP) {
-               if (!is_zero_ether_addr(info->bssid)) {
-                       ath10k_dbg(ar, ATH10K_DBG_MAC,
-                                  "mac vdev %d create peer %pM\n",
-                                  arvif->vdev_id, info->bssid);
-
-                       ret = ath10k_peer_create(ar, arvif->vdev_id,
-                                                info->bssid);
-                       if (ret)
-                               ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n",
-                                           info->bssid, arvif->vdev_id, ret);
-
-                       if (vif->type == NL80211_IFTYPE_STATION) {
-                               /*
-                                * this is never erased as we it for crypto key
-                                * clearing; this is FW requirement
-                                */
-                               ether_addr_copy(arvif->bssid, info->bssid);
-
-                               ath10k_dbg(ar, ATH10K_DBG_MAC,
-                                          "mac vdev %d start %pM\n",
-                                          arvif->vdev_id, info->bssid);
-
-                               ret = ath10k_vdev_start(arvif);
-                               if (ret) {
-                                       ath10k_warn(ar, "failed to start vdev %i: %d\n",
-                                                   arvif->vdev_id, ret);
-                                       goto exit;
-                               }
-
-                               arvif->is_started = true;
-                       }
-
-                       /*
-                        * Mac80211 does not keep IBSS bssid when leaving IBSS,
-                        * so driver need to store it. It is needed when leaving
-                        * IBSS in order to remove BSSID peer.
-                        */
-                       if (vif->type == NL80211_IFTYPE_ADHOC)
-                               memcpy(arvif->bssid, info->bssid,
-                                      ETH_ALEN);
-               }
-       }
+       if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid))
+               ether_addr_copy(arvif->bssid, info->bssid);
 
        if (changed & BSS_CHANGED_BEACON_ENABLED)
                ath10k_control_beaconing(arvif, info);
@@ -3177,10 +3207,21 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                                ath10k_monitor_stop(ar);
                        ath10k_bss_assoc(hw, vif, info);
                        ath10k_monitor_recalc(ar);
+               } else {
+                       ath10k_bss_disassoc(hw, vif);
                }
        }
 
-exit:
+       if (changed & BSS_CHANGED_TXPOWER) {
+               ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n",
+                          arvif->vdev_id, info->txpower);
+
+               arvif->txpower = info->txpower;
+               ret = ath10k_mac_txpower_recalc(ar);
+               if (ret)
+                       ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+       }
+
        mutex_unlock(&ar->conf_mutex);
 }
 
@@ -3453,7 +3494,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
                ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
                           sta->addr);
 
-               err = ath10k_station_assoc(ar, arvif, sta, true);
+               err = ath10k_station_assoc(ar, arvif->vif, sta, true);
                if (err)
                        ath10k_warn(ar, "failed to reassociate station: %pM\n",
                                    sta->addr);
@@ -3489,8 +3530,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
        mutex_lock(&ar->conf_mutex);
 
        if (old_state == IEEE80211_STA_NOTEXIST &&
-           new_state == IEEE80211_STA_NONE &&
-           vif->type != NL80211_IFTYPE_STATION) {
+           new_state == IEEE80211_STA_NONE) {
                /*
                 * New station addition.
                 */
@@ -3514,6 +3554,21 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                if (ret)
                        ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
+
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       WARN_ON(arvif->is_started);
+
+                       ret = ath10k_vdev_start(arvif);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to start vdev %i: %d\n",
+                                           arvif->vdev_id, ret);
+                               WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id,
+                                                          sta->addr));
+                               goto exit;
+                       }
+
+                       arvif->is_started = true;
+               }
        } else if ((old_state == IEEE80211_STA_NONE &&
                    new_state == IEEE80211_STA_NOTEXIST)) {
                /*
@@ -3522,13 +3577,23 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                ath10k_dbg(ar, ATH10K_DBG_MAC,
                           "mac vdev %d peer delete %pM (sta gone)\n",
                           arvif->vdev_id, sta->addr);
+
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       WARN_ON(!arvif->is_started);
+
+                       ret = ath10k_vdev_stop(arvif);
+                       if (ret)
+                               ath10k_warn(ar, "failed to stop vdev %i: %d\n",
+                                           arvif->vdev_id, ret);
+
+                       arvif->is_started = false;
+               }
+
                ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
                if (ret)
                        ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
 
-               if (vif->type == NL80211_IFTYPE_STATION)
-                       ath10k_bss_disassoc(hw, vif);
        } else if (old_state == IEEE80211_STA_AUTH &&
                   new_state == IEEE80211_STA_ASSOC &&
                   (vif->type == NL80211_IFTYPE_AP ||
@@ -3539,7 +3604,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n",
                           sta->addr);
 
-               ret = ath10k_station_assoc(ar, arvif, sta, false);
+               ret = ath10k_station_assoc(ar, vif, sta, false);
                if (ret)
                        ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
@@ -3553,7 +3618,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
                           sta->addr);
 
-               ret = ath10k_station_disassoc(ar, arvif, sta);
+               ret = ath10k_station_disassoc(ar, vif, sta);
                if (ret)
                        ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n",
                                    sta->addr, arvif->vdev_id, ret);
@@ -3929,10 +3994,14 @@ exit:
 }
 #endif
 
-static void ath10k_restart_complete(struct ieee80211_hw *hw)
+static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
+                                    enum ieee80211_reconfig_type reconfig_type)
 {
        struct ath10k *ar = hw->priv;
 
+       if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
+               return;
+
        mutex_lock(&ar->conf_mutex);
 
        /* If device failed to restart it will be in a different state, e.g.
@@ -4450,12 +4519,15 @@ static const struct ieee80211_ops ath10k_ops = {
        .tx_last_beacon                 = ath10k_tx_last_beacon,
        .set_antenna                    = ath10k_set_antenna,
        .get_antenna                    = ath10k_get_antenna,
-       .restart_complete               = ath10k_restart_complete,
+       .reconfig_complete              = ath10k_reconfig_complete,
        .get_survey                     = ath10k_get_survey,
        .set_bitrate_mask               = ath10k_set_bitrate_mask,
        .sta_rc_update                  = ath10k_sta_rc_update,
        .get_tsf                        = ath10k_get_tsf,
        .ampdu_action                   = ath10k_ampdu_action,
+       .get_et_sset_count              = ath10k_debug_get_et_sset_count,
+       .get_et_stats                   = ath10k_debug_get_et_stats,
+       .get_et_strings                 = ath10k_debug_get_et_strings,
 
        CFG80211_TESTMODE_CMD(ath10k_tm_cmd)
 
@@ -4800,15 +4872,6 @@ int ath10k_mac_register(struct ath10k *ar)
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_AP);
 
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-               /* TODO:  Have to deal with 2x2 chips if/when the come out. */
-               ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK;
-               ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK;
-       } else {
-               ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK;
-               ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK;
-       }
-
        ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask;
        ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask;
 
index 6c80eeada3e28863bb1fe22e753251b64f73608d..965c511174999508a5b5386e563fd61d1b4b55d2 100644 (file)
@@ -39,6 +39,7 @@ void ath10k_offchan_tx_work(struct work_struct *work);
 void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
 void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
 void ath10k_halt(struct ath10k *ar);
+void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
 
 static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
 {
index 59e0ea83be5098ea261f35330ba1659749b0eeb8..4a4740b4bdc05d9b2848aadf93efb1b60d3b9081 100644 (file)
@@ -485,6 +485,8 @@ 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);
+
        ce_diag = ar_pci->ce_diag;
 
        /*
@@ -511,7 +513,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                nbytes = min_t(unsigned int, remaining_bytes,
                               DIAG_TRANSFER_LIMIT);
 
-               ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
+               ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data);
                if (ret != 0)
                        goto done;
 
@@ -527,15 +529,15 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem,
                                                     address);
 
-               ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0,
-                                    0);
+               ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0,
+                                           0);
                if (ret)
                        goto done;
 
                i = 0;
-               while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
-                                                    &completed_nbytes,
-                                                    &id) != 0) {
+               while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
+                                                           &completed_nbytes,
+                                                           &id) != 0) {
                        mdelay(1);
                        if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
                                ret = -EBUSY;
@@ -554,9 +556,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
                }
 
                i = 0;
-               while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
-                                                    &completed_nbytes,
-                                                    &id, &flags) != 0) {
+               while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
+                                                           &completed_nbytes,
+                                                           &id, &flags) != 0) {
                        mdelay(1);
 
                        if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@@ -591,6 +593,8 @@ done:
                dma_free_coherent(ar->dev, orig_nbytes, data_buf,
                                  ce_data_base);
 
+       spin_unlock_bh(&ar_pci->ce_lock);
+
        return ret;
 }
 
@@ -648,6 +652,8 @@ static 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);
+
        ce_diag = ar_pci->ce_diag;
 
        /*
@@ -688,7 +694,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
                nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT);
 
                /* Set up to receive directly into Target(!) address */
-               ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address);
+               ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address);
                if (ret != 0)
                        goto done;
 
@@ -696,15 +702,15 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
                 * Request CE to send caller-supplied data that
                 * was copied to bounce buffer to Target(!) address.
                 */
-               ret = ath10k_ce_send(ce_diag, NULL, (u32)ce_data,
-                                    nbytes, 0, 0);
+               ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data,
+                                           nbytes, 0, 0);
                if (ret != 0)
                        goto done;
 
                i = 0;
-               while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf,
-                                                    &completed_nbytes,
-                                                    &id) != 0) {
+               while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf,
+                                                           &completed_nbytes,
+                                                           &id) != 0) {
                        mdelay(1);
 
                        if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@@ -724,9 +730,9 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
                }
 
                i = 0;
-               while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf,
-                                                    &completed_nbytes,
-                                                    &id, &flags) != 0) {
+               while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf,
+                                                           &completed_nbytes,
+                                                           &id, &flags) != 0) {
                        mdelay(1);
 
                        if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) {
@@ -760,6 +766,8 @@ done:
                ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n",
                            address, ret);
 
+       spin_unlock_bh(&ar_pci->ce_lock);
+
        return ret;
 }
 
@@ -861,6 +869,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
                }
 
                skb_put(skb, nbytes);
+
+               ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n",
+                          ce_state->id, skb->len);
+               ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ",
+                               skb->data, skb->len);
+
                cb->rx_completion(ar, skb, pipe_info->pipe_num);
        }
 
@@ -936,6 +950,12 @@ err:
        return err;
 }
 
+static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
+                                   size_t buf_len)
+{
+       return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
+}
+
 static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -986,6 +1006,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
 
        spin_lock_bh(&ar->data_lock);
 
+       ar->stats.fw_crash_counter++;
+
        crash_data = ath10k_debug_get_new_fw_crash_data(ar);
 
        if (crash_data)
@@ -1121,14 +1143,37 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
                                                 &dl_is_polled);
 }
 
-static void ath10k_pci_irq_disable(struct ath10k *ar)
+static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int i;
+       u32 val;
 
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
+       val &= ~CORE_CTRL_PCIE_REG_31_MASK;
+
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+}
+
+static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
+{
+       u32 val;
+
+       val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS);
+       val |= CORE_CTRL_PCIE_REG_31_MASK;
+
+       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val);
+}
+
+static void ath10k_pci_irq_disable(struct ath10k *ar)
+{
        ath10k_ce_disable_interrupts(ar);
        ath10k_pci_disable_and_clear_legacy_irq(ar);
-       /* FIXME: How to mask all MSI interrupts? */
+       ath10k_pci_irq_msi_fw_mask(ar);
+}
+
+static void ath10k_pci_irq_sync(struct ath10k *ar)
+{
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       int i;
 
        for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
                synchronize_irq(ar_pci->pdev->irq + i);
@@ -1138,7 +1183,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar)
 {
        ath10k_ce_enable_interrupts(ar);
        ath10k_pci_enable_legacy_irq(ar);
-       /* FIXME: How to unmask all MSI interrupts? */
+       ath10k_pci_irq_msi_fw_unmask(ar);
 }
 
 static int ath10k_pci_hif_start(struct ath10k *ar)
@@ -1266,6 +1311,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
        ath10k_pci_warm_reset(ar);
 
        ath10k_pci_irq_disable(ar);
+       ath10k_pci_irq_sync(ar);
        ath10k_pci_flush(ar);
 }
 
@@ -1569,23 +1615,40 @@ static int ath10k_pci_init_config(struct ath10k *ar)
        return 0;
 }
 
-static int ath10k_pci_alloc_ce(struct ath10k *ar)
+static int ath10k_pci_alloc_pipes(struct ath10k *ar)
 {
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+       struct ath10k_pci_pipe *pipe;
        int i, ret;
 
        for (i = 0; i < CE_COUNT; i++) {
-               ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);
+               pipe = &ar_pci->pipe_info[i];
+               pipe->ce_hdl = &ar_pci->ce_states[i];
+               pipe->pipe_num = i;
+               pipe->hif_ce_state = ar;
+
+               ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i],
+                                          ath10k_pci_ce_send_done,
+                                          ath10k_pci_ce_recv_data);
                if (ret) {
                        ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",
                                   i, ret);
                        return ret;
                }
+
+               /* Last CE is Diagnostic Window */
+               if (i == CE_COUNT - 1) {
+                       ar_pci->ce_diag = pipe->ce_hdl;
+                       continue;
+               }
+
+               pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max);
        }
 
        return 0;
 }
 
-static void ath10k_pci_free_ce(struct ath10k *ar)
+static void ath10k_pci_free_pipes(struct ath10k *ar)
 {
        int i;
 
@@ -1593,39 +1656,17 @@ static void ath10k_pci_free_ce(struct ath10k *ar)
                ath10k_ce_free_pipe(ar, i);
 }
 
-static int ath10k_pci_ce_init(struct ath10k *ar)
+static int ath10k_pci_init_pipes(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ath10k_pci_pipe *pipe_info;
-       const struct ce_attr *attr;
-       int pipe_num, ret;
+       int i, ret;
 
-       for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {
-               pipe_info = &ar_pci->pipe_info[pipe_num];
-               pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num];
-               pipe_info->pipe_num = pipe_num;
-               pipe_info->hif_ce_state = ar;
-               attr = &host_ce_config_wlan[pipe_num];
-
-               ret = ath10k_ce_init_pipe(ar, pipe_num, attr,
-                                         ath10k_pci_ce_send_done,
-                                         ath10k_pci_ce_recv_data);
+       for (i = 0; i < CE_COUNT; i++) {
+               ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);
                if (ret) {
                        ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",
-                                  pipe_num, ret);
+                                  i, ret);
                        return ret;
                }
-
-               if (pipe_num == CE_COUNT - 1) {
-                       /*
-                        * Reserve the ultimate CE for
-                        * diagnostic Window support
-                        */
-                       ar_pci->ce_diag = pipe_info->ce_hdl;
-                       continue;
-               }
-
-               pipe_info->buf_sz = (size_t)(attr->src_sz_max);
        }
 
        return 0;
@@ -1672,6 +1713,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n");
 
+       spin_lock_bh(&ar->data_lock);
+
+       ar->stats.fw_warm_reset_counter++;
+
+       spin_unlock_bh(&ar->data_lock);
+
        /* debug */
        val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
                                PCIE_INTR_CAUSE_ADDRESS);
@@ -1773,7 +1820,7 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset)
                goto err;
        }
 
-       ret = ath10k_pci_ce_init(ar);
+       ret = ath10k_pci_init_pipes(ar);
        if (ret) {
                ath10k_err(ar, "failed to initialize CE: %d\n", ret);
                goto err;
@@ -1921,6 +1968,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar)
 
 static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
        .tx_sg                  = ath10k_pci_hif_tx_sg,
+       .diag_read              = ath10k_pci_hif_diag_read,
        .exchange_bmi_msg       = ath10k_pci_hif_exchange_bmi_msg,
        .start                  = ath10k_pci_hif_start,
        .stop                   = ath10k_pci_hif_stop,
@@ -2250,14 +2298,14 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
 
                if (ar_pci->num_msi_intrs == 0)
                        /* Fix potential race by repeating CORE_BASE writes */
-                       ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
-                                          PCIE_INTR_ENABLE_ADDRESS,
-                                          PCIE_INTR_FIRMWARE_MASK |
-                                          PCIE_INTR_CE_MASK_ALL);
+                       ath10k_pci_enable_legacy_irq(ar);
 
                mdelay(10);
        } while (time_before(jiffies, timeout));
 
+       ath10k_pci_disable_and_clear_legacy_irq(ar);
+       ath10k_pci_irq_msi_fw_mask(ar);
+
        if (val == 0xffffffff) {
                ath10k_err(ar, "failed to read device register, device is gone\n");
                return -EIO;
@@ -2287,6 +2335,12 @@ static int ath10k_pci_cold_reset(struct ath10k *ar)
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n");
 
+       spin_lock_bh(&ar->data_lock);
+
+       ar->stats.fw_cold_reset_counter++;
+
+       spin_unlock_bh(&ar->data_lock);
+
        /* Put Target, including PCIe, into RESET. */
        val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
        val |= 1;
@@ -2400,6 +2454,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        u32 chip_id;
 
        ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
+                               ATH10K_BUS_PCI,
                                &ath10k_pci_hif_ops);
        if (!ar) {
                dev_err(&pdev->dev, "failed to allocate core\n");
@@ -2435,7 +2490,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_sleep;
        }
 
-       ret = ath10k_pci_alloc_ce(ar);
+       ret = ath10k_pci_alloc_pipes(ar);
        if (ret) {
                ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
                           ret);
@@ -2443,25 +2498,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        }
 
        ath10k_pci_ce_deinit(ar);
-
-       ret = ath10k_ce_disable_interrupts(ar);
-       if (ret) {
-               ath10k_err(ar, "failed to disable copy engine interrupts: %d\n",
-                          ret);
-               goto err_free_ce;
-       }
-
-       /* Workaround: There's no known way to mask all possible interrupts via
-        * device CSR. The only way to make sure device doesn't assert
-        * interrupts is to reset it. Interrupts are then disabled on host
-        * after handlers are registered.
-        */
-       ath10k_pci_warm_reset(ar);
+       ath10k_pci_irq_disable(ar);
 
        ret = ath10k_pci_init_irq(ar);
        if (ret) {
                ath10k_err(ar, "failed to init irqs: %d\n", ret);
-               goto err_free_ce;
+               goto err_free_pipes;
        }
 
        ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
@@ -2474,9 +2516,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_deinit_irq;
        }
 
-       /* This shouldn't race as the device has been reset above. */
-       ath10k_pci_irq_disable(ar);
-
        ret = ath10k_core_register(ar, chip_id);
        if (ret) {
                ath10k_err(ar, "failed to register driver core: %d\n", ret);
@@ -2492,8 +2531,8 @@ err_free_irq:
 err_deinit_irq:
        ath10k_pci_deinit_irq(ar);
 
-err_free_ce:
-       ath10k_pci_free_ce(ar);
+err_free_pipes:
+       ath10k_pci_free_pipes(ar);
 
 err_sleep:
        ath10k_pci_sleep(ar);
@@ -2527,7 +2566,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
        ath10k_pci_kill_tasklet(ar);
        ath10k_pci_deinit_irq(ar);
        ath10k_pci_ce_deinit(ar);
-       ath10k_pci_free_ce(ar);
+       ath10k_pci_free_pipes(ar);
        ath10k_pci_sleep(ar);
        ath10k_pci_release(ar);
        ath10k_core_destroy(ar);
@@ -2565,5 +2604,7 @@ module_exit(ath10k_pci_exit);
 MODULE_AUTHOR("Qualcomm Atheros");
 MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
+MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
index 3e1454b74e007200ccc8c6ee4a3f1647cefceebd..63ce61fcdac85c070033091fa9ac40e268021436 100644 (file)
@@ -56,14 +56,14 @@ static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
 }
 
 int ath10k_spectral_process_fft(struct ath10k *ar,
-                               struct wmi_single_phyerr_rx_event *event,
-                               struct phyerr_fft_report *fftr,
+                               const struct wmi_phyerr *phyerr,
+                               const struct phyerr_fft_report *fftr,
                                size_t bin_len, u64 tsf)
 {
        struct fft_sample_ath10k *fft_sample;
        u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
        u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
-       u32 reg0, reg1, nf_list1, nf_list2;
+       u32 reg0, reg1;
        u8 chain_idx, *bins;
        int dc_pos;
 
@@ -82,7 +82,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
        /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
         * but the results/plots suggest that its actually 22/44/88 MHz.
         */
-       switch (event->hdr.chan_width_mhz) {
+       switch (phyerr->chan_width_mhz) {
        case 20:
                fft_sample->chan_width_mhz = 22;
                break;
@@ -101,7 +101,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
                fft_sample->chan_width_mhz = 88;
                break;
        default:
-               fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
+               fft_sample->chan_width_mhz = phyerr->chan_width_mhz;
        }
 
        fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
@@ -110,36 +110,22 @@ int ath10k_spectral_process_fft(struct ath10k *ar,
        peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
        fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
        fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
-       fft_sample->rssi = event->hdr.rssi_combined;
+       fft_sample->rssi = phyerr->rssi_combined;
 
        total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
        base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
        fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
        fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
 
-       freq1 = __le16_to_cpu(event->hdr.freq1);
-       freq2 = __le16_to_cpu(event->hdr.freq2);
+       freq1 = __le16_to_cpu(phyerr->freq1);
+       freq2 = __le16_to_cpu(phyerr->freq2);
        fft_sample->freq1 = __cpu_to_be16(freq1);
        fft_sample->freq2 = __cpu_to_be16(freq2);
 
-       nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
-       nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
        chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
 
-       switch (chain_idx) {
-       case 0:
-               fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
-               break;
-       case 1:
-               fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
-               break;
-       case 2:
-               fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
-               break;
-       case 3:
-               fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
-               break;
-       }
+       fft_sample->noise = __cpu_to_be16(
+                       __le16_to_cpu(phyerr->nf_chains[chain_idx]));
 
        bins = (u8 *)fftr;
        bins += sizeof(*fftr);
index ddc57c55727214a386813e7f0a99393930161683..042f5b302c75ebc3121cd56cd7bacd830a10a8ce 100644 (file)
@@ -47,8 +47,8 @@ enum ath10k_spectral_mode {
 #ifdef CONFIG_ATH10K_DEBUGFS
 
 int ath10k_spectral_process_fft(struct ath10k *ar,
-                               struct wmi_single_phyerr_rx_event *event,
-                               struct phyerr_fft_report *fftr,
+                               const struct wmi_phyerr *phyerr,
+                               const struct phyerr_fft_report *fftr,
                                size_t bin_len, u64 tsf);
 int ath10k_spectral_start(struct ath10k *ar);
 int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
@@ -59,8 +59,8 @@ void ath10k_spectral_destroy(struct ath10k *ar);
 
 static inline int
 ath10k_spectral_process_fft(struct ath10k *ar,
-                           struct wmi_single_phyerr_rx_event *event,
-                           struct phyerr_fft_report *fftr,
+                           const struct wmi_phyerr *phyerr,
+                           const struct phyerr_fft_report *fftr,
                            size_t bin_len, u64 tsf)
 {
        return 0;
index 574b75ab260988a6525339ed44623e71e790a273..9d34e7f6c4553074b61d6b1793cee82cc077b113 100644 (file)
@@ -254,6 +254,169 @@ TRACE_EVENT(ath10k_wmi_dbglog,
        )
 );
 
+TRACE_EVENT(ath10k_htt_pktlog,
+           TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len),
+
+       TP_ARGS(ar, buf, buf_len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->dev))
+               __string(driver, dev_driver_string(ar->dev))
+               __field(u16, buf_len)
+               __dynamic_array(u8, pktlog, buf_len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->dev));
+               __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->buf_len = buf_len;
+               memcpy(__get_dynamic_array(pktlog), buf, buf_len);
+       ),
+
+       TP_printk(
+               "%s %s size %hu",
+               __get_str(driver),
+               __get_str(device),
+               __entry->buf_len
+        )
+);
+
+TRACE_EVENT(ath10k_htt_rx_desc,
+           TP_PROTO(struct ath10k *ar, u32 tsf, void *rxdesc, u16 len),
+
+       TP_ARGS(ar, tsf, rxdesc, len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->dev))
+               __string(driver, dev_driver_string(ar->dev))
+               __field(u32, tsf)
+               __field(u16, len)
+               __dynamic_array(u8, rxdesc, len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->dev));
+               __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->tsf = tsf;
+               __entry->len = len;
+               memcpy(__get_dynamic_array(rxdesc), rxdesc, len);
+       ),
+
+       TP_printk(
+               "%s %s %u len %hu",
+               __get_str(driver),
+               __get_str(device),
+               __entry->tsf,
+               __entry->len
+        )
+);
+
+TRACE_EVENT(ath10k_htt_tx,
+           TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len,
+                    u8 vdev_id, u8 tid),
+
+       TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->dev))
+               __string(driver, dev_driver_string(ar->dev))
+               __field(u16, msdu_id)
+               __field(u16, msdu_len)
+               __field(u8, vdev_id)
+               __field(u8, tid)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->dev));
+               __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->msdu_id = msdu_id;
+               __entry->msdu_len = msdu_len;
+               __entry->vdev_id = vdev_id;
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               "%s %s msdu_id %d msdu_len %d vdev_id %d tid %d",
+               __get_str(driver),
+               __get_str(device),
+               __entry->msdu_id,
+               __entry->msdu_len,
+               __entry->vdev_id,
+               __entry->tid
+        )
+);
+
+TRACE_EVENT(ath10k_txrx_tx_unref,
+           TP_PROTO(struct ath10k *ar, u16 msdu_id),
+
+       TP_ARGS(ar, msdu_id),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->dev))
+               __string(driver, dev_driver_string(ar->dev))
+               __field(u16, msdu_id)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->dev));
+               __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->msdu_id = msdu_id;
+       ),
+
+       TP_printk(
+               "%s %s msdu_id %d",
+               __get_str(driver),
+               __get_str(device),
+               __entry->msdu_id
+        )
+);
+
+DECLARE_EVENT_CLASS(ath10k_data_event,
+                   TP_PROTO(struct ath10k *ar, void *data, size_t len),
+
+       TP_ARGS(ar, data, len),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(ar->dev))
+               __string(driver, dev_driver_string(ar->dev))
+               __field(size_t, len)
+               __dynamic_array(u8, data, len)
+       ),
+
+       TP_fast_assign(
+               __assign_str(device, dev_name(ar->dev));
+               __assign_str(driver, dev_driver_string(ar->dev));
+               __entry->len = len;
+               memcpy(__get_dynamic_array(data), data, len);
+       ),
+
+       TP_printk(
+               "%s %s len %zu\n",
+               __get_str(driver),
+               __get_str(device),
+               __entry->len
+       )
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_htt_tx_msdu,
+            TP_PROTO(struct ath10k *ar, void *data, size_t len),
+            TP_ARGS(ar, data, len)
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_htt_rx_pop_msdu,
+            TP_PROTO(struct ath10k *ar, void *data, size_t len),
+            TP_ARGS(ar, data, len)
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_wmi_mgmt_tx,
+            TP_PROTO(struct ath10k *ar, void *data, size_t len),
+            TP_ARGS(ar, data, len)
+);
+
+DEFINE_EVENT(ath10k_data_event, ath10k_wmi_bcn_tx,
+            TP_PROTO(struct ath10k *ar, void *data, size_t len),
+            TP_ARGS(ar, data, len)
+);
 #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
 
 /* we don't want to use include/trace/events */
index a0cbc21d0d4b9146ff4a4f578f29be2f88bcdc13..f9c90e37bc7c3ad05d3ccf8a53bb58e729b55d3b 100644 (file)
@@ -78,6 +78,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 
        info = IEEE80211_SKB_CB(msdu);
        memset(&info->status, 0, sizeof(info->status));
+       trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
 
        if (tx_done->discard) {
                ieee80211_free_txskb(htt->ar->hw, msdu);
index 2c42bd504b792cce4bcf23e74c0184bcf6ba9569..ae746cece211716c3c51b1e97ab378b79e2ae03f 100644 (file)
@@ -609,6 +609,40 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
        .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
 };
 
+static void
+ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+                          const struct wmi_channel_arg *arg)
+{
+       u32 flags = 0;
+
+       memset(ch, 0, sizeof(*ch));
+
+       if (arg->passive)
+               flags |= WMI_CHAN_FLAG_PASSIVE;
+       if (arg->allow_ibss)
+               flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
+       if (arg->allow_ht)
+               flags |= WMI_CHAN_FLAG_ALLOW_HT;
+       if (arg->allow_vht)
+               flags |= WMI_CHAN_FLAG_ALLOW_VHT;
+       if (arg->ht40plus)
+               flags |= WMI_CHAN_FLAG_HT40_PLUS;
+       if (arg->chan_radar)
+               flags |= WMI_CHAN_FLAG_DFS;
+
+       ch->mhz = __cpu_to_le32(arg->freq);
+       ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
+       ch->band_center_freq2 = 0;
+       ch->min_power = arg->min_power;
+       ch->max_power = arg->max_power;
+       ch->reg_power = arg->max_reg_power;
+       ch->antenna_max = arg->max_antenna_gain;
+
+       /* mode & flags share storage */
+       ch->mode = arg->mode;
+       ch->flags |= __cpu_to_le32(flags);
+}
+
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
 {
        int ret;
@@ -800,6 +834,7 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
                   wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
                   fc & IEEE80211_FCTL_STYPE);
+       trace_ath10k_wmi_mgmt_tx(ar, skb->data, skb->len);
 
        /* Send the management frame buffer to the target */
        ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid);
@@ -1079,7 +1114,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
        struct wmi_mgmt_rx_event_v2 *ev_v2;
        struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_channel *ch;
        struct ieee80211_hdr *hdr;
        u32 rx_status;
        u32 channel;
@@ -1132,25 +1166,26 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
        if (rx_status & WMI_RX_STATUS_ERR_MIC)
                status->flag |= RX_FLAG_MMIC_ERROR;
 
-       /* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to
+       /* Hardware can Rx CCK rates on 5GHz. In that case phy_mode is set to
         * MODE_11B. This means phy_mode is not a reliable source for the band
-        * of mgmt rx. */
-
-       ch = ar->scan_channel;
-       if (!ch)
-               ch = ar->rx_channel;
-
-       if (ch) {
-               status->band = ch->band;
-
-               if (phy_mode == MODE_11B &&
-                   status->band == IEEE80211_BAND_5GHZ)
-                       ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+        * of mgmt rx.
+        */
+       if (channel >= 1 && channel <= 14) {
+               status->band = IEEE80211_BAND_2GHZ;
+       } else if (channel >= 36 && channel <= 165) {
+               status->band = IEEE80211_BAND_5GHZ;
        } else {
-               ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n");
-               status->band = phy_mode_to_band(phy_mode);
+               /* Shouldn't happen unless list of advertised channels to
+                * mac80211 has been changed.
+                */
+               WARN_ON_ONCE(1);
+               dev_kfree_skb(skb);
+               return 0;
        }
 
+       if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ)
+               ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n");
+
        status->freq = ieee80211_channel_to_frequency(channel, status->band);
        status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
        status->rate_idx = get_rate_idx(rate, status->band);
@@ -1295,14 +1330,196 @@ static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
        return 0;
 }
 
+static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
+                                      struct ath10k_fw_stats_pdev *dst)
+{
+       const struct wal_dbg_tx_stats *tx = &src->wal.tx;
+       const struct wal_dbg_rx_stats *rx = &src->wal.rx;
+
+       dst->ch_noise_floor = __le32_to_cpu(src->chan_nf);
+       dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count);
+       dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count);
+       dst->rx_clear_count = __le32_to_cpu(src->rx_clear_count);
+       dst->cycle_count = __le32_to_cpu(src->cycle_count);
+       dst->phy_err_count = __le32_to_cpu(src->phy_err_count);
+       dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr);
+
+       dst->comp_queued = __le32_to_cpu(tx->comp_queued);
+       dst->comp_delivered = __le32_to_cpu(tx->comp_delivered);
+       dst->msdu_enqued = __le32_to_cpu(tx->msdu_enqued);
+       dst->mpdu_enqued = __le32_to_cpu(tx->mpdu_enqued);
+       dst->wmm_drop = __le32_to_cpu(tx->wmm_drop);
+       dst->local_enqued = __le32_to_cpu(tx->local_enqued);
+       dst->local_freed = __le32_to_cpu(tx->local_freed);
+       dst->hw_queued = __le32_to_cpu(tx->hw_queued);
+       dst->hw_reaped = __le32_to_cpu(tx->hw_reaped);
+       dst->underrun = __le32_to_cpu(tx->underrun);
+       dst->tx_abort = __le32_to_cpu(tx->tx_abort);
+       dst->mpdus_requed = __le32_to_cpu(tx->mpdus_requed);
+       dst->tx_ko = __le32_to_cpu(tx->tx_ko);
+       dst->data_rc = __le32_to_cpu(tx->data_rc);
+       dst->self_triggers = __le32_to_cpu(tx->self_triggers);
+       dst->sw_retry_failure = __le32_to_cpu(tx->sw_retry_failure);
+       dst->illgl_rate_phy_err = __le32_to_cpu(tx->illgl_rate_phy_err);
+       dst->pdev_cont_xretry = __le32_to_cpu(tx->pdev_cont_xretry);
+       dst->pdev_tx_timeout = __le32_to_cpu(tx->pdev_tx_timeout);
+       dst->pdev_resets = __le32_to_cpu(tx->pdev_resets);
+       dst->phy_underrun = __le32_to_cpu(tx->phy_underrun);
+       dst->txop_ovf = __le32_to_cpu(tx->txop_ovf);
+
+       dst->mid_ppdu_route_change = __le32_to_cpu(rx->mid_ppdu_route_change);
+       dst->status_rcvd = __le32_to_cpu(rx->status_rcvd);
+       dst->r0_frags = __le32_to_cpu(rx->r0_frags);
+       dst->r1_frags = __le32_to_cpu(rx->r1_frags);
+       dst->r2_frags = __le32_to_cpu(rx->r2_frags);
+       dst->r3_frags = __le32_to_cpu(rx->r3_frags);
+       dst->htt_msdus = __le32_to_cpu(rx->htt_msdus);
+       dst->htt_mpdus = __le32_to_cpu(rx->htt_mpdus);
+       dst->loc_msdus = __le32_to_cpu(rx->loc_msdus);
+       dst->loc_mpdus = __le32_to_cpu(rx->loc_mpdus);
+       dst->oversize_amsdu = __le32_to_cpu(rx->oversize_amsdu);
+       dst->phy_errs = __le32_to_cpu(rx->phy_errs);
+       dst->phy_err_drop = __le32_to_cpu(rx->phy_err_drop);
+       dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs);
+}
+
+static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
+                                      struct ath10k_fw_stats_peer *dst)
+{
+       ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
+       dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
+       dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
+}
+
+static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
+                                        struct sk_buff *skb,
+                                        struct ath10k_fw_stats *stats)
+{
+       const struct wmi_stats_event *ev = (void *)skb->data;
+       u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+       int i;
+
+       if (!skb_pull(skb, sizeof(*ev)))
+               return -EPROTO;
+
+       num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+       num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+       num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+       for (i = 0; i < num_pdev_stats; i++) {
+               const struct wmi_pdev_stats *src;
+               struct ath10k_fw_stats_pdev *dst;
+
+               src = (void *)skb->data;
+               if (!skb_pull(skb, sizeof(*src)))
+                       return -EPROTO;
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath10k_wmi_pull_pdev_stats(src, dst);
+               list_add_tail(&dst->list, &stats->pdevs);
+       }
+
+       /* fw doesn't implement vdev stats */
+
+       for (i = 0; i < num_peer_stats; i++) {
+               const struct wmi_peer_stats *src;
+               struct ath10k_fw_stats_peer *dst;
+
+               src = (void *)skb->data;
+               if (!skb_pull(skb, sizeof(*src)))
+                       return -EPROTO;
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath10k_wmi_pull_peer_stats(src, dst);
+               list_add_tail(&dst->list, &stats->peers);
+       }
+
+       return 0;
+}
+
+static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
+                                       struct sk_buff *skb,
+                                       struct ath10k_fw_stats *stats)
+{
+       const struct wmi_stats_event *ev = (void *)skb->data;
+       u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+       int i;
+
+       if (!skb_pull(skb, sizeof(*ev)))
+               return -EPROTO;
+
+       num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+       num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+       num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+       for (i = 0; i < num_pdev_stats; i++) {
+               const struct wmi_10x_pdev_stats *src;
+               struct ath10k_fw_stats_pdev *dst;
+
+               src = (void *)skb->data;
+               if (!skb_pull(skb, sizeof(*src)))
+                       return -EPROTO;
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath10k_wmi_pull_pdev_stats(&src->old, dst);
+
+               dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad);
+               dst->rts_bad = __le32_to_cpu(src->rts_bad);
+               dst->rts_good = __le32_to_cpu(src->rts_good);
+               dst->fcs_bad = __le32_to_cpu(src->fcs_bad);
+               dst->no_beacons = __le32_to_cpu(src->no_beacons);
+               dst->mib_int_count = __le32_to_cpu(src->mib_int_count);
+
+               list_add_tail(&dst->list, &stats->pdevs);
+       }
+
+       /* fw doesn't implement vdev stats */
+
+       for (i = 0; i < num_peer_stats; i++) {
+               const struct wmi_10x_peer_stats *src;
+               struct ath10k_fw_stats_peer *dst;
+
+               src = (void *)skb->data;
+               if (!skb_pull(skb, sizeof(*src)))
+                       return -EPROTO;
+
+               dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+               if (!dst)
+                       continue;
+
+               ath10k_wmi_pull_peer_stats(&src->old, dst);
+
+               dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
+
+               list_add_tail(&dst->list, &stats->peers);
+       }
+
+       return 0;
+}
+
+int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
+                            struct ath10k_fw_stats *stats)
+{
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+               return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats);
+       else
+               return ath10k_wmi_main_pull_fw_stats(ar, skb, stats);
+}
+
 static void ath10k_wmi_event_update_stats(struct ath10k *ar,
                                          struct sk_buff *skb)
 {
-       struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data;
-
        ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
-
-       ath10k_debug_read_target_stats(ar, ev);
+       ath10k_debug_fw_stats_process(ar, skb);
 }
 
 static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
@@ -1579,6 +1796,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
        struct wmi_bcn_info *bcn_info;
        struct ath10k_vif *arvif;
        struct sk_buff *bcn;
+       dma_addr_t paddr;
        int ret, vdev_id = 0;
 
        ev = (struct wmi_host_swba_event *)skb->data;
@@ -1647,27 +1865,35 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                                ath10k_warn(ar, "SWBA overrun on vdev %d\n",
                                            arvif->vdev_id);
 
-                       dma_unmap_single(arvif->ar->dev,
-                                        ATH10K_SKB_CB(arvif->beacon)->paddr,
-                                        arvif->beacon->len, DMA_TO_DEVICE);
-                       dev_kfree_skb_any(arvif->beacon);
-                       arvif->beacon = NULL;
+                       ath10k_mac_vif_beacon_free(arvif);
                }
 
-               ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev,
-                                                          bcn->data, bcn->len,
-                                                          DMA_TO_DEVICE);
-               ret = dma_mapping_error(arvif->ar->dev,
-                                       ATH10K_SKB_CB(bcn)->paddr);
-               if (ret) {
-                       ath10k_warn(ar, "failed to map beacon: %d\n", ret);
-                       dev_kfree_skb_any(bcn);
-                       goto skip;
+               if (!arvif->beacon_buf) {
+                       paddr = dma_map_single(arvif->ar->dev, bcn->data,
+                                              bcn->len, DMA_TO_DEVICE);
+                       ret = dma_mapping_error(arvif->ar->dev, paddr);
+                       if (ret) {
+                               ath10k_warn(ar, "failed to map beacon: %d\n",
+                                           ret);
+                               dev_kfree_skb_any(bcn);
+                               goto skip;
+                       }
+
+                       ATH10K_SKB_CB(bcn)->paddr = paddr;
+               } else {
+                       if (bcn->len > IEEE80211_MAX_FRAME_LEN) {
+                               ath10k_warn(ar, "trimming beacon %d -> %d bytes!\n",
+                                           bcn->len, IEEE80211_MAX_FRAME_LEN);
+                               skb_trim(bcn, IEEE80211_MAX_FRAME_LEN);
+                       }
+                       memcpy(arvif->beacon_buf, bcn->data, bcn->len);
+                       ATH10K_SKB_CB(bcn)->paddr = arvif->beacon_paddr;
                }
 
                arvif->beacon = bcn;
                arvif->beacon_sent = false;
 
+               trace_ath10k_wmi_bcn_tx(ar, bcn->data, bcn->len);
                ath10k_wmi_tx_beacon_nowait(arvif);
 skip:
                spin_unlock_bh(&ar->data_lock);
@@ -1681,8 +1907,8 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
 }
 
 static void ath10k_dfs_radar_report(struct ath10k *ar,
-                                   struct wmi_single_phyerr_rx_event *event,
-                                   struct phyerr_radar_report *rr,
+                                   const struct wmi_phyerr *phyerr,
+                                   const struct phyerr_radar_report *rr,
                                    u64 tsf)
 {
        u32 reg0, reg1, tsf32l;
@@ -1715,12 +1941,12 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
                return;
 
        /* report event to DFS pattern detector */
-       tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp);
+       tsf32l = __le32_to_cpu(phyerr->tsf_timestamp);
        tsf64 = tsf & (~0xFFFFFFFFULL);
        tsf64 |= tsf32l;
 
        width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR);
-       rssi = event->hdr.rssi_combined;
+       rssi = phyerr->rssi_combined;
 
        /* hardware store this as 8 bit signed value,
         * set to zero if negative number
@@ -1759,8 +1985,8 @@ static void ath10k_dfs_radar_report(struct ath10k *ar,
 }
 
 static int ath10k_dfs_fft_report(struct ath10k *ar,
-                                struct wmi_single_phyerr_rx_event *event,
-                                struct phyerr_fft_report *fftr,
+                                const struct wmi_phyerr *phyerr,
+                                const struct phyerr_fft_report *fftr,
                                 u64 tsf)
 {
        u32 reg0, reg1;
@@ -1768,7 +1994,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
 
        reg0 = __le32_to_cpu(fftr->reg0);
        reg1 = __le32_to_cpu(fftr->reg1);
-       rssi = event->hdr.rssi_combined;
+       rssi = phyerr->rssi_combined;
 
        ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n",
@@ -1797,20 +2023,20 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
 }
 
 static void ath10k_wmi_event_dfs(struct ath10k *ar,
-                                struct wmi_single_phyerr_rx_event *event,
+                                const struct wmi_phyerr *phyerr,
                                 u64 tsf)
 {
        int buf_len, tlv_len, res, i = 0;
-       struct phyerr_tlv *tlv;
-       struct phyerr_radar_report *rr;
-       struct phyerr_fft_report *fftr;
-       u8 *tlv_buf;
+       const struct phyerr_tlv *tlv;
+       const struct phyerr_radar_report *rr;
+       const struct phyerr_fft_report *fftr;
+       const u8 *tlv_buf;
 
-       buf_len = __le32_to_cpu(event->hdr.buf_len);
+       buf_len = __le32_to_cpu(phyerr->buf_len);
        ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                   "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n",
-                  event->hdr.phy_err_code, event->hdr.rssi_combined,
-                  __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len);
+                  phyerr->phy_err_code, phyerr->rssi_combined,
+                  __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len);
 
        /* Skip event if DFS disabled */
        if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED))
@@ -1825,9 +2051,9 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
                        return;
                }
 
-               tlv = (struct phyerr_tlv *)&event->bufp[i];
+               tlv = (struct phyerr_tlv *)&phyerr->buf[i];
                tlv_len = __le16_to_cpu(tlv->len);
-               tlv_buf = &event->bufp[i + sizeof(*tlv)];
+               tlv_buf = &phyerr->buf[i + sizeof(*tlv)];
                ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
                           "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n",
                           tlv_len, tlv->tag, tlv->sig);
@@ -1841,7 +2067,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
                        }
 
                        rr = (struct phyerr_radar_report *)tlv_buf;
-                       ath10k_dfs_radar_report(ar, event, rr, tsf);
+                       ath10k_dfs_radar_report(ar, phyerr, rr, tsf);
                        break;
                case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
                        if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) {
@@ -1851,7 +2077,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
                        }
 
                        fftr = (struct phyerr_fft_report *)tlv_buf;
-                       res = ath10k_dfs_fft_report(ar, event, fftr, tsf);
+                       res = ath10k_dfs_fft_report(ar, phyerr, fftr, tsf);
                        if (res)
                                return;
                        break;
@@ -1863,16 +2089,16 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
 
 static void
 ath10k_wmi_event_spectral_scan(struct ath10k *ar,
-                              struct wmi_single_phyerr_rx_event *event,
+                              const struct wmi_phyerr *phyerr,
                               u64 tsf)
 {
        int buf_len, tlv_len, res, i = 0;
        struct phyerr_tlv *tlv;
-       u8 *tlv_buf;
-       struct phyerr_fft_report *fftr;
+       const void *tlv_buf;
+       const struct phyerr_fft_report *fftr;
        size_t fftr_len;
 
-       buf_len = __le32_to_cpu(event->hdr.buf_len);
+       buf_len = __le32_to_cpu(phyerr->buf_len);
 
        while (i < buf_len) {
                if (i + sizeof(*tlv) > buf_len) {
@@ -1881,9 +2107,9 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar,
                        return;
                }
 
-               tlv = (struct phyerr_tlv *)&event->bufp[i];
+               tlv = (struct phyerr_tlv *)&phyerr->buf[i];
                tlv_len = __le16_to_cpu(tlv->len);
-               tlv_buf = &event->bufp[i + sizeof(*tlv)];
+               tlv_buf = &phyerr->buf[i + sizeof(*tlv)];
 
                if (i + sizeof(*tlv) + tlv_len > buf_len) {
                        ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n",
@@ -1900,8 +2126,8 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar,
                        }
 
                        fftr_len = tlv_len - sizeof(*fftr);
-                       fftr = (struct phyerr_fft_report *)tlv_buf;
-                       res = ath10k_spectral_process_fft(ar, event,
+                       fftr = tlv_buf;
+                       res = ath10k_spectral_process_fft(ar, phyerr,
                                                          fftr, fftr_len,
                                                          tsf);
                        if (res < 0) {
@@ -1918,8 +2144,8 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar,
 
 static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 {
-       struct wmi_comb_phyerr_rx_event *comb_event;
-       struct wmi_single_phyerr_rx_event *event;
+       const struct wmi_phyerr_event *ev;
+       const struct wmi_phyerr *phyerr;
        u32 count, i, buf_len, phy_err_code;
        u64 tsf;
        int left_len = skb->len;
@@ -1927,38 +2153,38 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
        ATH10K_DFS_STAT_INC(ar, phy_errors);
 
        /* Check if combined event available */
-       if (left_len < sizeof(*comb_event)) {
+       if (left_len < sizeof(*ev)) {
                ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
                return;
        }
 
-       left_len -= sizeof(*comb_event);
+       left_len -= sizeof(*ev);
 
        /* Check number of included events */
-       comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data;
-       count = __le32_to_cpu(comb_event->hdr.num_phyerr_events);
+       ev = (const struct wmi_phyerr_event *)skb->data;
+       count = __le32_to_cpu(ev->num_phyerrs);
 
-       tsf = __le32_to_cpu(comb_event->hdr.tsf_u32);
+       tsf = __le32_to_cpu(ev->tsf_u32);
        tsf <<= 32;
-       tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32);
+       tsf |= __le32_to_cpu(ev->tsf_l32);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi event phyerr count %d tsf64 0x%llX\n",
                   count, tsf);
 
-       event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp;
+       phyerr = ev->phyerrs;
        for (i = 0; i < count; i++) {
                /* Check if we can read event header */
-               if (left_len < sizeof(*event)) {
+               if (left_len < sizeof(*phyerr)) {
                        ath10k_warn(ar, "single event (%d) wrong head len\n",
                                    i);
                        return;
                }
 
-               left_len -= sizeof(*event);
+               left_len -= sizeof(*phyerr);
 
-               buf_len = __le32_to_cpu(event->hdr.buf_len);
-               phy_err_code = event->hdr.phy_err_code;
+               buf_len = __le32_to_cpu(phyerr->buf_len);
+               phy_err_code = phyerr->phy_err_code;
 
                if (left_len < buf_len) {
                        ath10k_warn(ar, "single event (%d) wrong buf len\n", i);
@@ -1969,20 +2195,20 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
 
                switch (phy_err_code) {
                case PHY_ERROR_RADAR:
-                       ath10k_wmi_event_dfs(ar, event, tsf);
+                       ath10k_wmi_event_dfs(ar, phyerr, tsf);
                        break;
                case PHY_ERROR_SPECTRAL_SCAN:
-                       ath10k_wmi_event_spectral_scan(ar, event, tsf);
+                       ath10k_wmi_event_spectral_scan(ar, phyerr, tsf);
                        break;
                case PHY_ERROR_FALSE_RADAR_EXT:
-                       ath10k_wmi_event_dfs(ar, event, tsf);
-                       ath10k_wmi_event_spectral_scan(ar, event, tsf);
+                       ath10k_wmi_event_dfs(ar, phyerr, tsf);
+                       ath10k_wmi_event_spectral_scan(ar, phyerr, tsf);
                        break;
                default:
                        break;
                }
 
-               event += sizeof(*event) + buf_len;
+               phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len;
        }
 }
 
@@ -2163,30 +2389,113 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
        return 0;
 }
 
-static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
-                                             struct sk_buff *skb)
+static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
+                                          struct wmi_svc_rdy_ev_arg *arg)
 {
-       struct wmi_service_ready_event *ev = (void *)skb->data;
+       struct wmi_service_ready_event *ev;
+       size_t i, n;
+
+       if (skb->len < sizeof(*ev))
+               return -EPROTO;
+
+       ev = (void *)skb->data;
+       skb_pull(skb, sizeof(*ev));
+       arg->min_tx_power = ev->hw_min_tx_power;
+       arg->max_tx_power = ev->hw_max_tx_power;
+       arg->ht_cap = ev->ht_cap_info;
+       arg->vht_cap = ev->vht_cap_info;
+       arg->sw_ver0 = ev->sw_version;
+       arg->sw_ver1 = ev->sw_version_1;
+       arg->phy_capab = ev->phy_capability;
+       arg->num_rf_chains = ev->num_rf_chains;
+       arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+       arg->num_mem_reqs = ev->num_mem_reqs;
+       arg->service_map = ev->wmi_service_bitmap;
+
+       n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
+                 ARRAY_SIZE(arg->mem_reqs));
+       for (i = 0; i < n; i++)
+               arg->mem_reqs[i] = &ev->mem_reqs[i];
+
+       if (skb->len <
+           __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
+               return -EPROTO;
+
+       return 0;
+}
+
+static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
+                                         struct wmi_svc_rdy_ev_arg *arg)
+{
+       struct wmi_10x_service_ready_event *ev;
+       int i, n;
+
+       if (skb->len < sizeof(*ev))
+               return -EPROTO;
+
+       ev = (void *)skb->data;
+       skb_pull(skb, sizeof(*ev));
+       arg->min_tx_power = ev->hw_min_tx_power;
+       arg->max_tx_power = ev->hw_max_tx_power;
+       arg->ht_cap = ev->ht_cap_info;
+       arg->vht_cap = ev->vht_cap_info;
+       arg->sw_ver0 = ev->sw_version;
+       arg->phy_capab = ev->phy_capability;
+       arg->num_rf_chains = ev->num_rf_chains;
+       arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd;
+       arg->num_mem_reqs = ev->num_mem_reqs;
+       arg->service_map = ev->wmi_service_bitmap;
+
+       n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs),
+                 ARRAY_SIZE(arg->mem_reqs));
+       for (i = 0; i < n; i++)
+               arg->mem_reqs[i] = &ev->mem_reqs[i];
+
+       if (skb->len <
+           __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0]))
+               return -EPROTO;
+
+       return 0;
+}
+
+static void ath10k_wmi_event_service_ready(struct ath10k *ar,
+                                          struct sk_buff *skb)
+{
+       struct wmi_svc_rdy_ev_arg arg = {};
+       u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
        DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
+       int ret;
+
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
+               wmi_10x_svc_map(arg.service_map, svc_bmap);
+       } else {
+               ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
+               wmi_main_svc_map(arg.service_map, svc_bmap);
+       }
 
-       if (skb->len < sizeof(*ev)) {
-               ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
-                           skb->len, sizeof(*ev));
+       if (ret) {
+               ath10k_warn(ar, "failed to parse service ready: %d\n", ret);
                return;
        }
 
-       ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
-       ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
-       ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
-       ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
+       ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power);
+       ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power);
+       ar->ht_cap_info = __le32_to_cpu(arg.ht_cap);
+       ar->vht_cap_info = __le32_to_cpu(arg.vht_cap);
        ar->fw_version_major =
-               (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
-       ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
+               (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24;
+       ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff);
        ar->fw_version_release =
-               (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16;
-       ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff);
-       ar->phy_capability = __le32_to_cpu(ev->phy_capability);
-       ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
+               (__le32_to_cpu(arg.sw_ver1) & 0xffff0000) >> 16;
+       ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff);
+       ar->phy_capability = __le32_to_cpu(arg.phy_capab);
+       ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains);
+       ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd);
+
+       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
+       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
+                       arg.service_map, sizeof(arg.service_map));
 
        /* only manually set fw features when not using FW IE format */
        if (ar->fw_api == 1 && ar->fw_version_build > 636)
@@ -2198,13 +2507,8 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
                ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
        }
 
-       ar->ath_common.regulatory.current_rd =
-               __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
-
-       wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap);
-       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
-       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
-                       ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
+       ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1;
+       ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1;
 
        if (strlen(ar->hw->wiphy->fw_version) == 0) {
                snprintf(ar->hw->wiphy->fw_version,
@@ -2216,93 +2520,18 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
                         ar->fw_version_build);
        }
 
-       /* FIXME: it probably should be better to support this */
-       if (__le32_to_cpu(ev->num_mem_reqs) > 0) {
-               ath10k_warn(ar, "target requested %d memory chunks; ignoring\n",
-                           __le32_to_cpu(ev->num_mem_reqs));
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI,
-                  "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
-                  __le32_to_cpu(ev->sw_version),
-                  __le32_to_cpu(ev->sw_version_1),
-                  __le32_to_cpu(ev->abi_version),
-                  __le32_to_cpu(ev->phy_capability),
-                  __le32_to_cpu(ev->ht_cap_info),
-                  __le32_to_cpu(ev->vht_cap_info),
-                  __le32_to_cpu(ev->vht_supp_mcs),
-                  __le32_to_cpu(ev->sys_cap_info),
-                  __le32_to_cpu(ev->num_mem_reqs),
-                  __le32_to_cpu(ev->num_rf_chains));
-
-       complete(&ar->wmi.service_ready);
-}
-
-static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
-                                                 struct sk_buff *skb)
-{
-       u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
-       int ret;
-       struct wmi_service_ready_event_10x *ev = (void *)skb->data;
-       DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {};
-
-       if (skb->len < sizeof(*ev)) {
-               ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n",
-                           skb->len, sizeof(*ev));
-               return;
-       }
-
-       ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power);
-       ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power);
-       ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info);
-       ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info);
-       ar->fw_version_major =
-               (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24;
-       ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff);
-       ar->phy_capability = __le32_to_cpu(ev->phy_capability);
-       ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
-
-       if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
-               ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
-                           ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
-               ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM;
-       }
-
-       ar->ath_common.regulatory.current_rd =
-               __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd);
-
-       wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap);
-       ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap));
-       ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
-                       ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap));
-
-       if (strlen(ar->hw->wiphy->fw_version) == 0) {
-               snprintf(ar->hw->wiphy->fw_version,
-                        sizeof(ar->hw->wiphy->fw_version),
-                        "%u.%u",
-                        ar->fw_version_major,
-                        ar->fw_version_minor);
-       }
-
-       num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs);
-
-       if (num_mem_reqs > ATH10K_MAX_MEM_REQS) {
+       num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs);
+       if (num_mem_reqs > WMI_MAX_MEM_REQS) {
                ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
                            num_mem_reqs);
                return;
        }
 
-       if (!num_mem_reqs)
-               goto exit;
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n",
-                  num_mem_reqs);
-
        for (i = 0; i < num_mem_reqs; ++i) {
-               req_id = __le32_to_cpu(ev->mem_reqs[i].req_id);
-               num_units = __le32_to_cpu(ev->mem_reqs[i].num_units);
-               unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size);
-               num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info);
+               req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id);
+               num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units);
+               unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size);
+               num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info);
 
                if (num_unit_info & NUM_UNITS_IS_NUM_PEERS)
                        /* number of units to allocate is number of
@@ -2316,7 +2545,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
                ath10k_dbg(ar, ATH10K_DBG_WMI,
                           "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
                           req_id,
-                          __le32_to_cpu(ev->mem_reqs[i].num_units),
+                          __le32_to_cpu(arg.mem_reqs[i]->num_units),
                           num_unit_info,
                           unit_size,
                           num_units);
@@ -2327,23 +2556,23 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar,
                        return;
        }
 
-exit:
        ath10k_dbg(ar, ATH10K_DBG_WMI,
-                  "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n",
-                  __le32_to_cpu(ev->sw_version),
-                  __le32_to_cpu(ev->abi_version),
-                  __le32_to_cpu(ev->phy_capability),
-                  __le32_to_cpu(ev->ht_cap_info),
-                  __le32_to_cpu(ev->vht_cap_info),
-                  __le32_to_cpu(ev->vht_supp_mcs),
-                  __le32_to_cpu(ev->sys_cap_info),
-                  __le32_to_cpu(ev->num_mem_reqs),
-                  __le32_to_cpu(ev->num_rf_chains));
+                  "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
+                  __le32_to_cpu(arg.min_tx_power),
+                  __le32_to_cpu(arg.max_tx_power),
+                  __le32_to_cpu(arg.ht_cap),
+                  __le32_to_cpu(arg.vht_cap),
+                  __le32_to_cpu(arg.sw_ver0),
+                  __le32_to_cpu(arg.sw_ver1),
+                  __le32_to_cpu(arg.phy_capab),
+                  __le32_to_cpu(arg.num_rf_chains),
+                  __le32_to_cpu(arg.eeprom_rd),
+                  __le32_to_cpu(arg.num_mem_reqs));
 
        complete(&ar->wmi.service_ready);
 }
 
-static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data;
 
@@ -2466,10 +2695,10 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_event_vdev_install_key_complete(ar, skb);
                break;
        case WMI_SERVICE_READY_EVENTID:
-               ath10k_wmi_service_ready_event_rx(ar, skb);
+               ath10k_wmi_event_service_ready(ar, skb);
                break;
        case WMI_READY_EVENTID:
-               ath10k_wmi_ready_event_rx(ar, skb);
+               ath10k_wmi_event_ready(ar, skb);
                break;
        default:
                ath10k_warn(ar, "Unknown eventid: %d\n", id);
@@ -2586,10 +2815,10 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_event_vdev_resume_req(ar, skb);
                break;
        case WMI_10X_SERVICE_READY_EVENTID:
-               ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+               ath10k_wmi_event_service_ready(ar, skb);
                break;
        case WMI_10X_READY_EVENTID:
-               ath10k_wmi_ready_event_rx(ar, skb);
+               ath10k_wmi_event_ready(ar, skb);
                break;
        case WMI_10X_PDEV_UTF_EVENTID:
                /* ignore utf events */
@@ -2697,10 +2926,10 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_event_vdev_resume_req(ar, skb);
                break;
        case WMI_10_2_SERVICE_READY_EVENTID:
-               ath10k_wmi_10x_service_ready_event_rx(ar, skb);
+               ath10k_wmi_event_service_ready(ar, skb);
                break;
        case WMI_10_2_READY_EVENTID:
-               ath10k_wmi_ready_event_rx(ar, skb);
+               ath10k_wmi_event_ready(ar, skb);
                break;
        case WMI_10_2_RTT_KEEPALIVE_EVENTID:
        case WMI_10_2_GPIO_INPUT_EVENTID:
@@ -2732,45 +2961,6 @@ static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
        }
 }
 
-/* WMI Initialization functions */
-int ath10k_wmi_attach(struct ath10k *ar)
-{
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
-               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
-                       ar->wmi.cmd = &wmi_10_2_cmd_map;
-               else
-                       ar->wmi.cmd = &wmi_10x_cmd_map;
-
-               ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
-               ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
-       } else {
-               ar->wmi.cmd = &wmi_cmd_map;
-               ar->wmi.vdev_param = &wmi_vdev_param_map;
-               ar->wmi.pdev_param = &wmi_pdev_param_map;
-       }
-
-       init_completion(&ar->wmi.service_ready);
-       init_completion(&ar->wmi.unified_ready);
-       init_waitqueue_head(&ar->wmi.tx_credits_wq);
-
-       return 0;
-}
-
-void ath10k_wmi_detach(struct ath10k *ar)
-{
-       int i;
-
-       /* free the host memory chunks requested by firmware */
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               dma_free_coherent(ar->dev,
-                                 ar->wmi.mem_chunks[i].len,
-                                 ar->wmi.mem_chunks[i].vaddr,
-                                 ar->wmi.mem_chunks[i].paddr);
-       }
-
-       ar->wmi.num_mem_chunks = 0;
-}
-
 int ath10k_wmi_connect(struct ath10k *ar)
 {
        int status;
@@ -2865,42 +3055,6 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
                                                         ctl2g, ctl5g);
 }
 
-int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
-                               const struct wmi_channel_arg *arg)
-{
-       struct wmi_set_channel_cmd *cmd;
-       struct sk_buff *skb;
-       u32 ch_flags = 0;
-
-       if (arg->passive)
-               return -EINVAL;
-
-       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
-       if (!skb)
-               return -ENOMEM;
-
-       if (arg->chan_radar)
-               ch_flags |= WMI_CHAN_FLAG_DFS;
-
-       cmd = (struct wmi_set_channel_cmd *)skb->data;
-       cmd->chan.mhz               = __cpu_to_le32(arg->freq);
-       cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq);
-       cmd->chan.mode              = arg->mode;
-       cmd->chan.flags            |= __cpu_to_le32(ch_flags);
-       cmd->chan.min_power         = arg->min_power;
-       cmd->chan.max_power         = arg->max_power;
-       cmd->chan.reg_power         = arg->max_reg_power;
-       cmd->chan.reg_classid       = arg->reg_class_id;
-       cmd->chan.antenna_max       = arg->max_antenna_gain;
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI,
-                  "wmi set channel mode %d freq %d\n",
-                  arg->mode, arg->freq);
-
-       return ath10k_wmi_cmd_send(ar, skb,
-                                  ar->wmi.cmd->pdev_set_channel_cmdid);
-}
-
 int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
 {
        struct wmi_pdev_suspend_cmd *cmd;
@@ -2951,13 +3105,34 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
 }
 
+static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+                                          struct wmi_host_mem_chunks *chunks)
+{
+       struct host_memory_chunk *chunk;
+       int i;
+
+       chunks->count = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+               chunk = &chunks->items[i];
+               chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
+               chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len);
+               chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
+
+               ath10k_dbg(ar, ATH10K_DBG_WMI,
+                          "wmi chunk %d len %d requested, addr 0x%llx\n",
+                          i,
+                          ar->wmi.mem_chunks[i].len,
+                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
+       }
+}
+
 static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 {
        struct wmi_init_cmd *cmd;
        struct sk_buff *buf;
        struct wmi_resource_config config = {};
        u32 len, val;
-       int i;
 
        config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
        config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS);
@@ -3019,32 +3194,8 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
 
        cmd = (struct wmi_init_cmd *)buf->data;
 
-       if (ar->wmi.num_mem_chunks == 0) {
-               cmd->num_host_mem_chunks = 0;
-               goto out;
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
-                  ar->wmi.num_mem_chunks);
-
-       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               cmd->host_mem_chunks[i].ptr =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
-               cmd->host_mem_chunks[i].size =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
-               cmd->host_mem_chunks[i].req_id =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
-               ath10k_dbg(ar, ATH10K_DBG_WMI,
-                          "wmi chunk %d len %d requested, addr 0x%llx\n",
-                          i,
-                          ar->wmi.mem_chunks[i].len,
-                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
-       }
-out:
        memcpy(&cmd->resource_config, &config, sizeof(config));
+       ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
@@ -3056,7 +3207,6 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
        struct sk_buff *buf;
        struct wmi_resource_config_10x config = {};
        u32 len, val;
-       int i;
 
        config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
        config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
@@ -3110,32 +3260,8 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
 
        cmd = (struct wmi_init_cmd_10x *)buf->data;
 
-       if (ar->wmi.num_mem_chunks == 0) {
-               cmd->num_host_mem_chunks = 0;
-               goto out;
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
-                  ar->wmi.num_mem_chunks);
-
-       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               cmd->host_mem_chunks[i].ptr =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
-               cmd->host_mem_chunks[i].size =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
-               cmd->host_mem_chunks[i].req_id =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
-               ath10k_dbg(ar, ATH10K_DBG_WMI,
-                          "wmi chunk %d len %d requested, addr 0x%llx\n",
-                          i,
-                          ar->wmi.mem_chunks[i].len,
-                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
-       }
-out:
        memcpy(&cmd->resource_config, &config, sizeof(config));
+       ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
@@ -3147,7 +3273,6 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
        struct sk_buff *buf;
        struct wmi_resource_config_10x config = {};
        u32 len, val;
-       int i;
 
        config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
        config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
@@ -3201,32 +3326,8 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
 
        cmd = (struct wmi_init_cmd_10_2 *)buf->data;
 
-       if (ar->wmi.num_mem_chunks == 0) {
-               cmd->num_host_mem_chunks = 0;
-               goto out;
-       }
-
-       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
-                  ar->wmi.num_mem_chunks);
-
-       cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
-
-       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
-               cmd->host_mem_chunks[i].ptr =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
-               cmd->host_mem_chunks[i].size =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].len);
-               cmd->host_mem_chunks[i].req_id =
-                       __cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
-
-               ath10k_dbg(ar, ATH10K_DBG_WMI,
-                          "wmi chunk %d len %d requested, addr 0x%llx\n",
-                          i,
-                          ar->wmi.mem_chunks[i].len,
-                          (unsigned long long)ar->wmi.mem_chunks[i].paddr);
-       }
-out:
        memcpy(&cmd->resource_config.common, &config, sizeof(config));
+       ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
        return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
@@ -3248,52 +3349,50 @@ int ath10k_wmi_cmd_init(struct ath10k *ar)
        return ret;
 }
 
-static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar,
-                                         const struct wmi_start_scan_arg *arg)
+static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
 {
-       int len;
+       if (arg->ie_len && !arg->ie)
+               return -EINVAL;
+       if (arg->n_channels && !arg->channels)
+               return -EINVAL;
+       if (arg->n_ssids && !arg->ssids)
+               return -EINVAL;
+       if (arg->n_bssids && !arg->bssids)
+               return -EINVAL;
 
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-               len = sizeof(struct wmi_start_scan_cmd_10x);
-       else
-               len = sizeof(struct wmi_start_scan_cmd);
+       if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN)
+               return -EINVAL;
+       if (arg->n_channels > ARRAY_SIZE(arg->channels))
+               return -EINVAL;
+       if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID)
+               return -EINVAL;
+       if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID)
+               return -EINVAL;
 
-       if (arg->ie_len) {
-               if (!arg->ie)
-                       return -EINVAL;
-               if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN)
-                       return -EINVAL;
+       return 0;
+}
 
+static size_t
+ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg)
+{
+       int len = 0;
+
+       if (arg->ie_len) {
                len += sizeof(struct wmi_ie_data);
                len += roundup(arg->ie_len, 4);
        }
 
        if (arg->n_channels) {
-               if (!arg->channels)
-                       return -EINVAL;
-               if (arg->n_channels > ARRAY_SIZE(arg->channels))
-                       return -EINVAL;
-
                len += sizeof(struct wmi_chan_list);
                len += sizeof(__le32) * arg->n_channels;
        }
 
        if (arg->n_ssids) {
-               if (!arg->ssids)
-                       return -EINVAL;
-               if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID)
-                       return -EINVAL;
-
                len += sizeof(struct wmi_ssid_list);
                len += sizeof(struct wmi_ssid) * arg->n_ssids;
        }
 
        if (arg->n_bssids) {
-               if (!arg->bssids)
-                       return -EINVAL;
-               if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID)
-                       return -EINVAL;
-
                len += sizeof(struct wmi_bssid_list);
                len += sizeof(struct wmi_mac_addr) * arg->n_bssids;
        }
@@ -3301,28 +3400,12 @@ static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar,
        return len;
 }
 
-int ath10k_wmi_start_scan(struct ath10k *ar,
-                         const struct wmi_start_scan_arg *arg)
+static void
+ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+                                const struct wmi_start_scan_arg *arg)
 {
-       struct wmi_start_scan_cmd *cmd;
-       struct sk_buff *skb;
-       struct wmi_ie_data *ie;
-       struct wmi_chan_list *channels;
-       struct wmi_ssid_list *ssids;
-       struct wmi_bssid_list *bssids;
        u32 scan_id;
        u32 scan_req_id;
-       int off;
-       int len = 0;
-       int i;
-
-       len = ath10k_wmi_start_scan_calc_len(ar, arg);
-       if (len < 0)
-               return len; /* len contains error code here */
-
-       skb = ath10k_wmi_alloc_skb(ar, len);
-       if (!skb)
-               return -ENOMEM;
 
        scan_id  = WMI_HOST_SCAN_REQ_ID_PREFIX;
        scan_id |= arg->scan_id;
@@ -3330,35 +3413,36 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
        scan_req_id  = WMI_HOST_SCAN_REQUESTOR_ID_PREFIX;
        scan_req_id |= arg->scan_req_id;
 
-       cmd = (struct wmi_start_scan_cmd *)skb->data;
-       cmd->scan_id            = __cpu_to_le32(scan_id);
-       cmd->scan_req_id        = __cpu_to_le32(scan_req_id);
-       cmd->vdev_id            = __cpu_to_le32(arg->vdev_id);
-       cmd->scan_priority      = __cpu_to_le32(arg->scan_priority);
-       cmd->notify_scan_events = __cpu_to_le32(arg->notify_scan_events);
-       cmd->dwell_time_active  = __cpu_to_le32(arg->dwell_time_active);
-       cmd->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive);
-       cmd->min_rest_time      = __cpu_to_le32(arg->min_rest_time);
-       cmd->max_rest_time      = __cpu_to_le32(arg->max_rest_time);
-       cmd->repeat_probe_time  = __cpu_to_le32(arg->repeat_probe_time);
-       cmd->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time);
-       cmd->idle_time          = __cpu_to_le32(arg->idle_time);
-       cmd->max_scan_time      = __cpu_to_le32(arg->max_scan_time);
-       cmd->probe_delay        = __cpu_to_le32(arg->probe_delay);
-       cmd->scan_ctrl_flags    = __cpu_to_le32(arg->scan_ctrl_flags);
-
-       /* TLV list starts after fields included in the struct */
-       /* There's just one filed that differes the two start_scan
-        * structures - burst_duration, which we are not using btw,
-          no point to make the split here, just shift the buffer to fit with
-          given FW */
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
-               off = sizeof(struct wmi_start_scan_cmd_10x);
-       else
-               off = sizeof(struct wmi_start_scan_cmd);
+       cmn->scan_id            = __cpu_to_le32(scan_id);
+       cmn->scan_req_id        = __cpu_to_le32(scan_req_id);
+       cmn->vdev_id            = __cpu_to_le32(arg->vdev_id);
+       cmn->scan_priority      = __cpu_to_le32(arg->scan_priority);
+       cmn->notify_scan_events = __cpu_to_le32(arg->notify_scan_events);
+       cmn->dwell_time_active  = __cpu_to_le32(arg->dwell_time_active);
+       cmn->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive);
+       cmn->min_rest_time      = __cpu_to_le32(arg->min_rest_time);
+       cmn->max_rest_time      = __cpu_to_le32(arg->max_rest_time);
+       cmn->repeat_probe_time  = __cpu_to_le32(arg->repeat_probe_time);
+       cmn->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time);
+       cmn->idle_time          = __cpu_to_le32(arg->idle_time);
+       cmn->max_scan_time      = __cpu_to_le32(arg->max_scan_time);
+       cmn->probe_delay        = __cpu_to_le32(arg->probe_delay);
+       cmn->scan_ctrl_flags    = __cpu_to_le32(arg->scan_ctrl_flags);
+}
+
+static void
+ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
+                              const struct wmi_start_scan_arg *arg)
+{
+       struct wmi_ie_data *ie;
+       struct wmi_chan_list *channels;
+       struct wmi_ssid_list *ssids;
+       struct wmi_bssid_list *bssids;
+       void *ptr = tlvs->tlvs;
+       int i;
 
        if (arg->n_channels) {
-               channels = (void *)skb->data + off;
+               channels = ptr;
                channels->tag = __cpu_to_le32(WMI_CHAN_LIST_TAG);
                channels->num_chan = __cpu_to_le32(arg->n_channels);
 
@@ -3366,12 +3450,12 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
                        channels->channel_list[i].freq =
                                __cpu_to_le16(arg->channels[i]);
 
-               off += sizeof(*channels);
-               off += sizeof(__le32) * arg->n_channels;
+               ptr += sizeof(*channels);
+               ptr += sizeof(__le32) * arg->n_channels;
        }
 
        if (arg->n_ssids) {
-               ssids = (void *)skb->data + off;
+               ssids = ptr;
                ssids->tag = __cpu_to_le32(WMI_SSID_LIST_TAG);
                ssids->num_ssids = __cpu_to_le32(arg->n_ssids);
 
@@ -3383,12 +3467,12 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
                               arg->ssids[i].len);
                }
 
-               off += sizeof(*ssids);
-               off += sizeof(struct wmi_ssid) * arg->n_ssids;
+               ptr += sizeof(*ssids);
+               ptr += sizeof(struct wmi_ssid) * arg->n_ssids;
        }
 
        if (arg->n_bssids) {
-               bssids = (void *)skb->data + off;
+               bssids = ptr;
                bssids->tag = __cpu_to_le32(WMI_BSSID_LIST_TAG);
                bssids->num_bssid = __cpu_to_le32(arg->n_bssids);
 
@@ -3397,23 +3481,57 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
                               arg->bssids[i].bssid,
                               ETH_ALEN);
 
-               off += sizeof(*bssids);
-               off += sizeof(struct wmi_mac_addr) * arg->n_bssids;
+               ptr += sizeof(*bssids);
+               ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids;
        }
 
        if (arg->ie_len) {
-               ie = (void *)skb->data + off;
+               ie = ptr;
                ie->tag = __cpu_to_le32(WMI_IE_TAG);
                ie->ie_len = __cpu_to_le32(arg->ie_len);
                memcpy(ie->ie_data, arg->ie, arg->ie_len);
 
-               off += sizeof(*ie);
-               off += roundup(arg->ie_len, 4);
+               ptr += sizeof(*ie);
+               ptr += roundup(arg->ie_len, 4);
        }
+}
 
-       if (off != skb->len) {
-               dev_kfree_skb(skb);
-               return -EINVAL;
+int ath10k_wmi_start_scan(struct ath10k *ar,
+                         const struct wmi_start_scan_arg *arg)
+{
+       struct sk_buff *skb;
+       size_t len;
+       int ret;
+
+       ret = ath10k_wmi_start_scan_verify(arg);
+       if (ret)
+               return ret;
+
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+               len = sizeof(struct wmi_10x_start_scan_cmd) +
+                     ath10k_wmi_start_scan_tlvs_len(arg);
+       else
+               len = sizeof(struct wmi_start_scan_cmd) +
+                     ath10k_wmi_start_scan_tlvs_len(arg);
+
+       skb = ath10k_wmi_alloc_skb(ar, len);
+       if (!skb)
+               return -ENOMEM;
+
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               struct wmi_10x_start_scan_cmd *cmd;
+
+               cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
+               ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+               ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
+       } else {
+               struct wmi_start_scan_cmd *cmd;
+
+               cmd = (struct wmi_start_scan_cmd *)skb->data;
+               cmd->burst_duration_ms = __cpu_to_le32(0);
+
+               ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+               ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
        }
 
        ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
@@ -3532,7 +3650,6 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
        struct sk_buff *skb;
        const char *cmdname;
        u32 flags = 0;
-       u32 ch_flags = 0;
 
        if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
            cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
@@ -3559,8 +3676,6 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
                flags |= WMI_VDEV_START_HIDDEN_SSID;
        if (arg->pmf_enabled)
                flags |= WMI_VDEV_START_PMF_ENABLED;
-       if (arg->channel.chan_radar)
-               ch_flags |= WMI_CHAN_FLAG_DFS;
 
        cmd = (struct wmi_vdev_start_request_cmd *)skb->data;
        cmd->vdev_id         = __cpu_to_le32(arg->vdev_id);
@@ -3576,18 +3691,7 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
                memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
        }
 
-       cmd->chan.mhz = __cpu_to_le32(arg->channel.freq);
-
-       cmd->chan.band_center_freq1 =
-               __cpu_to_le32(arg->channel.band_center_freq1);
-
-       cmd->chan.mode = arg->channel.mode;
-       cmd->chan.flags |= __cpu_to_le32(ch_flags);
-       cmd->chan.min_power = arg->channel.min_power;
-       cmd->chan.max_power = arg->channel.max_power;
-       cmd->chan.reg_power = arg->channel.max_reg_power;
-       cmd->chan.reg_classid = arg->channel.reg_class_id;
-       cmd->chan.antenna_max = arg->channel.max_antenna_gain;
+       ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel);
 
        ath10k_dbg(ar, ATH10K_DBG_WMI,
                   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
@@ -3968,35 +4072,10 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
        cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
 
        for (i = 0; i < arg->n_channels; i++) {
-               u32 flags = 0;
-
                ch = &arg->channels[i];
                ci = &cmd->chan_info[i];
 
-               if (ch->passive)
-                       flags |= WMI_CHAN_FLAG_PASSIVE;
-               if (ch->allow_ibss)
-                       flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED;
-               if (ch->allow_ht)
-                       flags |= WMI_CHAN_FLAG_ALLOW_HT;
-               if (ch->allow_vht)
-                       flags |= WMI_CHAN_FLAG_ALLOW_VHT;
-               if (ch->ht40plus)
-                       flags |= WMI_CHAN_FLAG_HT40_PLUS;
-               if (ch->chan_radar)
-                       flags |= WMI_CHAN_FLAG_DFS;
-
-               ci->mhz               = __cpu_to_le32(ch->freq);
-               ci->band_center_freq1 = __cpu_to_le32(ch->freq);
-               ci->band_center_freq2 = 0;
-               ci->min_power         = ch->min_power;
-               ci->max_power         = ch->max_power;
-               ci->reg_power         = ch->max_reg_power;
-               ci->antenna_max       = ch->max_antenna_gain;
-
-               /* mode & flags share storage */
-               ci->mode              = ch->mode;
-               ci->flags            |= __cpu_to_le32(flags);
+               ath10k_wmi_put_wmi_channel(ci, ch);
        }
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
@@ -4267,3 +4346,74 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
 
        return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
 }
+
+int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
+{
+       struct wmi_pdev_pktlog_enable_cmd *cmd;
+       struct sk_buff *skb;
+
+       skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       ev_bitmap &= ATH10K_PKTLOG_ANY;
+       ath10k_dbg(ar, ATH10K_DBG_WMI,
+                  "wmi enable pktlog filter:%x\n", ev_bitmap);
+
+       cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data;
+       cmd->ev_bitmap = __cpu_to_le32(ev_bitmap);
+       return ath10k_wmi_cmd_send(ar, skb,
+                                  ar->wmi.cmd->pdev_pktlog_enable_cmdid);
+}
+
+int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
+{
+       struct sk_buff *skb;
+
+       skb = ath10k_wmi_alloc_skb(ar, 0);
+       if (!skb)
+               return -ENOMEM;
+
+       ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n");
+
+       return ath10k_wmi_cmd_send(ar, skb,
+                                  ar->wmi.cmd->pdev_pktlog_disable_cmdid);
+}
+
+int ath10k_wmi_attach(struct ath10k *ar)
+{
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
+                       ar->wmi.cmd = &wmi_10_2_cmd_map;
+               else
+                       ar->wmi.cmd = &wmi_10x_cmd_map;
+
+               ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
+               ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+       } else {
+               ar->wmi.cmd = &wmi_cmd_map;
+               ar->wmi.vdev_param = &wmi_vdev_param_map;
+               ar->wmi.pdev_param = &wmi_pdev_param_map;
+       }
+
+       init_completion(&ar->wmi.service_ready);
+       init_completion(&ar->wmi.unified_ready);
+       init_waitqueue_head(&ar->wmi.tx_credits_wq);
+
+       return 0;
+}
+
+void ath10k_wmi_detach(struct ath10k *ar)
+{
+       int i;
+
+       /* free the host memory chunks requested by firmware */
+       for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
+               dma_free_coherent(ar->dev,
+                                 ar->wmi.mem_chunks[i].len,
+                                 ar->wmi.mem_chunks[i].vaddr,
+                                 ar->wmi.mem_chunks[i].paddr);
+       }
+
+       ar->wmi.num_mem_chunks = 0;
+}
index 86f5ebccfe79c26a248935de47c6cc13f1b2cbd8..a38d788a6101b3e87a93a8349340997c56f4e209 100644 (file)
@@ -1428,11 +1428,11 @@ struct wmi_service_ready_event {
         * where FW can access this memory directly (or) by DMA.
         */
        __le32 num_mem_reqs;
-       struct wlan_host_mem_req mem_reqs[1];
+       struct wlan_host_mem_req mem_reqs[0];
 } __packed;
 
 /* This is the definition from 10.X firmware branch */
-struct wmi_service_ready_event_10x {
+struct wmi_10x_service_ready_event {
        __le32 sw_version;
        __le32 abi_version;
 
@@ -1467,7 +1467,7 @@ struct wmi_service_ready_event_10x {
         */
        __le32 num_mem_reqs;
 
-       struct wlan_host_mem_req mem_reqs[1];
+       struct wlan_host_mem_req mem_reqs[0];
 } __packed;
 
 #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
@@ -1883,38 +1883,26 @@ struct host_memory_chunk {
        __le32 size;
 } __packed;
 
+struct wmi_host_mem_chunks {
+       __le32 count;
+       /* some fw revisions require at least 1 chunk regardless of count */
+       struct host_memory_chunk items[1];
+} __packed;
+
 struct wmi_init_cmd {
        struct wmi_resource_config resource_config;
-       __le32 num_host_mem_chunks;
-
-       /*
-        * variable number of host memory chunks.
-        * This should be the last element in the structure
-        */
-       struct host_memory_chunk host_mem_chunks[1];
+       struct wmi_host_mem_chunks mem_chunks;
 } __packed;
 
 /* _10x stucture is from 10.X FW API */
 struct wmi_init_cmd_10x {
        struct wmi_resource_config_10x resource_config;
-       __le32 num_host_mem_chunks;
-
-       /*
-        * variable number of host memory chunks.
-        * This should be the last element in the structure
-        */
-       struct host_memory_chunk host_mem_chunks[1];
+       struct wmi_host_mem_chunks mem_chunks;
 } __packed;
 
 struct wmi_init_cmd_10_2 {
        struct wmi_resource_config_10_2 resource_config;
-       __le32 num_host_mem_chunks;
-
-       /*
-        * variable number of host memory chunks.
-        * This should be the last element in the structure
-        */
-       struct host_memory_chunk host_mem_chunks[1];
+       struct wmi_host_mem_chunks mem_chunks;
 } __packed;
 
 struct wmi_chan_list_entry {
@@ -1974,7 +1962,7 @@ enum wmi_scan_priority {
        WMI_SCAN_PRIORITY_COUNT   /* number of priorities supported */
 };
 
-struct wmi_start_scan_cmd {
+struct wmi_start_scan_common {
        /* Scan ID */
        __le32 scan_id;
        /* Scan requestor ID */
@@ -2032,95 +2020,25 @@ struct wmi_start_scan_cmd {
        __le32 probe_delay;
        /* Scan control flags */
        __le32 scan_ctrl_flags;
-
-       /* Burst duration time in msecs */
-       __le32 burst_duration;
-       /*
-        * TLV (tag length value )  paramerters follow the scan_cmd structure.
-        * TLV can contain channel list, bssid list, ssid list and
-        * ie. the TLV tags are defined above;
-        */
 } __packed;
 
-/* This is the definition from 10.X firmware branch */
-struct wmi_start_scan_cmd_10x {
-       /* Scan ID */
-       __le32 scan_id;
-
-       /* Scan requestor ID */
-       __le32 scan_req_id;
-
-       /* VDEV id(interface) that is requesting scan */
-       __le32 vdev_id;
-
-       /* Scan Priority, input to scan scheduler */
-       __le32 scan_priority;
-
-       /* Scan events subscription */
-       __le32 notify_scan_events;
-
-       /* dwell time in msec on active channels */
-       __le32 dwell_time_active;
-
-       /* dwell time in msec on passive channels */
-       __le32 dwell_time_passive;
-
-       /*
-        * min time in msec on the BSS channel,only valid if atleast one
-        * VDEV is active
-        */
-       __le32 min_rest_time;
-
-       /*
-        * max rest time in msec on the BSS channel,only valid if at least
-        * one VDEV is active
-        */
-       /*
-        * the scanner will rest on the bss channel at least min_rest_time
-        * after min_rest_time the scanner will start checking for tx/rx
-        * activity on all VDEVs. if there is no activity the scanner will
-        * switch to off channel. if there is activity the scanner will let
-        * the radio on the bss channel until max_rest_time expires.at
-        * max_rest_time scanner will switch to off channel irrespective of
-        * activity. activity is determined by the idle_time parameter.
-        */
-       __le32 max_rest_time;
-
-       /*
-        * time before sending next set of probe requests.
-        * The scanner keeps repeating probe requests transmission with
-        * period specified by repeat_probe_time.
-        * The number of probe requests specified depends on the ssid_list
-        * and bssid_list
-        */
-       __le32 repeat_probe_time;
-
-       /* time in msec between 2 consequetive probe requests with in a set. */
-       __le32 probe_spacing_time;
-
-       /*
-        * data inactivity time in msec on bss channel that will be used by
-        * scanner for measuring the inactivity.
-        */
-       __le32 idle_time;
-
-       /* maximum time in msec allowed for scan  */
-       __le32 max_scan_time;
-
-       /*
-        * delay in msec before sending first probe request after switching
-        * to a channel
+struct wmi_start_scan_tlvs {
+       /* TLV parameters. These includes channel list, ssid list, bssid list,
+        * extra ies.
         */
-       __le32 probe_delay;
+       u8 tlvs[0];
+} __packed;
 
-       /* Scan control flags */
-       __le32 scan_ctrl_flags;
+struct wmi_start_scan_cmd {
+       struct wmi_start_scan_common common;
+       __le32 burst_duration_ms;
+       struct wmi_start_scan_tlvs tlvs;
+} __packed;
 
-       /*
-        * TLV (tag length value )  paramerters follow the scan_cmd structure.
-        * TLV can contain channel list, bssid list, ssid list and
-        * ie. the TLV tags are defined above;
-        */
+/* This is the definition from 10.X firmware branch */
+struct wmi_10x_start_scan_cmd {
+       struct wmi_start_scan_common common;
+       struct wmi_start_scan_tlvs tlvs;
 } __packed;
 
 struct wmi_ssid_arg {
@@ -2306,94 +2224,25 @@ struct wmi_mgmt_rx_event_v2 {
 #define PHY_ERROR_FALSE_RADAR_EXT              0x24
 #define PHY_ERROR_RADAR                                0x05
 
-struct wmi_single_phyerr_rx_hdr {
-       /* TSF timestamp */
+struct wmi_phyerr {
        __le32 tsf_timestamp;
-
-       /*
-        * Current freq1, freq2
-        *
-        * [7:0]:    freq1[lo]
-        * [15:8] :   freq1[hi]
-        * [23:16]:   freq2[lo]
-        * [31:24]:   freq2[hi]
-        */
        __le16 freq1;
        __le16 freq2;
-
-       /*
-        * Combined RSSI over all chains and channel width for this PHY error
-        *
-        * [7:0]: RSSI combined
-        * [15:8]: Channel width (MHz)
-        * [23:16]: PHY error code
-        * [24:16]: reserved (future use)
-        */
        u8 rssi_combined;
        u8 chan_width_mhz;
        u8 phy_err_code;
        u8 rsvd0;
-
-       /*
-        * RSSI on chain 0 through 3
-        *
-        * This is formatted the same as the PPDU_START RX descriptor
-        * field:
-        *
-        * [7:0]:   pri20
-        * [15:8]:  sec20
-        * [23:16]: sec40
-        * [31:24]: sec80
-        */
-
-       __le32 rssi_chain0;
-       __le32 rssi_chain1;
-       __le32 rssi_chain2;
-       __le32 rssi_chain3;
-
-       /*
-        * Last calibrated NF value for chain 0 through 3
-        *
-        * nf_list_1:
-        *
-        * + [15:0] - chain 0
-        * + [31:16] - chain 1
-        *
-        * nf_list_2:
-        *
-        * + [15:0] - chain 2
-        * + [31:16] - chain 3
-        */
-       __le32 nf_list_1;
-       __le32 nf_list_2;
-
-       /* Length of the frame */
+       __le32 rssi_chains[4];
+       __le16 nf_chains[4];
        __le32 buf_len;
+       u8 buf[0];
 } __packed;
 
-struct wmi_single_phyerr_rx_event {
-       /* Phy error event header */
-       struct wmi_single_phyerr_rx_hdr hdr;
-       /* frame buffer */
-       u8 bufp[0];
-} __packed;
-
-struct wmi_comb_phyerr_rx_hdr {
-       /* Phy error phy error count */
-       __le32 num_phyerr_events;
+struct wmi_phyerr_event {
+       __le32 num_phyerrs;
        __le32 tsf_l32;
        __le32 tsf_u32;
-} __packed;
-
-struct wmi_comb_phyerr_rx_event {
-       /* Phy error phy error count */
-       struct wmi_comb_phyerr_rx_hdr hdr;
-       /*
-        * frame buffer - contains multiple payloads in the order:
-        *                    header - payload, header - payload...
-        *  (The header is of type: wmi_single_phyerr_rx_hdr)
-        */
-       u8 bufp[0];
+       struct wmi_phyerr phyerrs[0];
 } __packed;
 
 #define PHYERR_TLV_SIG                         0xBB
@@ -2908,11 +2757,6 @@ enum wmi_tp_scale {
        WMI_TP_SCALE_SIZE   = 5,        /* max num of enum     */
 };
 
-struct wmi_set_channel_cmd {
-       /* channel (only frequency and mode info are used) */
-       struct wmi_channel chan;
-} __packed;
-
 struct wmi_pdev_chanlist_update_event {
        /* number of channels */
        __le32 num_chan;
@@ -2943,6 +2787,10 @@ struct wmi_pdev_set_channel_cmd {
        struct wmi_channel chan;
 } __packed;
 
+struct wmi_pdev_pktlog_enable_cmd {
+       __le32 ev_bitmap;
+} __packed;
+
 /* Customize the DSCP (bit) to TID (0-7) mapping for QOS */
 #define WMI_DSCP_MAP_MAX    (64)
 struct wmi_pdev_set_dscp_tid_map_cmd {
@@ -3177,7 +3025,7 @@ struct wmi_stats_event {
  * PDEV statistics
  * TODO: add all PDEV stats here
  */
-struct wmi_pdev_stats_old {
+struct wmi_pdev_stats {
        __le32 chan_nf;        /* Channel noise floor */
        __le32 tx_frame_count; /* TX frame count */
        __le32 rx_frame_count; /* RX frame count */
@@ -3188,15 +3036,8 @@ struct wmi_pdev_stats_old {
        struct wal_dbg_stats wal; /* WAL dbg stats */
 } __packed;
 
-struct wmi_pdev_stats_10x {
-       __le32 chan_nf;        /* Channel noise floor */
-       __le32 tx_frame_count; /* TX frame count */
-       __le32 rx_frame_count; /* RX frame count */
-       __le32 rx_clear_count; /* rx clear count */
-       __le32 cycle_count;    /* cycle count */
-       __le32 phy_err_count;  /* Phy error count */
-       __le32 chan_tx_pwr;    /* channel tx power */
-       struct wal_dbg_stats wal; /* WAL dbg stats */
+struct wmi_10x_pdev_stats {
+       struct wmi_pdev_stats old;
        __le32 ack_rx_bad;
        __le32 rts_bad;
        __le32 rts_good;
@@ -3217,16 +3058,14 @@ struct wmi_vdev_stats {
  * peer statistics.
  * TODO: add more stats
  */
-struct wmi_peer_stats_old {
+struct wmi_peer_stats {
        struct wmi_mac_addr peer_macaddr;
        __le32 peer_rssi;
        __le32 peer_tx_rate;
 } __packed;
 
-struct wmi_peer_stats_10x {
-       struct wmi_mac_addr peer_macaddr;
-       __le32 peer_rssi;
-       __le32 peer_tx_rate;
+struct wmi_10x_peer_stats {
+       struct wmi_peer_stats old;
        __le32 peer_rx_rate;
 } __packed;
 
@@ -4719,8 +4558,26 @@ struct wmi_dbglog_cfg_cmd {
 /* By default disable power save for IBSS */
 #define ATH10K_DEFAULT_ATIM 0
 
+#define WMI_MAX_MEM_REQS 16
+
+struct wmi_svc_rdy_ev_arg {
+       __le32 min_tx_power;
+       __le32 max_tx_power;
+       __le32 ht_cap;
+       __le32 vht_cap;
+       __le32 sw_ver0;
+       __le32 sw_ver1;
+       __le32 phy_capab;
+       __le32 num_rf_chains;
+       __le32 eeprom_rd;
+       __le32 num_mem_reqs;
+       const __le32 *service_map;
+       const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
+};
+
 struct ath10k;
 struct ath10k_vif;
+struct ath10k_fw_stats;
 
 int ath10k_wmi_attach(struct ath10k *ar);
 void ath10k_wmi_detach(struct ath10k *ar);
@@ -4732,8 +4589,6 @@ int ath10k_wmi_connect(struct ath10k *ar);
 struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
 int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
 
-int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
-                               const struct wmi_channel_arg *);
 int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
 int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
 int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
@@ -4794,5 +4649,9 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
                             enum wmi_force_fw_hang_type type, u32 delay_ms);
 int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
 int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
+int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
+                            struct ath10k_fw_stats *stats);
+int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list);
+int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar);
 
 #endif /* _WMI_H_ */
index ba60e37213eb1d289fa983e8eacbce48c1616b0a..7a5337877a0c507d5c94b2002b2c4e7e9577d3f3 100644 (file)
@@ -2976,11 +2976,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev,
-                             const u8 *mac)
+                             struct station_del_parameters *params)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
-       const u8 *addr = mac ? mac : bcast_addr;
+       const u8 *addr = params->mac ? params->mac : bcast_addr;
 
        return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH,
                                      addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
index 05debf700a846db00f55e0071df53e207d2e6c63..4f82e8632d37ba10a321e3182b6bb8ffa7d594f7 100644 (file)
@@ -22,7 +22,7 @@
 
 #define ATH6KL_MAX_IE                  256
 
-__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);
+__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...);
 
 /*
  * Reflects the version of binary interface exposed by ATH6KL target
index 55c4064dd5067f26b8dfaf54689f85c9eb67a88e..81ba48d2938b2cfc3f11d22e6fb723a8f03f82e5 100644 (file)
@@ -37,76 +37,64 @@ struct ath6kl_fwlog_slot {
 
 #define ATH6KL_FWLOG_VALID_MASK 0x1ffff
 
-int ath6kl_printk(const char *level, const char *fmt, ...)
+void ath6kl_printk(const char *level, const char *fmt, ...)
 {
        struct va_format vaf;
        va_list args;
-       int rtn;
 
        va_start(args, fmt);
 
        vaf.fmt = fmt;
        vaf.va = &args;
 
-       rtn = printk("%sath6kl: %pV", level, &vaf);
+       printk("%sath6kl: %pV", level, &vaf);
 
        va_end(args);
-
-       return rtn;
 }
 EXPORT_SYMBOL(ath6kl_printk);
 
-int ath6kl_info(const char *fmt, ...)
+void ath6kl_info(const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
        };
        va_list args;
-       int ret;
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = ath6kl_printk(KERN_INFO, "%pV", &vaf);
+       ath6kl_printk(KERN_INFO, "%pV", &vaf);
        trace_ath6kl_log_info(&vaf);
        va_end(args);
-
-       return ret;
 }
 EXPORT_SYMBOL(ath6kl_info);
 
-int ath6kl_err(const char *fmt, ...)
+void ath6kl_err(const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
        };
        va_list args;
-       int ret;
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = ath6kl_printk(KERN_ERR, "%pV", &vaf);
+       ath6kl_printk(KERN_ERR, "%pV", &vaf);
        trace_ath6kl_log_err(&vaf);
        va_end(args);
-
-       return ret;
 }
 EXPORT_SYMBOL(ath6kl_err);
 
-int ath6kl_warn(const char *fmt, ...)
+void ath6kl_warn(const char *fmt, ...)
 {
        struct va_format vaf = {
                .fmt = fmt,
        };
        va_list args;
-       int ret;
 
        va_start(args, fmt);
        vaf.va = &args;
-       ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf);
+       ath6kl_printk(KERN_WARNING, "%pV", &vaf);
        trace_ath6kl_log_warn(&vaf);
        va_end(args);
-
-       return ret;
 }
 EXPORT_SYMBOL(ath6kl_warn);
 
index e194c10d9f0071725c1c5eba917347ae8209b0a0..19106ed28961643870d36d95456ee80b3af6ec18 100644 (file)
@@ -50,10 +50,10 @@ enum ATH6K_DEBUG_MASK {
 };
 
 extern unsigned int debug_mask;
-__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...);
-__printf(1, 2) int ath6kl_info(const char *fmt, ...);
-__printf(1, 2) int ath6kl_err(const char *fmt, ...);
-__printf(1, 2) int ath6kl_warn(const char *fmt, ...);
+__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...);
+__printf(1, 2) void ath6kl_info(const char *fmt, ...);
+__printf(1, 2) void ath6kl_err(const char *fmt, ...);
+__printf(1, 2) void ath6kl_warn(const char *fmt, ...);
 
 enum ath6kl_war {
        ATH6KL_WAR_INVALID_RATE,
@@ -81,10 +81,9 @@ int ath6kl_debug_init_fs(struct ath6kl *ar);
 void ath6kl_debug_cleanup(struct ath6kl *ar);
 
 #else
-static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
-                            const char *fmt, ...)
+static inline void ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask,
+                             const char *fmt, ...)
 {
-       return 0;
 }
 
 static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask,
index 896e63281b3b8464b9bbdbd5bab6d9d1f09b4302..ca101d7cb99faf09b269c4f517c009c046d7466a 100644 (file)
@@ -148,6 +148,11 @@ config ATH9K_CHANNEL_CONTEXT
         for multi-channel concurrency. Enable this if P2P PowerSave support
         is required.
 
+config ATH9K_PCOEM
+       bool "Atheros ath9k support for PC OEM cards" if EXPERT
+       depends on ATH9K
+       default y
+
 config ATH9K_HTC
        tristate "Atheros HTC based wireless cards support"
        depends on USB && MAC80211
index 73704c1be736f188dd5cb9f9c746a51dc4d35a94..22b934b07bd4a7cc278f831357e677b7861e67d3 100644 (file)
@@ -32,7 +32,6 @@ ath9k_hw-y:=  \
                ar5008_phy.o \
                ar9002_calib.o \
                ar9003_calib.o \
-               ar9003_rtt.o \
                calib.o \
                eeprom.o \
                eeprom_def.o \
@@ -50,6 +49,8 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o
 ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \
                                           ar9003_mci.o
 
+ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o
+
 ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o
 
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
index b72d0be716dbdc91c56f822f1ec3d352f82e4e80..5829074208fa8173c343c6eaee050c86c8d30c41 100644 (file)
@@ -1190,7 +1190,7 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
 static void ar5008_hw_set_radar_params(struct ath_hw *ah,
                                       struct ath_hw_radar_conf *conf)
 {
-       u32 radar_0 = 0, radar_1 = 0;
+       u32 radar_0 = 0, radar_1;
 
        if (!conf) {
                REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
@@ -1204,6 +1204,9 @@ static void ar5008_hw_set_radar_params(struct ath_hw *ah,
        radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
        radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
 
+       radar_1 = REG_READ(ah, AR_PHY_RADAR_1);
+       radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH |
+                    AR_PHY_RADAR_1_RELPWR_THRESH);
        radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
        radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
        radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
@@ -1225,7 +1228,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
        conf->fir_power = -33;
        conf->radar_rssi = 20;
        conf->pulse_height = 10;
-       conf->pulse_rssi = 24;
+       conf->pulse_rssi = 15;
        conf->pulse_inband = 15;
        conf->pulse_maxlen = 255;
        conf->pulse_inband_step = 12;
index cdc74005650ce9848147ee0e051c64f9df989ffd..42190b67c6719594bcbe57b9d70e02186645bace 100644 (file)
@@ -657,31 +657,29 @@ static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
                ar9280_hw_olc_temp_compensation(ah);
 }
 
-static bool ar9002_hw_calibrate(struct ath_hw *ah,
-                               struct ath9k_channel *chan,
-                               u8 rxchainmask,
-                               bool longcal)
+static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
+                              u8 rxchainmask, bool longcal)
 {
-       bool iscaldone = true;
        struct ath9k_cal_list *currCal = ah->cal_list_curr;
-       bool nfcal, nfcal_pending = false;
+       bool nfcal, nfcal_pending = false, percal_pending;
+       int ret;
 
        nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
        if (ah->caldata)
                nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 
-       if (currCal && !nfcal &&
-           (currCal->calState == CAL_RUNNING ||
-            currCal->calState == CAL_WAITING)) {
-               iscaldone = ar9002_hw_per_calibration(ah, chan,
-                                                     rxchainmask, currCal);
-               if (iscaldone) {
-                       ah->cal_list_curr = currCal = currCal->calNext;
-
-                       if (currCal->calState == CAL_WAITING) {
-                               iscaldone = false;
-                               ath9k_hw_reset_calibration(ah, currCal);
-                       }
+       percal_pending = (currCal &&
+                         (currCal->calState == CAL_RUNNING ||
+                          currCal->calState == CAL_WAITING));
+
+       if (percal_pending && !nfcal) {
+               if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
+                       return 0;
+
+               ah->cal_list_curr = currCal = currCal->calNext;
+               if (currCal->calState == CAL_WAITING) {
+                       ath9k_hw_reset_calibration(ah, currCal);
+                       return 0;
                }
        }
 
@@ -698,7 +696,9 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
                         * NF is slow time-variant, so it is OK to use a
                         * historical value.
                         */
-                       ath9k_hw_loadnf(ah, ah->curchan);
+                       ret = ath9k_hw_loadnf(ah, ah->curchan);
+                       if (ret < 0)
+                               return ret;
                }
 
                if (longcal) {
@@ -709,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
                }
        }
 
-       return iscaldone;
+       return !percal_pending;
 }
 
 /* Carrier leakage Calibration fix */
@@ -856,6 +856,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 
        /* Do PA Calibration */
        ar9002_hw_pa_cal(ah, true);
+       ath9k_hw_loadnf(ah, chan);
+       ath9k_hw_start_nfcal(ah, true);
 
        if (ah->caldata)
                set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
index ac8301ef52420a00009f4d78b82e700987ea7508..06ab71db6e804b76a867cc036cb27887a2ac5b62 100644 (file)
@@ -121,13 +121,12 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
        return iscaldone;
 }
 
-static bool ar9003_hw_calibrate(struct ath_hw *ah,
-                               struct ath9k_channel *chan,
-                               u8 rxchainmask,
-                               bool longcal)
+static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
+                              u8 rxchainmask, bool longcal)
 {
        bool iscaldone = true;
        struct ath9k_cal_list *currCal = ah->cal_list_curr;
+       int ret;
 
        /*
         * For given calibration:
@@ -163,7 +162,9 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
                 * NF is slow time-variant, so it is OK to use a historical
                 * value.
                 */
-               ath9k_hw_loadnf(ah, ah->curchan);
+               ret = ath9k_hw_loadnf(ah, ah->curchan);
+               if (ret < 0)
+                       return ret;
 
                /* start NF calibration, without updating BB NF register */
                ath9k_hw_start_nfcal(ah, false);
index ddef9eedbac6f0d5e0b2ea2d0bfacda4f96e63c1..cb09102245b2bb6c9d00a1971e1c3bbece7ab470 100644 (file)
@@ -670,9 +670,6 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
        if (AR_SREV_9485_11_OR_LATER(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9485Modes_green_ob_db_tx_gain_1_1);
-       else if (AR_SREV_9340(ah))
-               INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9340Modes_ub124_tx_gain_table_1p0);
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_type5_tx_gain_table);
index 697c4ae90af006f9c7f962bd21ea938af1892455..9bdaa0afc37f7bed18594e7cab050e1467bfb279 100644 (file)
@@ -1348,7 +1348,7 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah,
                                       struct ath_hw_radar_conf *conf)
 {
        unsigned int regWrites = 0;
-       u32 radar_0 = 0, radar_1 = 0;
+       u32 radar_0 = 0, radar_1;
 
        if (!conf) {
                REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
@@ -1362,6 +1362,9 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah,
        radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI);
        radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND);
 
+       radar_1 = REG_READ(ah, AR_PHY_RADAR_1);
+       radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH |
+                    AR_PHY_RADAR_1_RELPWR_THRESH);
        radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI;
        radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK;
        radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN);
@@ -1388,7 +1391,7 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah)
        conf->fir_power = -28;
        conf->radar_rssi = 0;
        conf->pulse_height = 10;
-       conf->pulse_rssi = 24;
+       conf->pulse_rssi = 15;
        conf->pulse_inband = 8;
        conf->pulse_maxlen = 255;
        conf->pulse_inband_step = 12;
index a43b30d723a426bc1a2b3d8aac67b99942ea3df0..6290467a75a04ab94e7779f674a1c1ceb751bd3e 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef AR9003_RTT_H
 #define AR9003_RTT_H
 
+#ifdef CONFIG_ATH9K_PCOEM
 void ar9003_hw_rtt_enable(struct ath_hw *ah);
 void ar9003_hw_rtt_disable(struct ath_hw *ah);
 void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
@@ -25,5 +26,40 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah);
 void ar9003_hw_rtt_fill_hist(struct ath_hw *ah);
 void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
 bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan);
+#else
+static inline void ar9003_hw_rtt_enable(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_disable(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask)
+{
+}
+
+static inline bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
+{
+       return false;
+}
+
+static inline void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
+{
+}
+
+static inline void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
+{
+}
+
+static inline bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       return false;
+}
+#endif
 
 #endif
index 74d8bc05b317af2818317b5d1e77dc30ec8d8e8c..fd6a84ccd49e71fc086a00dcd9831efca3a59071 100644 (file)
@@ -507,7 +507,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
        {0x00009d04, 0x40206c10},
        {0x00009d08, 0x009c4060},
        {0x00009d0c, 0x9883800a},
-       {0x00009d10, 0x01834061},
+       {0x00009d10, 0x01884061},
        {0x00009d14, 0x00c0040b},
        {0x00009d18, 0x00000000},
        {0x00009e08, 0x0038230c},
@@ -545,9 +545,9 @@ static const u32 ar955x_1p0_baseband_core[][2] = {
        {0x0000a370, 0x00000000},
        {0x0000a390, 0x00000001},
        {0x0000a394, 0x00000444},
-       {0x0000a398, 0x1f020503},
-       {0x0000a39c, 0x29180c03},
-       {0x0000a3a0, 0x9a8b6844},
+       {0x0000a398, 0x001f0e0f},
+       {0x0000a39c, 0x0075393f},
+       {0x0000a3a0, 0xb79f6427},
        {0x0000a3a4, 0x00000000},
        {0x0000a3a8, 0xaaaaaaaa},
        {0x0000a3ac, 0x3c466478},
index a5ca65240af30b8980b5732a610d73ef155063c9..5d4629f96c15ab582d359f78105d17fc0258316b 100644 (file)
 
 #define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble
 
-#define ar9580_1p0_radio_core ar9300_2p2_radio_core
+static const u32 ar9580_1p0_radio_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00016000, 0x36db2db6},
+       {0x00016004, 0x6db6db40},
+       {0x00016008, 0x73f00000},
+       {0x0001600c, 0x00000000},
+       {0x00016040, 0x7f80fff8},
+       {0x0001604c, 0x76d005b5},
+       {0x00016050, 0x556cf031},
+       {0x00016054, 0x13449440},
+       {0x00016058, 0x0c51c92c},
+       {0x0001605c, 0x3db7fffc},
+       {0x00016060, 0xfffffffc},
+       {0x00016064, 0x000f0278},
+       {0x0001606c, 0x6db60000},
+       {0x00016080, 0x00000000},
+       {0x00016084, 0x0e48048c},
+       {0x00016088, 0x54214514},
+       {0x0001608c, 0x119f481e},
+       {0x00016090, 0x24926490},
+       {0x00016098, 0xd2888888},
+       {0x000160a0, 0x0a108ffe},
+       {0x000160a4, 0x812fc370},
+       {0x000160a8, 0x423c8000},
+       {0x000160b4, 0x92480080},
+       {0x000160c0, 0x00adb6d0},
+       {0x000160c4, 0x6db6db60},
+       {0x000160c8, 0x6db6db6c},
+       {0x000160cc, 0x01e6c000},
+       {0x00016100, 0x3fffbe01},
+       {0x00016104, 0xfff80000},
+       {0x00016108, 0x00080010},
+       {0x00016144, 0x02084080},
+       {0x00016148, 0x00000000},
+       {0x00016280, 0x058a0001},
+       {0x00016284, 0x3d840208},
+       {0x00016288, 0x05a20408},
+       {0x0001628c, 0x00038c07},
+       {0x00016290, 0x00000004},
+       {0x00016294, 0x458a214f},
+       {0x00016380, 0x00000000},
+       {0x00016384, 0x00000000},
+       {0x00016388, 0x00800700},
+       {0x0001638c, 0x00800700},
+       {0x00016390, 0x00800700},
+       {0x00016394, 0x00000000},
+       {0x00016398, 0x00000000},
+       {0x0001639c, 0x00000000},
+       {0x000163a0, 0x00000001},
+       {0x000163a4, 0x00000001},
+       {0x000163a8, 0x00000000},
+       {0x000163ac, 0x00000000},
+       {0x000163b0, 0x00000000},
+       {0x000163b4, 0x00000000},
+       {0x000163b8, 0x00000000},
+       {0x000163bc, 0x00000000},
+       {0x000163c0, 0x000000a0},
+       {0x000163c4, 0x000c0000},
+       {0x000163c8, 0x14021402},
+       {0x000163cc, 0x00001402},
+       {0x000163d0, 0x00000000},
+       {0x000163d4, 0x00000000},
+       {0x00016400, 0x36db2db6},
+       {0x00016404, 0x6db6db40},
+       {0x00016408, 0x73f00000},
+       {0x0001640c, 0x00000000},
+       {0x00016440, 0x7f80fff8},
+       {0x0001644c, 0x76d005b5},
+       {0x00016450, 0x556cf031},
+       {0x00016454, 0x13449440},
+       {0x00016458, 0x0c51c92c},
+       {0x0001645c, 0x3db7fffc},
+       {0x00016460, 0xfffffffc},
+       {0x00016464, 0x000f0278},
+       {0x0001646c, 0x6db60000},
+       {0x00016500, 0x3fffbe01},
+       {0x00016504, 0xfff80000},
+       {0x00016508, 0x00080010},
+       {0x00016544, 0x02084080},
+       {0x00016548, 0x00000000},
+       {0x00016780, 0x00000000},
+       {0x00016784, 0x00000000},
+       {0x00016788, 0x00800700},
+       {0x0001678c, 0x00800700},
+       {0x00016790, 0x00800700},
+       {0x00016794, 0x00000000},
+       {0x00016798, 0x00000000},
+       {0x0001679c, 0x00000000},
+       {0x000167a0, 0x00000001},
+       {0x000167a4, 0x00000001},
+       {0x000167a8, 0x00000000},
+       {0x000167ac, 0x00000000},
+       {0x000167b0, 0x00000000},
+       {0x000167b4, 0x00000000},
+       {0x000167b8, 0x00000000},
+       {0x000167bc, 0x00000000},
+       {0x000167c0, 0x000000a0},
+       {0x000167c4, 0x000c0000},
+       {0x000167c8, 0x14021402},
+       {0x000167cc, 0x00001402},
+       {0x000167d0, 0x00000000},
+       {0x000167d4, 0x00000000},
+       {0x00016800, 0x36db2db6},
+       {0x00016804, 0x6db6db40},
+       {0x00016808, 0x73f00000},
+       {0x0001680c, 0x00000000},
+       {0x00016840, 0x7f80fff8},
+       {0x0001684c, 0x76d005b5},
+       {0x00016850, 0x556cf031},
+       {0x00016854, 0x13449440},
+       {0x00016858, 0x0c51c92c},
+       {0x0001685c, 0x3db7fffc},
+       {0x00016860, 0xfffffffc},
+       {0x00016864, 0x000f0278},
+       {0x0001686c, 0x6db60000},
+       {0x00016900, 0x3fffbe01},
+       {0x00016904, 0xfff80000},
+       {0x00016908, 0x00080010},
+       {0x00016944, 0x02084080},
+       {0x00016948, 0x00000000},
+       {0x00016b80, 0x00000000},
+       {0x00016b84, 0x00000000},
+       {0x00016b88, 0x00800700},
+       {0x00016b8c, 0x00800700},
+       {0x00016b90, 0x00800700},
+       {0x00016b94, 0x00000000},
+       {0x00016b98, 0x00000000},
+       {0x00016b9c, 0x00000000},
+       {0x00016ba0, 0x00000001},
+       {0x00016ba4, 0x00000001},
+       {0x00016ba8, 0x00000000},
+       {0x00016bac, 0x00000000},
+       {0x00016bb0, 0x00000000},
+       {0x00016bb4, 0x00000000},
+       {0x00016bb8, 0x00000000},
+       {0x00016bbc, 0x00000000},
+       {0x00016bc0, 0x000000a0},
+       {0x00016bc4, 0x000c0000},
+       {0x00016bc8, 0x14021402},
+       {0x00016bcc, 0x00001402},
+       {0x00016bd0, 0x00000000},
+       {0x00016bd4, 0x00000000},
+};
 
 #define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble
 
index 01a7db061c6a2b8df0a8cac77a747c506d971705..85d74ff0767c733e6057cad23d934f5861bb4bf6 100644 (file)
@@ -345,6 +345,7 @@ struct ath_chanctx {
        u64 tsf_val;
        u32 last_beacon;
 
+       int flush_timeout;
        u16 txpower;
        bool offchannel;
        bool stopped;
@@ -362,7 +363,7 @@ enum ath_chanctx_event {
        ATH_CHANCTX_EVENT_BEACON_SENT,
        ATH_CHANCTX_EVENT_TSF_TIMER,
        ATH_CHANCTX_EVENT_BEACON_RECEIVED,
-       ATH_CHANCTX_EVENT_ASSOC,
+       ATH_CHANCTX_EVENT_AUTHORIZED,
        ATH_CHANCTX_EVENT_SWITCH,
        ATH_CHANCTX_EVENT_ASSIGN,
        ATH_CHANCTX_EVENT_UNASSIGN,
@@ -384,6 +385,7 @@ struct ath_chanctx_sched {
        bool wait_switch;
        bool force_noa_update;
        bool extend_absence;
+       bool mgd_prepare_tx;
        enum ath_chanctx_state state;
        u8 beacon_miss;
 
@@ -468,6 +470,7 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force);
 void ath_offchannel_next(struct ath_softc *sc);
 void ath_scan_complete(struct ath_softc *sc, bool abort);
 void ath_roc_complete(struct ath_softc *sc, bool abort);
+struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc);
 
 #else
 
@@ -540,7 +543,6 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc,
 
 #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
 
-int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan);
 void ath_startrecv(struct ath_softc *sc);
 bool ath_stoprecv(struct ath_softc *sc);
 u32 ath_calcrxfilter(struct ath_softc *sc);
@@ -595,7 +597,7 @@ struct ath_vif {
        u16 seq_no;
 
        /* BSS info */
-       u8 bssid[ETH_ALEN];
+       u8 bssid[ETH_ALEN] __aligned(2);
        u16 aid;
        bool assoc;
 
@@ -618,6 +620,7 @@ struct ath_vif {
        u32 noa_start;
        u32 noa_duration;
        bool periodic_noa;
+       bool oneshot_noa;
 };
 
 struct ath9k_vif_iter_data {
@@ -715,7 +718,8 @@ int ath_update_survey_stats(struct ath_softc *sc);
 void ath_update_survey_nf(struct ath_softc *sc, int channel);
 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
 void ath_ps_full_sleep(unsigned long data);
-void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
+void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
+                  bool sw_pending, bool timeout_override);
 
 /**********/
 /* BTCOEX */
@@ -975,6 +979,7 @@ struct ath_softc {
        struct ath_chanctx_sched sched;
        struct ath_offchannel offchannel;
        struct ath_chanctx *next_chan;
+       struct completion go_beacon;
 #endif
 
        unsigned long driver_data;
@@ -1069,7 +1074,7 @@ void ath9k_tasklet(unsigned long data);
 int ath_cabq_update(struct ath_softc *);
 u8 ath9k_parse_mpdudensity(u8 mpdudensity);
 irqreturn_t ath_isr(int irq, void *dev);
-int ath_reset(struct ath_softc *sc);
+int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan);
 void ath_cancel_work(struct ath_softc *sc);
 void ath_restart_work(struct ath_softc *sc);
 int ath9k_init_device(u16 devid, struct ath_softc *sc,
index 278365b8a8955dda362292b99949e63155be354c..e200a6e3aca5f4e4ce98354814358724cb0444d3 100644 (file)
@@ -234,7 +234,7 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
        REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 }
 
-void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
 {
        struct ath9k_nfcal_hist *h = NULL;
        unsigned i, j;
@@ -301,7 +301,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                ath_dbg(common, ANY,
                        "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
                        REG_READ(ah, AR_PHY_AGC_CONTROL));
-               return;
+               return -ETIMEDOUT;
        }
 
        /*
@@ -322,6 +322,8 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                }
        }
        REGWRITE_BUFFER_FLUSH(ah);
+
+       return 0;
 }
 
 
index b8ed95e9a335d90d86e8d0dd4031e5abc2e8dffc..87badf4bb8a4109bfeb9bdda6454fff2a0b2e630 100644 (file)
@@ -109,7 +109,7 @@ struct ath9k_pacal_info{
 
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
 void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
-void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
+int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
 bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
                                  struct ath9k_channel *chan);
index 945c89826b14cc70f1dd5f36b4bcd2b9efc21b10..c7234d5dda34fa9b58b78776a66dd97c18a5ba2d 100644 (file)
@@ -66,7 +66,7 @@ static int ath_set_channel(struct ath_softc *sc)
        }
 
        hchan = &sc->sc_ah->channels[pos];
-       r = ath_reset_internal(sc, hchan);
+       r = ath_reset(sc, hchan);
        if (r)
                return r;
 
@@ -117,6 +117,7 @@ void ath_chanctx_init(struct ath_softc *sc)
                cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
                INIT_LIST_HEAD(&ctx->vifs);
                ctx->txpower = ATH_TXPOWER_MAX;
+               ctx->flush_timeout = HZ / 5; /* 200ms */
                for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
                        INIT_LIST_HEAD(&ctx->acq[j]);
        }
@@ -145,6 +146,36 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
 
 #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
 
+/*************/
+/* Utilities */
+/*************/
+
+struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc)
+{
+       struct ath_chanctx *ctx;
+       struct ath_vif *avp;
+       struct ieee80211_vif *vif;
+
+       spin_lock_bh(&sc->chan_lock);
+
+       ath_for_each_chanctx(sc, ctx) {
+               if (!ctx->active)
+                       continue;
+
+               list_for_each_entry(avp, &ctx->vifs, list) {
+                       vif = avp->vif;
+
+                       if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO) {
+                               spin_unlock_bh(&sc->chan_lock);
+                               return ctx;
+                       }
+               }
+       }
+
+       spin_unlock_bh(&sc->chan_lock);
+       return NULL;
+}
+
 /**********************************************************/
 /* Functions to handle the channel context state machine. */
 /**********************************************************/
@@ -171,7 +202,7 @@ static const char *chanctx_event_string(enum ath_chanctx_event ev)
                case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT);
                case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER);
                case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED);
-               case_rtn_string(ATH_CHANCTX_EVENT_ASSOC);
+               case_rtn_string(ATH_CHANCTX_EVENT_AUTHORIZED);
                case_rtn_string(ATH_CHANCTX_EVENT_SWITCH);
                case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN);
                case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN);
@@ -198,6 +229,7 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
 void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_chanctx *ictx;
        struct ath_vif *avp;
        bool active = false;
        u8 n_active = 0;
@@ -205,6 +237,28 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
        if (!ctx)
                return;
 
+       if (ctx == &sc->offchannel.chan) {
+               spin_lock_bh(&sc->chan_lock);
+
+               if (likely(sc->sched.channel_switch_time))
+                       ctx->flush_timeout =
+                               usecs_to_jiffies(sc->sched.channel_switch_time);
+               else
+                       ctx->flush_timeout =
+                               msecs_to_jiffies(10);
+
+               spin_unlock_bh(&sc->chan_lock);
+
+               /*
+                * There is no need to iterate over the
+                * active/assigned channel contexts if
+                * the current context is offchannel.
+                */
+               return;
+       }
+
+       ictx = ctx;
+
        list_for_each_entry(avp, &ctx->vifs, list) {
                struct ieee80211_vif *vif = avp->vif;
 
@@ -227,12 +281,23 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
                n_active++;
        }
 
+       spin_lock_bh(&sc->chan_lock);
+
        if (n_active <= 1) {
+               ictx->flush_timeout = HZ / 5;
                clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags);
+               spin_unlock_bh(&sc->chan_lock);
                return;
        }
-       if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+
+       ictx->flush_timeout = usecs_to_jiffies(sc->sched.channel_switch_time);
+
+       if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
+               spin_unlock_bh(&sc->chan_lock);
                return;
+       }
+
+       spin_unlock_bh(&sc->chan_lock);
 
        if (ath9k_is_chanctx_enabled()) {
                ath_chanctx_event(sc, NULL,
@@ -301,6 +366,111 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time)
                "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time));
 }
 
+static void ath_chanctx_handle_bmiss(struct ath_softc *sc,
+                                    struct ath_chanctx *ctx,
+                                    struct ath_vif *avp)
+{
+       /*
+        * Clear the extend_absence flag if it had been
+        * set during the previous beacon transmission,
+        * since we need to revert to the normal NoA
+        * schedule.
+        */
+       if (ctx->active && sc->sched.extend_absence) {
+               avp->noa_duration = 0;
+               sc->sched.extend_absence = false;
+       }
+
+       /* If at least two consecutive beacons were missed on the STA
+        * chanctx, stay on the STA channel for one extra beacon period,
+        * to resync the timer properly.
+        */
+       if (ctx->active && sc->sched.beacon_miss >= 2) {
+               avp->noa_duration = 0;
+               sc->sched.extend_absence = true;
+       }
+}
+
+static void ath_chanctx_offchannel_noa(struct ath_softc *sc,
+                                      struct ath_chanctx *ctx,
+                                      struct ath_vif *avp,
+                                      u32 tsf_time)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       avp->noa_index++;
+       avp->offchannel_start = tsf_time;
+       avp->offchannel_duration = sc->sched.offchannel_duration;
+
+       ath_dbg(common, CHAN_CTX,
+               "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
+               avp->offchannel_duration,
+               avp->offchannel_start,
+               avp->noa_index);
+
+       /*
+        * When multiple contexts are active, the NoA
+        * has to be recalculated and advertised after
+        * an offchannel operation.
+        */
+       if (ctx->active && avp->noa_duration)
+               avp->noa_duration = 0;
+}
+
+static void ath_chanctx_set_periodic_noa(struct ath_softc *sc,
+                                        struct ath_vif *avp,
+                                        struct ath_beacon_config *cur_conf,
+                                        u32 tsf_time,
+                                        u32 beacon_int)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       avp->noa_index++;
+       avp->noa_start = tsf_time;
+
+       if (sc->sched.extend_absence)
+               avp->noa_duration = (3 * beacon_int / 2) +
+                       sc->sched.channel_switch_time;
+       else
+               avp->noa_duration =
+                       TU_TO_USEC(cur_conf->beacon_interval) / 2 +
+                       sc->sched.channel_switch_time;
+
+       if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
+           sc->sched.extend_absence)
+               avp->periodic_noa = false;
+       else
+               avp->periodic_noa = true;
+
+       ath_dbg(common, CHAN_CTX,
+               "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+               avp->noa_duration,
+               avp->noa_start,
+               avp->noa_index,
+               avp->periodic_noa);
+}
+
+static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc,
+                                       struct ath_vif *avp,
+                                       u32 tsf_time,
+                                       u32 duration)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+       avp->noa_index++;
+       avp->noa_start = tsf_time;
+       avp->periodic_noa = false;
+       avp->oneshot_noa = true;
+       avp->noa_duration = duration + sc->sched.channel_switch_time;
+
+       ath_dbg(common, CHAN_CTX,
+               "oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
+               avp->noa_duration,
+               avp->noa_start,
+               avp->noa_index,
+               avp->periodic_noa);
+}
+
 void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                       enum ath_chanctx_event ev)
 {
@@ -327,6 +497,14 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                if (avp->offchannel_duration)
                        avp->offchannel_duration = 0;
 
+               if (avp->oneshot_noa) {
+                       avp->noa_duration = 0;
+                       avp->oneshot_noa = false;
+
+                       ath_dbg(common, CHAN_CTX,
+                               "Clearing oneshot NoA\n");
+               }
+
                if (avp->chanctx != sc->cur_chan) {
                        ath_dbg(common, CHAN_CTX,
                                "Contexts differ, not preparing beacon\n");
@@ -356,6 +534,24 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                                "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n");
                }
 
+               if (sc->sched.mgd_prepare_tx)
+                       sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON;
+
+               /*
+                * When a context becomes inactive, for example,
+                * disassociation of a station context, the NoA
+                * attribute needs to be removed from subsequent
+                * beacons.
+                */
+               if (!ctx->active && avp->noa_duration &&
+                   sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) {
+                       avp->noa_duration = 0;
+                       avp->periodic_noa = false;
+
+                       ath_dbg(common, CHAN_CTX,
+                               "Clearing NoA schedule\n");
+               }
+
                if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
                        break;
 
@@ -378,45 +574,22 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                 * values and increment the index.
                 */
                if (sc->next_chan == &sc->offchannel.chan) {
-                       avp->noa_index++;
-                       avp->offchannel_start = tsf_time;
-                       avp->offchannel_duration = sc->sched.offchannel_duration;
-
-                       ath_dbg(common, CHAN_CTX,
-                               "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n",
-                               avp->offchannel_duration,
-                               avp->offchannel_start,
-                               avp->noa_index);
-
-                       /*
-                        * When multiple contexts are active, the NoA
-                        * has to be recalculated and advertised after
-                        * an offchannel operation.
-                        */
-                       if (ctx->active && avp->noa_duration)
-                               avp->noa_duration = 0;
-
+                       ath_chanctx_offchannel_noa(sc, ctx, avp, tsf_time);
                        break;
                }
 
-               /*
-                * Clear the extend_absence flag if it had been
-                * set during the previous beacon transmission,
-                * since we need to revert to the normal NoA
-                * schedule.
-                */
-               if (ctx->active && sc->sched.extend_absence) {
-                       avp->noa_duration = 0;
-                       sc->sched.extend_absence = false;
-               }
+               ath_chanctx_handle_bmiss(sc, ctx, avp);
 
-               /* If at least two consecutive beacons were missed on the STA
-                * chanctx, stay on the STA channel for one extra beacon period,
-                * to resync the timer properly.
+               /*
+                * If a mgd_prepare_tx() has been called by mac80211,
+                * a one-shot NoA needs to be sent. This can happen
+                * with one or more active channel contexts - in both
+                * cases, a new NoA schedule has to be advertised.
                 */
-               if (ctx->active && sc->sched.beacon_miss >= 2) {
-                       avp->noa_duration = 0;
-                       sc->sched.extend_absence = true;
+               if (sc->sched.mgd_prepare_tx) {
+                       ath_chanctx_set_oneshot_noa(sc, avp, tsf_time,
+                                                   jiffies_to_usecs(HZ / 5));
+                       break;
                }
 
                /* Prevent wrap-around issues */
@@ -429,31 +602,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                 * announcement.
                 */
                if (ctx->active &&
-                   (!avp->noa_duration || sc->sched.force_noa_update)) {
-                       avp->noa_index++;
-                       avp->noa_start = tsf_time;
-
-                       if (sc->sched.extend_absence)
-                               avp->noa_duration = (3 * beacon_int / 2) +
-                                       sc->sched.channel_switch_time;
-                       else
-                               avp->noa_duration =
-                                       TU_TO_USEC(cur_conf->beacon_interval) / 2 +
-                                       sc->sched.channel_switch_time;
-
-                       if (test_bit(ATH_OP_SCANNING, &common->op_flags) ||
-                           sc->sched.extend_absence)
-                               avp->periodic_noa = false;
-                       else
-                               avp->periodic_noa = true;
-
-                       ath_dbg(common, CHAN_CTX,
-                               "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n",
-                               avp->noa_duration,
-                               avp->noa_start,
-                               avp->noa_index,
-                               avp->periodic_noa);
-               }
+                   (!avp->noa_duration || sc->sched.force_noa_update))
+                       ath_chanctx_set_periodic_noa(sc, avp, cur_conf,
+                                                    tsf_time, beacon_int);
 
                if (ctx->active && sc->sched.force_noa_update)
                        sc->sched.force_noa_update = false;
@@ -467,6 +618,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                }
 
                sc->sched.beacon_pending = false;
+
+               if (sc->sched.mgd_prepare_tx) {
+                       sc->sched.mgd_prepare_tx = false;
+                       complete(&sc->go_beacon);
+                       ath_dbg(common, CHAN_CTX,
+                               "Beacon sent, complete go_beacon\n");
+                       break;
+               }
+
                if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON)
                        break;
 
@@ -495,10 +655,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                    sc->cur_chan == &sc->offchannel.chan)
                        break;
 
-               ath_chanctx_adjust_tbtt_delta(sc);
                sc->sched.beacon_pending = false;
                sc->sched.beacon_miss = 0;
 
+               if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE ||
+                   !sc->cur_chan->tsf_val)
+                       break;
+
+               ath_chanctx_adjust_tbtt_delta(sc);
+
                /* TSF time might have been updated by the incoming beacon,
                 * need update the channel switch timer to reflect the change.
                 */
@@ -510,7 +675,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
 
                ath_chanctx_setup_timer(sc, tsf_time);
                break;
-       case ATH_CHANCTX_EVENT_ASSOC:
+       case ATH_CHANCTX_EVENT_AUTHORIZED:
                if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE ||
                    avp->chanctx != sc->cur_chan)
                        break;
@@ -578,22 +743,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
                ieee80211_queue_work(sc->hw, &sc->chanctx_work);
                break;
        case ATH_CHANCTX_EVENT_ASSIGN:
-               /*
-                * When adding a new channel context, check if a scan
-                * is in progress and abort it since the addition of
-                * a new channel context is usually followed by VIF
-                * assignment, in which case we have to start multi-channel
-                * operation.
-                */
-               if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
-                       ath_dbg(common, CHAN_CTX,
-                               "Aborting HW scan to add new context\n");
-
-                       spin_unlock_bh(&sc->chan_lock);
-                       del_timer_sync(&sc->offchannel.timer);
-                       ath_scan_complete(sc, true);
-                       spin_lock_bh(&sc->chan_lock);
-               }
                break;
        case ATH_CHANCTX_EVENT_CHANGE:
                break;
@@ -770,7 +919,7 @@ void ath_roc_complete(struct ath_softc *sc, bool abort)
 
        sc->offchannel.roc_vif = NULL;
        sc->offchannel.roc_chan = NULL;
-       if (!abort)
+       if (abort)
                ieee80211_remain_on_channel_expired(sc->hw);
        ath_offchannel_next(sc);
        ath9k_ps_restore(sc);
@@ -904,6 +1053,7 @@ static void ath_offchannel_timer(unsigned long data)
        case ATH_OFFCHANNEL_ROC_WAIT:
                ctx = ath_chanctx_get_oper_chan(sc, false);
                sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE;
+               ieee80211_remain_on_channel_expired(sc->hw);
                ath_chanctx_switch(sc, ctx, NULL);
                break;
        default:
@@ -1082,10 +1232,11 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force)
                ath9k_chanctx_stop_queues(sc, sc->cur_chan);
                queues_stopped = true;
 
-               __ath9k_flush(sc->hw, ~0, true);
+               __ath9k_flush(sc->hw, ~0, true, false, false);
 
                if (ath_chanctx_send_ps_frame(sc, true))
-                       __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
+                       __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO),
+                                     false, false, false);
 
                send_ps = true;
                spin_lock_bh(&sc->chan_lock);
@@ -1177,6 +1328,8 @@ void ath9k_init_channel_context(struct ath_softc *sc)
                    (unsigned long)sc);
        setup_timer(&sc->sched.timer, ath_chanctx_timer,
                    (unsigned long)sc);
+
+       init_completion(&sc->go_beacon);
 }
 
 void ath9k_deinit_channel_context(struct ath_softc *sc)
index 5c45e787814ed6a9b65f9f3e523626f282201ddb..c9afc15cd4d3dca6b3d88098c56c5f4d267117e1 100644 (file)
@@ -852,36 +852,31 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
                               size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
+       static const char * const reset_cause[__RESET_TYPE_MAX] = {
+               [RESET_TYPE_BB_HANG] = "Baseband Hang",
+               [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog",
+               [RESET_TYPE_FATAL_INT] = "Fatal HW Error",
+               [RESET_TYPE_TX_ERROR] = "TX HW error",
+               [RESET_TYPE_TX_GTT] = "Transmit timeout",
+               [RESET_TYPE_TX_HANG] = "TX Path Hang",
+               [RESET_TYPE_PLL_HANG] = "PLL RX Hang",
+               [RESET_TYPE_MAC_HANG] = "MAC Hang",
+               [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
+               [RESET_TYPE_MCI] = "MCI Reset",
+               [RESET_TYPE_CALIBRATION] = "Calibration error",
+       };
        char buf[512];
        unsigned int len = 0;
+       int i;
 
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "Baseband Hang",
-                        sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "Baseband Watchdog",
-                        sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "Fatal HW Error",
-                        sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "TX HW error",
-                        sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "TX Path Hang",
-                        sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "PLL RX Hang",
-                        sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "MAC Hang",
-                        sc->debug.stats.reset[RESET_TYPE_MAC_HANG]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "Stuck Beacon",
-                        sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]);
-       len += scnprintf(buf + len, sizeof(buf) - len,
-                        "%17s: %2d\n", "MCI Reset",
-                        sc->debug.stats.reset[RESET_TYPE_MCI]);
+       for (i = 0; i < ARRAY_SIZE(reset_cause); i++) {
+               if (!reset_cause[i])
+                   continue;
+
+               len += scnprintf(buf + len, sizeof(buf) - len,
+                                "%17s: %2d\n", reset_cause[i],
+                                sc->debug.stats.reset[i]);
+       }
 
        if (len > sizeof(buf))
                len = sizeof(buf);
index 53ae15bd0c9d4ac8b40a7a9de3689c607d56c3cd..bd75b1f716db527208afc525a0fd186d527e6e29 100644 (file)
@@ -49,6 +49,7 @@ enum ath_reset_type {
        RESET_TYPE_MAC_HANG,
        RESET_TYPE_BEACON_STUCK,
        RESET_TYPE_MCI,
+       RESET_TYPE_CALIBRATION,
        __RESET_TYPE_MAX
 };
 
index 3218ca9947463a844ed38f22956faedaca688cbb..122b846b8ec0e796bed2e15f8a6dc4341b9c00bc 100644 (file)
@@ -262,7 +262,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
 {
        struct ar5416_eeprom_def *eep = &ah->eeprom.def;
        struct ath_common *common = ath9k_hw_common(ah);
-       u16 *eepdata, temp, magic, magic2;
+       u16 *eepdata, temp, magic;
        u32 sum = 0, el;
        bool need_swap = false;
        int i, addr, size;
@@ -272,27 +272,16 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
                return false;
        }
 
-       if (!ath9k_hw_use_flash(ah)) {
-               ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
-
-               if (magic != AR5416_EEPROM_MAGIC) {
-                       magic2 = swab16(magic);
-
-                       if (magic2 == AR5416_EEPROM_MAGIC) {
-                               size = sizeof(struct ar5416_eeprom_def);
-                               need_swap = true;
-                               eepdata = (u16 *) (&ah->eeprom);
+       if (swab16(magic) == AR5416_EEPROM_MAGIC &&
+           !(ah->ah_flags & AH_NO_EEP_SWAP)) {
+               size = sizeof(struct ar5416_eeprom_def);
+               need_swap = true;
+               eepdata = (u16 *) (&ah->eeprom);
 
-                               for (addr = 0; addr < size / sizeof(u16); addr++) {
-                                       temp = swab16(*eepdata);
-                                       *eepdata = temp;
-                                       eepdata++;
-                               }
-                       } else {
-                               ath_err(common,
-                                       "Invalid EEPROM Magic. Endianness mismatch.\n");
-                               return -EINVAL;
-                       }
+               for (addr = 0; addr < size / sizeof(u16); addr++) {
+                       temp = swab16(*eepdata);
+                       *eepdata = temp;
+                       eepdata++;
                }
        }
 
index 8e85efeaeffcf67d08dcc9e94d793f5bb0559a9f..88769b64b20b29d9f9cb71c6ffbca27cc3d314d4 100644 (file)
@@ -41,10 +41,9 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds,
        ath9k_hw_ops(ah)->set_desc_link(ds, link);
 }
 
-static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
-                                     struct ath9k_channel *chan,
-                                     u8 rxchainmask,
-                                     bool longcal)
+static inline int ath9k_hw_calibrate(struct ath_hw *ah,
+                                    struct ath9k_channel *chan,
+                                    u8 rxchainmask, bool longcal)
 {
        return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
 }
index 8be4b145339426b7ea8a47a4788c9dd6be04b238..ee9fb52cec62aa9ee07cdda616ea4d1ac041f342 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/bitops.h>
+#include <linux/etherdevice.h>
 #include <asm/unaligned.h>
 
 #include "hw.h"
@@ -446,8 +447,16 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
                common->macaddr[2 * i] = eeval >> 8;
                common->macaddr[2 * i + 1] = eeval & 0xff;
        }
-       if (sum == 0 || sum == 0xffff * 3)
-               return -EADDRNOTAVAIL;
+       if (!is_valid_ether_addr(common->macaddr)) {
+               ath_err(common,
+                       "eeprom contains invalid mac address: %pM\n",
+                       common->macaddr);
+
+               random_ether_addr(common->macaddr);
+               ath_err(common,
+                       "random mac address will be used: %pM\n",
+                       common->macaddr);
+       }
 
        return 0;
 }
@@ -1953,8 +1962,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ath9k_hw_mci_is_enabled(ah))
                ar9003_mci_check_bt(ah);
 
-       ath9k_hw_loadnf(ah, chan);
-       ath9k_hw_start_nfcal(ah, true);
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               ath9k_hw_loadnf(ah, chan);
+               ath9k_hw_start_nfcal(ah, true);
+       }
 
        if (AR_SREV_9300_20_OR_LATER(ah))
                ar9003_hw_bb_watchdog_config(ah);
@@ -2342,17 +2353,25 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE);
-       if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) {
-               ath_err(common,
-                       "no band has been marked as supported in EEPROM\n");
-               return -EINVAL;
+
+       if (eeval & AR5416_OPFLAGS_11A) {
+               if (ah->disable_5ghz)
+                       ath_warn(common, "disabling 5GHz band\n");
+               else
+                       pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
        }
 
-       if (eeval & AR5416_OPFLAGS_11A)
-               pCap->hw_caps |= ATH9K_HW_CAP_5GHZ;
+       if (eeval & AR5416_OPFLAGS_11G) {
+               if (ah->disable_2ghz)
+                       ath_warn(common, "disabling 2GHz band\n");
+               else
+                       pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
+       }
 
-       if (eeval & AR5416_OPFLAGS_11G)
-               pCap->hw_caps |= ATH9K_HW_CAP_2GHZ;
+       if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) {
+               ath_err(common, "both bands are disabled\n");
+               return -EINVAL;
+       }
 
        if (AR_SREV_9485(ah) ||
            AR_SREV_9285(ah) ||
index 975074fc11bcdda44e65e4eaabe05b75b51c90c9..e49721e85f6a17879d68ae6c03075bcaf1847cbc 100644 (file)
@@ -244,13 +244,20 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_2GHZ                       = BIT(11),
        ATH9K_HW_CAP_5GHZ                       = BIT(12),
        ATH9K_HW_CAP_APM                        = BIT(13),
+#ifdef CONFIG_ATH9K_PCOEM
        ATH9K_HW_CAP_RTT                        = BIT(14),
        ATH9K_HW_CAP_MCI                        = BIT(15),
-       ATH9K_HW_CAP_DFS                        = BIT(16),
-       ATH9K_HW_WOW_DEVICE_CAPABLE             = BIT(17),
-       ATH9K_HW_CAP_PAPRD                      = BIT(18),
-       ATH9K_HW_CAP_FCC_BAND_SWITCH            = BIT(19),
-       ATH9K_HW_CAP_BT_ANT_DIV                 = BIT(20),
+       ATH9K_HW_WOW_DEVICE_CAPABLE             = BIT(16),
+       ATH9K_HW_CAP_BT_ANT_DIV                 = BIT(17),
+#else
+       ATH9K_HW_CAP_RTT                        = 0,
+       ATH9K_HW_CAP_MCI                        = 0,
+       ATH9K_HW_WOW_DEVICE_CAPABLE             = 0,
+       ATH9K_HW_CAP_BT_ANT_DIV                 = 0,
+#endif
+       ATH9K_HW_CAP_DFS                        = BIT(18),
+       ATH9K_HW_CAP_PAPRD                      = BIT(19),
+       ATH9K_HW_CAP_FCC_BAND_SWITCH            = BIT(20),
 };
 
 /*
@@ -681,10 +688,8 @@ struct ath_hw_ops {
                                     bool power_off);
        void (*rx_enable)(struct ath_hw *ah);
        void (*set_desc_link)(void *ds, u32 link);
-       bool (*calibrate)(struct ath_hw *ah,
-                         struct ath9k_channel *chan,
-                         u8 rxchainmask,
-                         bool longcal);
+       int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan,
+                        u8 rxchainmask, bool longcal);
        bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
                        u32 *sync_cause_p);
        void (*set_txdesc)(struct ath_hw *ah, void *ds,
@@ -726,6 +731,7 @@ enum ath_cal_list {
 #define AH_USE_EEPROM   0x1
 #define AH_UNPLUGGED    0x2 /* The card has been physically removed. */
 #define AH_FASTCC       0x4
+#define AH_NO_EEP_SWAP  0x8 /* Do not swap EEPROM data */
 
 struct ath_hw {
        struct ath_ops reg_ops;
@@ -924,6 +930,8 @@ struct ath_hw {
        bool is_clk_25mhz;
        int (*get_mac_revision)(void);
        int (*external_reset)(void);
+       bool disable_2ghz;
+       bool disable_5ghz;
 
        const struct firmware *eeprom_blob;
 
index 3bd030494986a087bfd9744873649442fa67b572..a4d69a0597537979e1ef576ba440dbb89ccbb716 100644 (file)
@@ -362,6 +362,9 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc)
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
 
+       if (!IS_ENABLED(CONFIG_ATH9K_PCOEM))
+               return;
+
        if (common->bus_ops->ath_bus_type != ATH_PCI)
                return;
 
@@ -528,6 +531,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
                ah->is_clk_25mhz = pdata->is_clk_25mhz;
                ah->get_mac_revision = pdata->get_mac_revision;
                ah->external_reset = pdata->external_reset;
+               ah->disable_2ghz = pdata->disable_2ghz;
+               ah->disable_5ghz = pdata->disable_5ghz;
+               if (!pdata->endian_check)
+                       ah->ah_flags |= AH_NO_EEP_SWAP;
        }
 
        common->ops = &ah->reg_ops;
index 2343f56e64987730bcb3ad1cb5542c41dcd94310..b829263e3d0a7f2a849bb96bfeed4ab948a0c1bc 100644 (file)
@@ -371,9 +371,15 @@ void ath_ani_calibrate(unsigned long data)
 
        /* Perform calibration if necessary */
        if (longcal || shortcal) {
-               common->ani.caldone =
-                       ath9k_hw_calibrate(ah, ah->curchan,
-                                          ah->rxchainmask, longcal);
+               int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask,
+                                            longcal);
+               if (ret < 0) {
+                       common->ani.caldone = 0;
+                       ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION);
+                       return;
+               }
+
+               common->ani.caldone = ret;
        }
 
        ath_dbg(common, ANI,
index 30c66dfcd7a04b8489186c82db741b87f0afbad0..a91ee92d9d3f83be5825f1d71703ab2b35f03ec0 100644 (file)
@@ -54,7 +54,8 @@ u8 ath9k_parse_mpdudensity(u8 mpdudensity)
        }
 }
 
-static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
+static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq,
+                                    bool sw_pending)
 {
        bool pending = false;
 
@@ -65,6 +66,9 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
                goto out;
        }
 
+       if (!sw_pending)
+               goto out;
+
        if (txq->mac80211_qnum >= 0) {
                struct list_head *list;
 
@@ -270,7 +274,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
        return true;
 }
 
-int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
+static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -281,6 +285,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
        __ath_cancel_work(sc);
 
        tasklet_disable(&sc->intr_tq);
+       tasklet_disable(&sc->bcon_tasklet);
        spin_lock_bh(&sc->sc_pcu_lock);
 
        if (!sc->cur_chan->offchannel) {
@@ -326,6 +331,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
 
 out:
        spin_unlock_bh(&sc->sc_pcu_lock);
+       tasklet_enable(&sc->bcon_tasklet);
        tasklet_enable(&sc->intr_tq);
 
        return r;
@@ -539,11 +545,10 @@ irqreturn_t ath_isr(int irq, void *dev)
                sched = true;
 
        /*
-        * If a FATAL or RXORN interrupt is received, we have to reset the
-        * chip immediately.
+        * If a FATAL interrupt is received, we have to reset the chip
+        * immediately.
         */
-       if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) &&
-           !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
+       if (status & ATH9K_INT_FATAL)
                goto chip_reset;
 
        if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
@@ -598,17 +603,29 @@ chip_reset:
 #undef SCHED_INTR
 }
 
-int ath_reset(struct ath_softc *sc)
+/*
+ * This function is called when a HW reset cannot be deferred
+ * and has to be immediate.
+ */
+int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int r;
 
+       set_bit(ATH_OP_HW_RESET, &common->op_flags);
+
        ath9k_ps_wakeup(sc);
-       r = ath_reset_internal(sc, NULL);
+       r = ath_reset_internal(sc, hchan);
        ath9k_ps_restore(sc);
 
        return r;
 }
 
+/*
+ * When a HW reset can be deferred, it is added to the
+ * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before
+ * queueing.
+ */
 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -623,7 +640,9 @@ void ath_reset_work(struct work_struct *work)
 {
        struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work);
 
-       ath_reset(sc);
+       ath9k_ps_wakeup(sc);
+       ath_reset_internal(sc, NULL);
+       ath9k_ps_restore(sc);
 }
 
 /**********************/
@@ -1037,7 +1056,7 @@ static void ath9k_set_offchannel_state(struct ath_softc *sc)
 
        eth_zero_addr(common->curbssid);
        eth_broadcast_addr(common->bssidmask);
-       ether_addr_copy(common->macaddr, vif->addr);
+       memcpy(common->macaddr, vif->addr, ETH_ALEN);
        common->curaid = 0;
        ah->opmode = vif->type;
        ah->imask &= ~ATH9K_INT_SWBA;
@@ -1078,7 +1097,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc,
        ath9k_calculate_iter_data(sc, ctx, &iter_data);
 
        if (iter_data.has_hw_macaddr)
-               ether_addr_copy(common->macaddr, iter_data.hw_macaddr);
+               memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
 
        memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
        ath_hw_setbssidmask(common);
@@ -1550,6 +1569,40 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw,
        return 0;
 }
 
+static int ath9k_sta_state(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta,
+                          enum ieee80211_sta_state old_state,
+                          enum ieee80211_sta_state new_state)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       int ret = 0;
+
+       if (old_state == IEEE80211_STA_AUTH &&
+           new_state == IEEE80211_STA_ASSOC) {
+               ret = ath9k_sta_add(hw, vif, sta);
+               ath_dbg(common, CONFIG,
+                       "Add station: %pM\n", sta->addr);
+       } else if (old_state == IEEE80211_STA_ASSOC &&
+                  new_state == IEEE80211_STA_AUTH) {
+               ret = ath9k_sta_remove(hw, vif, sta);
+               ath_dbg(common, CONFIG,
+                       "Remove station: %pM\n", sta->addr);
+       }
+
+       if (ath9k_is_chanctx_enabled()) {
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       if (old_state == IEEE80211_STA_ASSOC &&
+                           new_state == IEEE80211_STA_AUTHORIZED)
+                               ath_chanctx_event(sc, vif,
+                                                 ATH_CHANCTX_EVENT_AUTHORIZED);
+               }
+       }
+
+       return ret;
+}
+
 static void ath9k_sta_set_tx_filter(struct ath_hw *ah,
                                    struct ath_node *an,
                                    bool set)
@@ -1734,17 +1787,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n",
                        bss_conf->bssid, bss_conf->assoc);
 
-               ether_addr_copy(avp->bssid, bss_conf->bssid);
+               memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
                avp->aid = bss_conf->aid;
                avp->assoc = bss_conf->assoc;
 
                ath9k_calculate_summary_state(sc, avp->chanctx);
-
-               if (ath9k_is_chanctx_enabled()) {
-                       if (bss_conf->assoc)
-                               ath_chanctx_event(sc, vif,
-                                                 ATH_CHANCTX_EVENT_ASSOC);
-               }
        }
 
        if (changed & BSS_CHANGED_IBSS) {
@@ -1840,6 +1887,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                              u16 tid, u16 *ssn, u8 buf_size)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        bool flush = false;
        int ret = 0;
 
@@ -1851,6 +1899,12 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
        case IEEE80211_AMPDU_RX_STOP:
                break;
        case IEEE80211_AMPDU_TX_START:
+               if (ath9k_is_chanctx_enabled()) {
+                       if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+                               ret = -EBUSY;
+                               break;
+                       }
+               }
                ath9k_ps_wakeup(sc);
                ret = ath_tx_aggr_start(sc, sta, tid, ssn);
                if (!ret)
@@ -1964,7 +2018,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw,
        mutex_unlock(&sc->mutex);
 }
 
-static bool ath9k_has_tx_pending(struct ath_softc *sc)
+static bool ath9k_has_tx_pending(struct ath_softc *sc,
+                                bool sw_pending)
 {
        int i, npend = 0;
 
@@ -1972,7 +2027,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc)
                if (!ATH_TXQ_SETUP(sc, i))
                        continue;
 
-               npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+               npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i],
+                                                sw_pending);
                if (npend)
                        break;
        }
@@ -1984,18 +2040,38 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        u32 queues, bool drop)
 {
        struct ath_softc *sc = hw->priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 
+       if (ath9k_is_chanctx_enabled()) {
+               if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
+                       goto flush;
+
+               /*
+                * If MCC is active, extend the flush timeout
+                * and wait for the HW/SW queues to become
+                * empty. This needs to be done outside the
+                * sc->mutex lock to allow the channel scheduler
+                * to switch channel contexts.
+                *
+                * The vif queues have been stopped in mac80211,
+                * so there won't be any incoming frames.
+                */
+               __ath9k_flush(hw, queues, drop, true, true);
+               return;
+       }
+flush:
        mutex_lock(&sc->mutex);
-       __ath9k_flush(hw, queues, drop);
+       __ath9k_flush(hw, queues, drop, true, false);
        mutex_unlock(&sc->mutex);
 }
 
-void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
+                  bool sw_pending, bool timeout_override)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       int timeout = HZ / 5; /* 200 ms */
+       int timeout;
        bool drain_txq;
 
        cancel_delayed_work_sync(&sc->tx_complete_work);
@@ -2010,7 +2086,17 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
                return;
        }
 
-       if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
+       spin_lock_bh(&sc->chan_lock);
+       if (timeout_override)
+               timeout = HZ / 5;
+       else
+               timeout = sc->cur_chan->flush_timeout;
+       spin_unlock_bh(&sc->chan_lock);
+
+       ath_dbg(common, CHAN_CTX,
+               "Flush timeout: %d\n", jiffies_to_msecs(timeout));
+
+       if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending),
                               timeout) > 0)
                drop = false;
 
@@ -2021,7 +2107,7 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
                spin_unlock_bh(&sc->sc_pcu_lock);
 
                if (!drain_txq)
-                       ath_reset(sc);
+                       ath_reset(sc, NULL);
 
                ath9k_ps_restore(sc);
        }
@@ -2033,7 +2119,7 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
 {
        struct ath_softc *sc = hw->priv;
 
-       return ath9k_has_tx_pending(sc);
+       return ath9k_has_tx_pending(sc, true);
 }
 
 static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
@@ -2310,7 +2396,6 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw,
                        conf->def.chan->center_freq);
 
                ath_chanctx_set_channel(sc, ctx, &conf->def);
-               ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN);
 
                mutex_unlock(&sc->mutex);
                return 0;
@@ -2419,7 +2504,11 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
        struct ath_softc *sc = hw->priv;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (struct ath_vif *) vif->drv_priv;
+       struct ath_beacon_config *cur_conf;
+       struct ath_chanctx *go_ctx;
+       unsigned long timeout;
        bool changed = false;
+       u32 beacon_int;
 
        if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
                return;
@@ -2430,19 +2519,59 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw,
        mutex_lock(&sc->mutex);
 
        spin_lock_bh(&sc->chan_lock);
-       if (sc->next_chan || (sc->cur_chan != avp->chanctx)) {
-               sc->next_chan = avp->chanctx;
+       if (sc->next_chan || (sc->cur_chan != avp->chanctx))
                changed = true;
+       spin_unlock_bh(&sc->chan_lock);
+
+       if (!changed)
+               goto out;
+
+       if (test_bit(ATH_OP_SCANNING, &common->op_flags)) {
+               ath_dbg(common, CHAN_CTX,
+                       "%s: Aborting HW scan\n", __func__);
+
+               mutex_unlock(&sc->mutex);
+
+               del_timer_sync(&sc->offchannel.timer);
+               ath_scan_complete(sc, true);
+               flush_work(&sc->chanctx_work);
+
+               mutex_lock(&sc->mutex);
+       }
+
+       go_ctx = ath_is_go_chanctx_present(sc);
+
+       if (go_ctx) {
+               /*
+                * Wait till the GO interface gets a chance
+                * to send out an NoA.
+                */
+               spin_lock_bh(&sc->chan_lock);
+               sc->sched.mgd_prepare_tx = true;
+               cur_conf = &go_ctx->beacon;
+               beacon_int = TU_TO_USEC(cur_conf->beacon_interval);
+               spin_unlock_bh(&sc->chan_lock);
+
+               timeout = usecs_to_jiffies(beacon_int);
+               init_completion(&sc->go_beacon);
+
+               if (wait_for_completion_timeout(&sc->go_beacon,
+                                               timeout) == 0)
+                       ath_dbg(common, CHAN_CTX,
+                               "Failed to send new NoA\n");
        }
+
        ath_dbg(common, CHAN_CTX,
-               "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n",
-               __func__, changed);
+               "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n",
+               __func__, vif->addr);
+
+       spin_lock_bh(&sc->chan_lock);
+       sc->next_chan = avp->chanctx;
        sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE;
        spin_unlock_bh(&sc->chan_lock);
 
-       if (changed)
-               ath_chanctx_set_next(sc, true);
-
+       ath_chanctx_set_next(sc, true);
+out:
        mutex_unlock(&sc->mutex);
 }
 
@@ -2474,8 +2603,7 @@ struct ieee80211_ops ath9k_ops = {
        .remove_interface   = ath9k_remove_interface,
        .config             = ath9k_config,
        .configure_filter   = ath9k_configure_filter,
-       .sta_add            = ath9k_sta_add,
-       .sta_remove         = ath9k_sta_remove,
+       .sta_state          = ath9k_sta_state,
        .sta_notify         = ath9k_sta_notify,
        .conf_tx            = ath9k_conf_tx,
        .bss_info_changed   = ath9k_bss_info_changed,
index c018dea0b2e82da6177da57ad4ea111e23d34eec..e3f60d5c526379848ce6eaa237ad0e51430bbfd3 100644 (file)
@@ -30,6 +30,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
 
+#ifdef CONFIG_ATH9K_PCOEM
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x002A,
                         PCI_VENDOR_ID_AZWAVE,
@@ -82,6 +83,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
                         PCI_VENDOR_ID_AZWAVE,
                         0x2C37),
          .driver_data = ATH9K_PCI_BT_ANT_DIV },
+#endif
 
        { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
        { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
@@ -102,6 +104,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
 
        { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
 
+#ifdef CONFIG_ATH9K_PCOEM
        /* PCI-E CUS198 */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0032,
@@ -294,10 +297,12 @@ static const struct pci_device_id ath_pci_id_table[] = {
                         PCI_VENDOR_ID_ASUSTEK,
                         0x850D),
          .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE },
+#endif
 
        { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
        { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */
 
+#ifdef CONFIG_ATH9K_PCOEM
        /* PCI-E CUS217 */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0034,
@@ -657,6 +662,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
        /* PCI-E AR9565 (WB335) */
        { PCI_VDEVICE(ATHEROS, 0x0036),
          .driver_data = ATH9K_PCI_BT_ANT_DIV },
+#endif
 
        { 0 }
 };
index 2a938f4feac5fd91e33fd3c61e5364de1809b591..1c0b1c1c53508f826a7d806a8e9d72f77814749e 100644 (file)
        (AR_SREV_9330((_ah)) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_12))
 
+#ifdef CONFIG_ATH9K_PCOEM
+#define AR_SREV_9462(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
 #define AR_SREV_9485(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
+#define AR_SREV_9565(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
+#else
+#define AR_SREV_9462(_ah) 0
+#define AR_SREV_9485(_ah) 0
+#define AR_SREV_9565(_ah) 0
+#endif
+
 #define AR_SREV_9485_11_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485) && \
+       (AR_SREV_9485(_ah) && \
         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11))
 #define AR_SREV_9485_OR_LATER(_ah) \
        (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
     (AR_SREV_9285_12_OR_LATER(_ah) && \
      ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
 
-#define AR_SREV_9462(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462))
 #define AR_SREV_9462_20(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+       (AR_SREV_9462(_ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20))
 #define AR_SREV_9462_21(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+       (AR_SREV_9462(_ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_21))
 #define AR_SREV_9462_20_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+       (AR_SREV_9462(_ah) && \
         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20))
 #define AR_SREV_9462_21_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \
+       (AR_SREV_9462(_ah) && \
         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_21))
 
-#define AR_SREV_9565(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
 #define AR_SREV_9565_10(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+       (AR_SREV_9565(_ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10))
 #define AR_SREV_9565_101(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+       (AR_SREV_9565(_ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101))
 #define AR_SREV_9565_11(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+       (AR_SREV_9565(_ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11))
 #define AR_SREV_9565_11_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \
+       (AR_SREV_9565(_ah) && \
         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11))
 
 #define AR_SREV_9550(_ah) \
index 40ab65e6882f10cf0c4fa4707fb0b90065ea135a..ac4781f37e786150181139ffe562fca55da3a1fd 100644 (file)
@@ -99,7 +99,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
 
 static void ath9k_tx99_deinit(struct ath_softc *sc)
 {
-       ath_reset(sc);
+       ath_reset(sc, NULL);
 
        ath9k_ps_wakeup(sc);
        ath9k_tx99_stop(sc);
@@ -127,7 +127,7 @@ static int ath9k_tx99_init(struct ath_softc *sc)
        memset(&txctl, 0, sizeof(txctl));
        txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];
 
-       ath_reset(sc);
+       ath_reset(sc, NULL);
 
        ath9k_ps_wakeup(sc);
 
index b80b2138ce3c745d93d9bc973ac83cbedc984aab..dca6df13fd5b9be5de049f56b595d94fa94aeda2 100644 (file)
@@ -994,7 +994,7 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
                        refsel0 = 0;
                        refsel1 = 1;
                }
-               chansel = byte_rev_table[chansel];
+               chansel = bitrev8(chansel);
        } else {
                if (freq == 2484) {
                        chansel = 10 + (freq - 2274) / 5;
@@ -1002,7 +1002,7 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
                } else
                        chansel = 16 + (freq - 2272) / 5;
                chansel *= 4;
-               chansel = byte_rev_table[chansel];
+               chansel = bitrev8(chansel);
        }
 
        d1 =    chansel;
index d9f4b30dd343b01e1d58ac8c9deadbb246a82abd..0fc0b9f8e605f0f51afb3e49e317b2e14cfcc9b4 100644 (file)
@@ -792,12 +792,13 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
 }
 
 static int wil_cfg80211_del_station(struct wiphy *wiphy,
-                                   struct net_device *dev, const u8 *mac)
+                                   struct net_device *dev,
+                                   struct station_del_parameters *params)
 {
        struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, mac);
+       wil6210_disconnect(wil, params->mac, false);
        mutex_unlock(&wil->mutex);
 
        return 0;
index 6500caf8d609ccd90fae94ce704635df1b50cb16..6212983fede27d36ce520f78f40668531e7e96ff 100644 (file)
@@ -38,6 +38,35 @@ static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
 module_param(itr_trsh, uint, S_IRUGO);
 MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
 
+/* We allow allocation of more than 1 page buffers to support large packets.
+ * It is suboptimal behavior performance wise in case MTU above page size.
+ */
+unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN;
+static int mtu_max_set(const char *val, const struct kernel_param *kp)
+{
+       int ret;
+
+       /* sets mtu_max directly. no need to restore it in case of
+        * illegal value since we assume this will fail insmod
+        */
+       ret = param_set_uint(val, kp);
+       if (ret)
+               return ret;
+
+       if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static struct kernel_param_ops mtu_max_ops = {
+       .set = mtu_max_set,
+       .get = param_get_uint,
+};
+
+module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO);
+MODULE_PARM_DESC(mtu_max, " Max MTU value.");
+
 #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */
 #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */
 
@@ -74,7 +103,8 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
                __raw_writel(*s++, d++);
 }
 
-static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
+static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
+                              bool from_event)
 {
        uint i;
        struct net_device *ndev = wil_to_ndev(wil);
@@ -86,7 +116,10 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
 
        sta->data_port_open = false;
        if (sta->status != wil_sta_unused) {
-               wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING);
+               if (!from_event)
+                       wmi_disconnect_sta(wil, sta->addr,
+                                          WLAN_REASON_DEAUTH_LEAVING);
+
                switch (wdev->iftype) {
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_P2P_GO:
@@ -118,7 +151,8 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid)
        memset(&sta->stats, 0, sizeof(sta->stats));
 }
 
-static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
+static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+                               bool from_event)
 {
        int cid = -ENOENT;
        struct net_device *ndev = wil_to_ndev(wil);
@@ -133,10 +167,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
        }
 
        if (cid >= 0) /* disconnect 1 peer */
-               wil_disconnect_cid(wil, cid);
+               wil_disconnect_cid(wil, cid, from_event);
        else /* disconnect all */
                for (cid = 0; cid < WIL6210_MAX_CID; cid++)
-                       wil_disconnect_cid(wil, cid);
+                       wil_disconnect_cid(wil, cid, from_event);
 
        /* link state */
        switch (wdev->iftype) {
@@ -166,7 +200,7 @@ static void wil_disconnect_worker(struct work_struct *work)
                        struct wil6210_priv, disconnect_worker);
 
        mutex_lock(&wil->mutex);
-       _wil6210_disconnect(wil, NULL);
+       _wil6210_disconnect(wil, NULL, false);
        mutex_unlock(&wil->mutex);
 }
 
@@ -223,6 +257,11 @@ static void wil_fw_error_worker(struct work_struct *work)
 
        wil_dbg_misc(wil, "fw error worker\n");
 
+       if (!netif_running(wil_to_ndev(wil))) {
+               wil_info(wil, "No recovery - interface is down\n");
+               return;
+       }
+
        /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
         * passed since last recovery attempt
         */
@@ -257,9 +296,12 @@ static void wil_fw_error_worker(struct work_struct *work)
                break;
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
+               wil_info(wil, "No recovery for AP-like interface\n");
                /* recovery in these modes is done by upper layers */
                break;
        default:
+               wil_err(wil, "No recovery - unknown interface type %d\n",
+                       wdev->iftype);
                break;
        }
        mutex_unlock(&wil->mutex);
@@ -346,12 +388,22 @@ int wil_priv_init(struct wil6210_priv *wil)
        return 0;
 }
 
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid)
+/**
+ * wil6210_disconnect - disconnect one connection
+ * @wil: driver context
+ * @bssid: peer to disconnect, NULL to disconnect all
+ * @from_event: whether is invoked from FW event handler
+ *
+ * Disconnect and release associated resources. If invoked not from the
+ * FW event handler, issue WMI command(s) to trigger MAC disconnect.
+ */
+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+                       bool from_event)
 {
        wil_dbg_misc(wil, "%s()\n", __func__);
 
        del_timer_sync(&wil->connect_timer);
-       _wil6210_disconnect(wil, bssid);
+       _wil6210_disconnect(wil, bssid, from_event);
 }
 
 void wil_priv_deinit(struct wil6210_priv *wil)
@@ -363,7 +415,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
        cancel_work_sync(&wil->disconnect_worker);
        cancel_work_sync(&wil->fw_error_worker);
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, NULL);
+       wil6210_disconnect(wil, NULL, false);
        mutex_unlock(&wil->mutex);
        wmi_event_flush(wil);
        destroy_workqueue(wil->wmi_wq_conn);
@@ -395,7 +447,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
 static int wil_target_reset(struct wil6210_priv *wil)
 {
        int delay = 0;
-       u32 hw_state;
+       u32 x;
        u32 rev_id;
        bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
 
@@ -410,9 +462,22 @@ static int wil_target_reset(struct wil6210_priv *wil)
        S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST);
 
        wil_halt_cpu(wil);
-       C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */
 
        if (is_sparrow) {
+               S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
+               /* XTAL stabilization should take about 3ms */
+               usleep_range(5000, 7000);
+               x = R(RGF_CAF_PLL_LOCK_STATUS);
+               if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) {
+                       wil_err(wil, "Xtal stabilization timeout\n"
+                               "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x);
+                       return -ETIME;
+               }
+               /* switch 10k to XTAL*/
+               C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF);
+               /* 40 MHz */
+               C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL);
+
                W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f);
                W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf);
        }
@@ -453,13 +518,13 @@ static int wil_target_reset(struct wil6210_priv *wil)
        /* wait until device ready. typical time is 200..250 msec */
        do {
                msleep(RST_DELAY);
-               hw_state = R(RGF_USER_HW_MACHINE_STATE);
+               x = R(RGF_USER_HW_MACHINE_STATE);
                if (delay++ > RST_COUNT) {
                        wil_err(wil, "Reset not completed, hw_state 0x%08x\n",
-                               hw_state);
+                               x);
                        return -ETIME;
                }
-       } while (hw_state != HW_MACHINE_BOOT_DONE);
+       } while (x != HW_MACHINE_BOOT_DONE);
 
        /* TODO: Erez check rev_id != 1 */
        if (!is_sparrow && (rev_id != 1))
@@ -535,7 +600,7 @@ int wil_reset(struct wil6210_priv *wil)
        WARN_ON(test_bit(wil_status_napi_en, &wil->status));
 
        cancel_work_sync(&wil->disconnect_worker);
-       wil6210_disconnect(wil, NULL);
+       wil6210_disconnect(wil, NULL, false);
 
        wil->status = 0; /* prevent NAPI from being scheduled */
 
index 239965106c05d1f878f52cd8b552047d2743d998..e81703ca7701cbc1e04413d51c3af25a2d4d7986 100644 (file)
@@ -41,7 +41,7 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu)
 {
        struct wil6210_priv *wil = ndev_to_wil(ndev);
 
-       if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) {
+       if (new_mtu < 68 || new_mtu > mtu_max) {
                wil_err(wil, "invalid MTU %d\n", new_mtu);
                return -EINVAL;
        }
index 2936ef0c18cbc700003760e5a93a9f504b9d8840..c680906bc0dc6ebbcba1aa270c11d7cc7c0681fc 100644 (file)
@@ -206,7 +206,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring,
                               u32 i, int headroom)
 {
        struct device *dev = wil_to_dev(wil);
-       unsigned int sz = RX_BUF_LEN;
+       unsigned int sz = mtu_max + ETH_HLEN;
        struct vring_rx_desc dd, *d = &dd;
        volatile struct vring_rx_desc *_d = &vring->va[i].rx;
        dma_addr_t pa;
@@ -385,7 +385,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        struct vring_rx_desc *d;
        struct sk_buff *skb;
        dma_addr_t pa;
-       unsigned int sz = RX_BUF_LEN;
+       unsigned int sz = mtu_max + ETH_HLEN;
        u16 dmalen;
        u8 ftype;
        u8 ds_bits;
@@ -646,7 +646,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
                .action = cpu_to_le32(WMI_VRING_CMD_ADD),
                .vring_cfg = {
                        .tx_sw_ring = {
-                               .max_mpdu_size = cpu_to_le16(TX_BUF_LEN),
+                               .max_mpdu_size =
+                                       cpu_to_le16(mtu_max + ETH_HLEN),
                                .ring_size = cpu_to_le16(size),
                        },
                        .ringid = id,
index de046716d2b7e2de3c96e2f8aaff266796c78967..630aeb5fa7f4a50f37b90d99137ce591bc4c2b9e 100644 (file)
@@ -21,8 +21,8 @@
 #define BUF_HW_OWNED    (0)
 
 /* size of max. Tx/Rx buffers, as supported by FW */
-#define RX_BUF_LEN      (2242)
-#define TX_BUF_LEN      (2242)
+#define TXRX_BUF_LEN_DEFAULT (2242)
+
 /* how many bytes to reserve for rtap header? */
 #define WIL6210_RTAP_SIZE (128)
 
index ce6488e42091cf8a935bfe87dd84baad34224656..95d3a062d35c57d9634dba7bf10a836891de9c50 100644 (file)
@@ -24,6 +24,7 @@
 #include "wil_platform.h"
 
 extern bool no_fw_recovery;
+extern unsigned int mtu_max;
 
 #define WIL_NAME "wil6210"
 #define WIL_FW_NAME "wil6210.fw"
@@ -117,6 +118,8 @@ struct RGF_ICR {
        #define BIT_USER_USER_ICR_SW_INT_2      BIT(18)
 #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0     (0x880c18)
 #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1     (0x880c2c)
+#define RGF_USER_SPARROW_M_4                   (0x880c50) /* Sparrow */
+       #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF        BIT(2)
 
 #define RGF_DMA_EP_TX_ICR              (0x881bb4) /* struct RGF_ICR */
        #define BIT_DMA_EP_TX_ICR_TX_DONE       BIT(0)
@@ -152,6 +155,10 @@ struct RGF_ICR {
 #define RGF_MAC_MTRL_COUNTER_0         (0x886aa8)
 
 #define RGF_CAF_ICR                    (0x88946c) /* struct RGF_ICR */
+#define RGF_CAF_OSC_CONTROL            (0x88afa4)
+       #define BIT_CAF_OSC_XTAL_EN             BIT(0)
+#define RGF_CAF_PLL_LOCK_STATUS                (0x88afec)
+       #define BIT_CAF_OSC_DIG_XTAL_STABLE     BIT(0)
 
 /* popular locations */
 #define HOST_MBOX   HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
@@ -463,8 +470,11 @@ struct wil6210_priv {
 #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
 #define wil_to_pcie_dev(i) (&i->pdev->dev)
 
+__printf(2, 3)
 void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
+__printf(2, 3)
 void wil_err(struct wil6210_priv *wil, const char *fmt, ...);
+__printf(2, 3)
 void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
 #define wil_dbg(wil, fmt, arg...) do { \
        netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
@@ -575,7 +585,8 @@ void wil_wdev_free(struct wil6210_priv *wil);
 int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
 int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
 int wmi_pcp_stop(struct wil6210_priv *wil);
-void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid);
+void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
+                       bool from_event);
 
 int wil_rx_init(struct wil6210_priv *wil);
 void wil_rx_fini(struct wil6210_priv *wil);
index 4311df982c6074cf54e2fe43a8971f4aa355725e..bb1e066f756a88cd3920cbc62ccf251c5fa6aa4e 100644 (file)
@@ -486,7 +486,7 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
        wil->sinfo_gen++;
 
        mutex_lock(&wil->mutex);
-       wil6210_disconnect(wil, evt->bssid);
+       wil6210_disconnect(wil, evt->bssid, true);
        mutex_unlock(&wil->mutex);
 }
 
@@ -1025,7 +1025,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
        struct wmi_cfg_rx_chain_cmd cmd = {
                .action = WMI_RX_CHAIN_ADD,
                .rx_sw_ring = {
-                       .max_mpdu_size = cpu_to_le16(RX_BUF_LEN),
+                       .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN),
                        .ring_mem_base = cpu_to_le64(vring->pa),
                        .ring_size = cpu_to_le16(vring->size),
                },
index 90a977fe9a648d0f34eda15bbcba305eac6d35c0..dc4c75083085bbe3afe09d53ed68ffe207c93102 100644 (file)
@@ -23,15 +23,15 @@ ccflags-y += -D__CHECK_ENDIAN__
 
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += \
-               wl_cfg80211.o \
+               cfg80211.o \
                chip.o \
                fwil.o \
                fweh.o \
                fwsignal.o \
                p2p.o \
                proto.o \
-               dhd_common.o \
-               dhd_linux.o \
+               common.o \
+               core.o \
                firmware.o \
                feature.o \
                btcoex.o \
@@ -43,14 +43,14 @@ brcmfmac-$(CONFIG_BRCMFMAC_PROTO_MSGBUF) += \
                flowring.o \
                msgbuf.o
 brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \
-               dhd_sdio.o \
+               sdio.o \
                bcmsdh.o
 brcmfmac-$(CONFIG_BRCMFMAC_USB) += \
                usb.o
 brcmfmac-$(CONFIG_BRCMFMAC_PCIE) += \
                pcie.o
 brcmfmac-$(CONFIG_BRCMDBG) += \
-               dhd_dbg.o
+               debug.o
 brcmfmac-$(CONFIG_BRCM_TRACING) += \
                tracepoint.o
 brcmfmac-$(CONFIG_OF) += \
index a159ff3427de9fa7c3e42c508bc6a0c8930e5cdb..8e0e91c4a0b1670526683ced476e7b366451752e 100644 (file)
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 
-#include "dhd.h"
-#include "dhd_bus.h"
+#include "core.h"
+#include "bus.h"
 #include "fwsignal.h"
-#include "dhd_dbg.h"
+#include "debug.h"
 #include "tracepoint.h"
 #include "proto.h"
 #include "bcdc.h"
index 8dbd5dbb78fd14c8b697c04379e88bdf7442784f..f754ffcd030864ffd93f9bff4f86e80e249ea7c4 100644 (file)
@@ -41,9 +41,9 @@
 #include <chipcommon.h>
 #include <soc.h>
 #include "chip.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-#include "sdio_host.h"
+#include "bus.h"
+#include "debug.h"
+#include "sdio.h"
 #include "of.h"
 
 #define SDIOH_API_ACCESS_RETRY_LIMIT   2
@@ -1064,6 +1064,16 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        if (!sdiodev->pdata)
                brcmf_of_probe(sdiodev);
 
+#ifdef CONFIG_PM_SLEEP
+       /* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
+        * is true or when platform data OOB irq is true).
+        */
+       if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
+           ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
+            (sdiodev->pdata->oob_irq_supported)))
+               bus_if->wowl_supported = true;
+#endif
+
        atomic_set(&sdiodev->suspend, false);
        init_waitqueue_head(&sdiodev->request_word_wait);
        init_waitqueue_head(&sdiodev->request_buffer_wait);
@@ -1116,34 +1126,39 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
        brcmf_dbg(SDIO, "Exit\n");
 }
 
+void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+
+       brcmf_dbg(SDIO, "Configuring WOWL, enabled=%d\n", enabled);
+       sdiodev->wowl_enabled = enabled;
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int brcmf_ops_sdio_suspend(struct device *dev)
 {
-       mmc_pm_flag_t sdio_flags;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
-       int ret = 0;
+       mmc_pm_flag_t sdio_flags;
 
        brcmf_dbg(SDIO, "Enter\n");
 
-       sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
-       if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
-               brcmf_err("Host can't keep power while suspended\n");
-               return -EINVAL;
-       }
-
        atomic_set(&sdiodev->suspend, true);
 
-       ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
-       if (ret) {
-               brcmf_err("Failed to set pm_flags\n");
-               atomic_set(&sdiodev->suspend, false);
-               return ret;
+       if (sdiodev->wowl_enabled) {
+               sdio_flags = MMC_PM_KEEP_POWER;
+               if (sdiodev->pdata->oob_irq_supported)
+                       enable_irq_wake(sdiodev->pdata->oob_irq_nr);
+               else
+                       sdio_flags = MMC_PM_WAKE_SDIO_IRQ;
+               if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
+                       brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
        }
 
        brcmf_sdio_wd_timer(sdiodev->bus, 0);
 
-       return ret;
+       return 0;
 }
 
 static int brcmf_ops_sdio_resume(struct device *dev)
@@ -1152,6 +1167,8 @@ static int brcmf_ops_sdio_resume(struct device *dev)
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
        brcmf_dbg(SDIO, "Enter\n");
+       if (sdiodev->pdata->oob_irq_supported)
+               disable_irq_wake(sdiodev->pdata->oob_irq_nr);
        brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
        atomic_set(&sdiodev->suspend, false);
        return 0;
index a29ac4977b3a12e009f2947c09bd40d3b604ccde..0445163991b72cf34e78b353825b6505e3775dd1 100644 (file)
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
 #include <defs.h>
-#include <dhd.h>
-#include <dhd_dbg.h>
+#include "core.h"
+#include "debug.h"
 #include "fwil.h"
 #include "fwil_types.h"
 #include "btcoex.h"
 #include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
 
 /* T1 start SCO/eSCO priority suppression */
 #define BRCMF_BTCOEX_OPPR_WIN_TIME   2000
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
rename to drivers/net/wireless/brcm80211/brcmfmac/bus.h
index 80e73a1262be81b6d143f4a8967e960def536fa7..ef344e47218a3ab153f86fba35f510c6dc6cd809 100644 (file)
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef _BRCMF_BUS_H_
-#define _BRCMF_BUS_H_
+#ifndef BRCMFMAC_BUS_H
+#define BRCMFMAC_BUS_H
 
-#include "dhd_dbg.h"
+#include "debug.h"
 
 /* IDs of the 6 default common rings of msgbuf protocol */
 #define BRCMF_H2D_MSGRING_CONTROL_SUBMIT       0
@@ -227,8 +227,7 @@ void brcmf_txflowblock(struct device *dev, bool state);
 void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
 
 int brcmf_bus_start(struct device *dev);
-s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data,
-                               u32 len);
+s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
 void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
 
 #ifdef CONFIG_BRCMFMAC_SDIO
@@ -241,4 +240,4 @@ void brcmf_usb_exit(void);
 void brcmf_usb_register(void);
 #endif
 
-#endif                         /* _BRCMF_BUS_H_ */
+#endif /* BRCMFMAC_BUS_H */
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
rename to drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
index 28fa25b509db8c3154d2ff0220d4b05c5f83c99d..e418969679c9c558cb5045691d9d195957625542 100644 (file)
 #include <brcmu_utils.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "debug.h"
 #include "tracepoint.h"
 #include "fwil_types.h"
 #include "p2p.h"
 #include "btcoex.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
 #include "feature.h"
 #include "fwil.h"
 #include "proto.h"
 #include "vendor.h"
-#include "dhd_bus.h"
+#include "bus.h"
 
 #define BRCMF_SCAN_IE_LEN_MAX          2048
 #define BRCMF_PNO_VERSION              2
@@ -2779,6 +2779,44 @@ static __always_inline void brcmf_delay(u32 ms)
        }
 }
 
+static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
+                                    u8 *pattern, u32 patternsize, u8 *mask,
+                                    u32 packet_offset)
+{
+       struct brcmf_fil_wowl_pattern_le *filter;
+       u32 masksize;
+       u32 patternoffset;
+       u8 *buf;
+       u32 bufsize;
+       s32 ret;
+
+       masksize = (patternsize + 7) / 8;
+       patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
+
+       bufsize = sizeof(*filter) + patternsize + masksize;
+       buf = kzalloc(bufsize, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       filter = (struct brcmf_fil_wowl_pattern_le *)buf;
+
+       memcpy(filter->cmd, cmd, 4);
+       filter->masksize = cpu_to_le32(masksize);
+       filter->offset = cpu_to_le32(packet_offset);
+       filter->patternoffset = cpu_to_le32(patternoffset);
+       filter->patternsize = cpu_to_le32(patternsize);
+       filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
+
+       if ((mask) && (masksize))
+               memcpy(buf + sizeof(*filter), mask, masksize);
+       if ((pattern) && (patternsize))
+               memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
+
+       ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
+
+       kfree(buf);
+       return ret;
+}
+
 static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
@@ -2788,10 +2826,11 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
        brcmf_dbg(TRACE, "Enter\n");
 
        if (cfg->wowl_enabled) {
+               brcmf_configure_arp_offload(ifp, true);
                brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
                                      cfg->pre_wowl_pmmode);
-               brcmf_fil_iovar_data_set(ifp, "wowl_pattern", "clr", 4);
                brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
+               brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
                cfg->wowl_enabled = false;
        }
        return 0;
@@ -2802,21 +2841,29 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
                                 struct cfg80211_wowlan *wowl)
 {
        u32 wowl_config;
+       u32 i;
 
        brcmf_dbg(TRACE, "Suspend, wowl config.\n");
 
+       brcmf_configure_arp_offload(ifp, false);
        brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->pre_wowl_pmmode);
        brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
 
        wowl_config = 0;
        if (wowl->disconnect)
-               wowl_config |= WL_WOWL_DIS | WL_WOWL_BCN | WL_WOWL_RETR;
-               /* Note: if "wowl" target and not "wowlpf" then wowl_bcn_loss
-                * should be configured. This paramater is not supported by
-                * wowlpf.
-                */
+               wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
        if (wowl->magic_pkt)
-               wowl_config |= WL_WOWL_MAGIC;
+               wowl_config |= BRCMF_WOWL_MAGIC;
+       if ((wowl->patterns) && (wowl->n_patterns)) {
+               wowl_config |= BRCMF_WOWL_NET;
+               for (i = 0; i < wowl->n_patterns; i++) {
+                       brcmf_config_wowl_pattern(ifp, "add",
+                               (u8 *)wowl->patterns[i].pattern,
+                               wowl->patterns[i].pattern_len,
+                               (u8 *)wowl->patterns[i].mask,
+                               wowl->patterns[i].pkt_offset);
+               }
+       }
        brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
        brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
        brcmf_bus_wowl_config(cfg->pub->bus_if, true);
@@ -3998,24 +4045,24 @@ brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev,
 
 static int
 brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
-                          const u8 *mac)
+                          struct station_del_parameters *params)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_scb_val_le scbval;
        struct brcmf_if *ifp = netdev_priv(ndev);
        s32 err;
 
-       if (!mac)
+       if (!params->mac)
                return -EFAULT;
 
-       brcmf_dbg(TRACE, "Enter %pM\n", mac);
+       brcmf_dbg(TRACE, "Enter %pM\n", params->mac);
 
        if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
                ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
        if (!check_vif_up(ifp->vif))
                return -EIO;
 
-       memcpy(&scbval.ea, mac, ETH_ALEN);
+       memcpy(&scbval.ea, params->mac, ETH_ALEN);
        scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
        err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
                                     &scbval, sizeof(scbval));
@@ -5440,10 +5487,13 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
        wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 }
 
-
 #ifdef CONFIG_PM
 static const struct wiphy_wowlan_support brcmf_wowlan_support = {
        .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+       .n_patterns = BRCMF_WOWL_MAXPATTERNS,
+       .pattern_max_len = BRCMF_WOWL_MAXPATTERNSIZE,
+       .pattern_min_len = 1,
+       .max_pkt_offset = 1500,
 };
 #endif
 
@@ -5607,7 +5657,8 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp)
        return wdev->iftype;
 }
 
-bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state)
+bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
+                            unsigned long state)
 {
        struct brcmf_cfg80211_vif *vif;
 
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
rename to drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
index 6abf94e41d3d0683b3f5e95da0fadb3b1f0f8c3b..2a5b22cb3fef2ad8e5743b4b48c37a6f12123a10 100644 (file)
@@ -14,8 +14,8 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef _wl_cfg80211_h_
-#define _wl_cfg80211_h_
+#ifndef BRCMFMAC_CFG80211_H
+#define BRCMFMAC_CFG80211_H
 
 /* for brcmu_d11inf */
 #include <brcmu_d11.h>
@@ -480,7 +480,8 @@ const struct brcmf_tlv *
 brcmf_parse_tlvs(const void *buf, int buflen, uint key);
 u16 channel_to_chanspec(struct brcmu_d11inf *d11inf,
                        struct ieee80211_channel *ch);
-bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg, unsigned long state);
+bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
+                            unsigned long state);
 void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
                                  struct brcmf_cfg80211_vif *vif);
 bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
@@ -493,4 +494,4 @@ void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
 void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
 void brcmf_cfg80211_free_netdev(struct net_device *ndev);
 
-#endif                         /* _wl_cfg80211_h_ */
+#endif /* BRCMFMAC_CFG80211_H */
index 95efde868db82e6b36e0c954fe4d0ad2cd797721..ddae0b5e56eced02eed599d41decd62ab7b2e273 100644 (file)
@@ -25,7 +25,7 @@
 #include <brcm_hw_ids.h>
 #include <brcmu_utils.h>
 #include <chipcommon.h>
-#include "dhd_dbg.h"
+#include "debug.h"
 #include "chip.h"
 
 /* SOC Interconnect types (aka chip types) */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c
new file mode 100644 (file)
index 0000000..1861a13
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2010 Broadcom Corporation
+ *
+ * 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/kernel.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
+#include "fwil.h"
+#include "fwil_types.h"
+#include "tracepoint.h"
+
+#define BRCMF_DEFAULT_BCN_TIMEOUT      3
+#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME        40
+#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
+
+/* boost value for RSSI_DELTA in preferred join selection */
+#define BRCMF_JOIN_PREF_RSSI_BOOST     8
+
+int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
+{
+       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+       u8 buf[BRCMF_DCMD_SMLEN];
+       struct brcmf_join_pref_params join_pref_params[2];
+       char *ptr;
+       s32 err;
+
+       /* retreive mac address */
+       err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
+                                      sizeof(ifp->mac_addr));
+       if (err < 0) {
+               brcmf_err("Retreiving cur_etheraddr failed, %d\n",
+                         err);
+               goto done;
+       }
+       memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
+
+       /* query for 'ver' to get version info from firmware */
+       memset(buf, 0, sizeof(buf));
+       strcpy(buf, "ver");
+       err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
+       if (err < 0) {
+               brcmf_err("Retreiving version information failed, %d\n",
+                         err);
+               goto done;
+       }
+       ptr = (char *)buf;
+       strsep(&ptr, "\n");
+
+       /* Print fw version info */
+       brcmf_err("Firmware version = %s\n", buf);
+
+       /* locate firmware version number for ethtool */
+       ptr = strrchr(buf, ' ') + 1;
+       strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
+
+       /* set mpc */
+       err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
+       if (err) {
+               brcmf_err("failed setting mpc\n");
+               goto done;
+       }
+
+       /*
+        * Setup timeout if Beacons are lost and roam is off to report
+        * link down
+        */
+       err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
+                                     BRCMF_DEFAULT_BCN_TIMEOUT);
+       if (err) {
+               brcmf_err("bcn_timeout error (%d)\n", err);
+               goto done;
+       }
+
+       /* Enable/Disable build-in roaming to allowed ext supplicant to take
+        * of romaing
+        */
+       err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
+       if (err) {
+               brcmf_err("roam_off error (%d)\n", err);
+               goto done;
+       }
+
+       /* Setup join_pref to select target by RSSI(with boost on 5GHz) */
+       join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
+       join_pref_params[0].len = 2;
+       join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
+       join_pref_params[0].band = WLC_BAND_5G;
+       join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
+       join_pref_params[1].len = 2;
+       join_pref_params[1].rssi_gain = 0;
+       join_pref_params[1].band = 0;
+       err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
+                                      sizeof(join_pref_params));
+       if (err)
+               brcmf_err("Set join_pref error (%d)\n", err);
+
+       /* Setup event_msgs, enable E_IF */
+       err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
+                                      BRCMF_EVENTING_MASK_LEN);
+       if (err) {
+               brcmf_err("Get event_msgs error (%d)\n", err);
+               goto done;
+       }
+       setbit(eventmask, BRCMF_E_IF);
+       err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
+                                      BRCMF_EVENTING_MASK_LEN);
+       if (err) {
+               brcmf_err("Set event_msgs error (%d)\n", err);
+               goto done;
+       }
+
+       /* Setup default scan channel time */
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+                                   BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
+       if (err) {
+               brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
+                         err);
+               goto done;
+       }
+
+       /* Setup default scan unassoc time */
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+                                   BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
+       if (err) {
+               brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
+                         err);
+               goto done;
+       }
+
+       /* do bus specific preinit here */
+       err = brcmf_bus_preinit(ifp->drvr->bus_if);
+done:
+       return err;
+}
+
+#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
+void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       if (brcmf_msg_level & level)
+               pr_debug("%s %pV", func, &vaf);
+       trace_brcmf_dbg(level, func, &vaf);
+       va_end(args);
+}
+#endif
index c6d65b8e1e1565c6aaa9fed7b9af5902516d855d..77656c711bedbfc44a8a7ddf97b58cb3efabf24a 100644 (file)
@@ -19,7 +19,7 @@
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 
-#include "dhd.h"
+#include "core.h"
 #include "commonring.h"
 
 
similarity index 99%
rename from drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
rename to drivers/net/wireless/brcm80211/brcmfmac/core.c
index fb1043908a23eec22c71845d83686b81c872da21..f407665cb1eaab430e2ffed21a3181280f44cdd9 100644 (file)
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
 #include "fwil_types.h"
 #include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
 #include "fwil.h"
 #include "fwsignal.h"
 #include "feature.h"
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/dhd.h
rename to drivers/net/wireless/brcm80211/brcmfmac/core.h
index 5e4317dbc2b0a14b00c464c5e3e1f6e30689a046..98228e922d3ae3dffd83e38b328c960700008db1 100644 (file)
@@ -18,8 +18,8 @@
  * Common types *
  */
 
-#ifndef _BRCMF_H_
-#define _BRCMF_H_
+#ifndef BRCMFMAC_CORE_H
+#define BRCMFMAC_CORE_H
 
 #include "fweh.h"
 
@@ -83,7 +83,6 @@ struct brcmf_pub {
        /* Internal brcmf items */
        uint hdrlen;            /* Total BRCMF header length (proto + bus) */
        uint rxsz;              /* Rx buffer size bus module should use */
-       u8 wme_dp;              /* wme discard priority */
 
        /* Dongle media info */
        char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];
@@ -186,4 +185,4 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
 /* Sets dongle media info (drv_version, mac address). */
 int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
 
-#endif                         /* _BRCMF_H_ */
+#endif /* BRCMFMAC_CORE_H */
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
rename to drivers/net/wireless/brcm80211/brcmfmac/debug.c
index be9f4f829192cc020294f08950b0fe995fca10dc..9b473d50b0058d68ba8cf60c02f4cbd55b60edb0 100644 (file)
@@ -19,9 +19,9 @@
 
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
 
 static struct dentry *root_folder;
 
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
rename to drivers/net/wireless/brcm80211/brcmfmac/debug.h
index dec40d316c829129cfd86b5043cfc3fbdedb03b4..eb0b8c47479d1f7acaadd1ca2f129e2fa07dbe2c 100644 (file)
@@ -14,8 +14,8 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef _BRCMF_DBG_H_
-#define _BRCMF_DBG_H_
+#ifndef BRCMFMAC_DEBUG_H
+#define BRCMFMAC_DEBUG_H
 
 /* message levels */
 #define BRCMF_TRACE_VAL                0x00000002
@@ -133,4 +133,4 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
 }
 #endif
 
-#endif                         /* _BRCMF_DBG_H_ */
+#endif /* BRCMFMAC_DEBUG_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
deleted file mode 100644 (file)
index d991f8e..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * 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/kernel.h>
-#include <linux/string.h>
-#include <linux/netdevice.h>
-#include <brcmu_wifi.h>
-#include <brcmu_utils.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
-#include "fwil.h"
-#include "fwil_types.h"
-#include "tracepoint.h"
-
-#define PKTFILTER_BUF_SIZE             128
-#define BRCMF_DEFAULT_BCN_TIMEOUT      3
-#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME        40
-#define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
-#define BRCMF_DEFAULT_PACKET_FILTER    "100 0 0 0 0x01 0x00"
-
-/* boost value for RSSI_DELTA in preferred join selection */
-#define BRCMF_JOIN_PREF_RSSI_BOOST     8
-
-
-bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
-                     struct sk_buff *pkt, int prec)
-{
-       struct sk_buff *p;
-       int eprec = -1;         /* precedence to evict from */
-       bool discard_oldest;
-       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_pub *drvr = bus_if->drvr;
-
-       /* Fast case, precedence queue is not full and we are also not
-        * exceeding total queue length
-        */
-       if (!pktq_pfull(q, prec) && !pktq_full(q)) {
-               brcmu_pktq_penq(q, prec, pkt);
-               return true;
-       }
-
-       /* Determine precedence from which to evict packet, if any */
-       if (pktq_pfull(q, prec))
-               eprec = prec;
-       else if (pktq_full(q)) {
-               p = brcmu_pktq_peek_tail(q, &eprec);
-               if (eprec > prec)
-                       return false;
-       }
-
-       /* Evict if needed */
-       if (eprec >= 0) {
-               /* Detect queueing to unconfigured precedence */
-               discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
-               if (eprec == prec && !discard_oldest)
-                       return false;   /* refuse newer (incoming) packet */
-               /* Evict packet according to discard policy */
-               p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
-                       brcmu_pktq_pdeq_tail(q, eprec);
-               if (p == NULL)
-                       brcmf_err("brcmu_pktq_penq() failed, oldest %d\n",
-                                 discard_oldest);
-
-               brcmu_pkt_buf_free_skb(p);
-       }
-
-       /* Enqueue */
-       p = brcmu_pktq_penq(q, prec, pkt);
-       if (p == NULL)
-               brcmf_err("brcmu_pktq_penq() failed\n");
-
-       return p != NULL;
-}
-
-/* Convert user's input in hex pattern to byte-size mask */
-static int brcmf_c_pattern_atoh(char *src, char *dst)
-{
-       int i;
-       if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
-               brcmf_err("Mask invalid format. Needs to start with 0x\n");
-               return -EINVAL;
-       }
-       src = src + 2;          /* Skip past 0x */
-       if (strlen(src) % 2 != 0) {
-               brcmf_err("Mask invalid format. Length must be even.\n");
-               return -EINVAL;
-       }
-       for (i = 0; *src != '\0'; i++) {
-               unsigned long res;
-               char num[3];
-               strncpy(num, src, 2);
-               num[2] = '\0';
-               if (kstrtoul(num, 16, &res))
-                       return -EINVAL;
-               dst[i] = (u8)res;
-               src += 2;
-       }
-       return i;
-}
-
-static void
-brcmf_c_pktfilter_offload_enable(struct brcmf_if *ifp, char *arg, int enable,
-                                int master_mode)
-{
-       unsigned long res;
-       char *argv;
-       char *arg_save = NULL, *arg_org = NULL;
-       s32 err;
-       struct brcmf_pkt_filter_enable_le enable_parm;
-
-       arg_save = kstrdup(arg, GFP_ATOMIC);
-       if (!arg_save)
-               goto fail;
-
-       arg_org = arg_save;
-
-       argv = strsep(&arg_save, " ");
-
-       if (argv == NULL) {
-               brcmf_err("No args provided\n");
-               goto fail;
-       }
-
-       /* Parse packet filter id. */
-       enable_parm.id = 0;
-       if (!kstrtoul(argv, 0, &res))
-               enable_parm.id = cpu_to_le32((u32)res);
-
-       /* Enable/disable the specified filter. */
-       enable_parm.enable = cpu_to_le32(enable);
-
-       err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_enable", &enable_parm,
-                                      sizeof(enable_parm));
-       if (err)
-               brcmf_err("Set pkt_filter_enable error (%d)\n", err);
-
-       /* Control the master mode */
-       err = brcmf_fil_iovar_int_set(ifp, "pkt_filter_mode", master_mode);
-       if (err)
-               brcmf_err("Set pkt_filter_mode error (%d)\n", err);
-
-fail:
-       kfree(arg_org);
-}
-
-static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
-{
-       struct brcmf_pkt_filter_le *pkt_filter;
-       unsigned long res;
-       int buf_len;
-       s32 err;
-       u32 mask_size;
-       u32 pattern_size;
-       char *argv[8], *buf = NULL;
-       int i = 0;
-       char *arg_save = NULL, *arg_org = NULL;
-
-       arg_save = kstrdup(arg, GFP_ATOMIC);
-       if (!arg_save)
-               goto fail;
-
-       arg_org = arg_save;
-
-       buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
-       if (!buf)
-               goto fail;
-
-       argv[i] = strsep(&arg_save, " ");
-       while (argv[i]) {
-               i++;
-               if (i >= 8) {
-                       brcmf_err("Too many parameters\n");
-                       goto fail;
-               }
-               argv[i] = strsep(&arg_save, " ");
-       }
-
-       if (i != 6) {
-               brcmf_err("Not enough args provided %d\n", i);
-               goto fail;
-       }
-
-       pkt_filter = (struct brcmf_pkt_filter_le *)buf;
-
-       /* Parse packet filter id. */
-       pkt_filter->id = 0;
-       if (!kstrtoul(argv[0], 0, &res))
-               pkt_filter->id = cpu_to_le32((u32)res);
-
-       /* Parse filter polarity. */
-       pkt_filter->negate_match = 0;
-       if (!kstrtoul(argv[1], 0, &res))
-               pkt_filter->negate_match = cpu_to_le32((u32)res);
-
-       /* Parse filter type. */
-       pkt_filter->type = 0;
-       if (!kstrtoul(argv[2], 0, &res))
-               pkt_filter->type = cpu_to_le32((u32)res);
-
-       /* Parse pattern filter offset. */
-       pkt_filter->u.pattern.offset = 0;
-       if (!kstrtoul(argv[3], 0, &res))
-               pkt_filter->u.pattern.offset = cpu_to_le32((u32)res);
-
-       /* Parse pattern filter mask. */
-       mask_size = brcmf_c_pattern_atoh(argv[4],
-                       (char *)pkt_filter->u.pattern.mask_and_pattern);
-
-       /* Parse pattern filter pattern. */
-       pattern_size = brcmf_c_pattern_atoh(argv[5],
-               (char *)&pkt_filter->u.pattern.mask_and_pattern[mask_size]);
-
-       if (mask_size != pattern_size) {
-               brcmf_err("Mask and pattern not the same size\n");
-               goto fail;
-       }
-
-       pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
-       buf_len = offsetof(struct brcmf_pkt_filter_le,
-                          u.pattern.mask_and_pattern);
-       buf_len += mask_size + pattern_size;
-
-       err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
-                                      buf_len);
-       if (err)
-               brcmf_err("Set pkt_filter_add error (%d)\n", err);
-
-fail:
-       kfree(arg_org);
-
-       kfree(buf);
-}
-
-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
-{
-       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
-       u8 buf[BRCMF_DCMD_SMLEN];
-       struct brcmf_join_pref_params join_pref_params[2];
-       char *ptr;
-       s32 err;
-
-       /* retreive mac address */
-       err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
-                                      sizeof(ifp->mac_addr));
-       if (err < 0) {
-               brcmf_err("Retreiving cur_etheraddr failed, %d\n",
-                         err);
-               goto done;
-       }
-       memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
-
-       /* query for 'ver' to get version info from firmware */
-       memset(buf, 0, sizeof(buf));
-       strcpy(buf, "ver");
-       err = brcmf_fil_iovar_data_get(ifp, "ver", buf, sizeof(buf));
-       if (err < 0) {
-               brcmf_err("Retreiving version information failed, %d\n",
-                         err);
-               goto done;
-       }
-       ptr = (char *)buf;
-       strsep(&ptr, "\n");
-
-       /* Print fw version info */
-       brcmf_err("Firmware version = %s\n", buf);
-
-       /* locate firmware version number for ethtool */
-       ptr = strrchr(buf, ' ') + 1;
-       strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));
-
-       /* set mpc */
-       err = brcmf_fil_iovar_int_set(ifp, "mpc", 1);
-       if (err) {
-               brcmf_err("failed setting mpc\n");
-               goto done;
-       }
-
-       /*
-        * Setup timeout if Beacons are lost and roam is off to report
-        * link down
-        */
-       err = brcmf_fil_iovar_int_set(ifp, "bcn_timeout",
-                                     BRCMF_DEFAULT_BCN_TIMEOUT);
-       if (err) {
-               brcmf_err("bcn_timeout error (%d)\n", err);
-               goto done;
-       }
-
-       /* Enable/Disable build-in roaming to allowed ext supplicant to take
-        * of romaing
-        */
-       err = brcmf_fil_iovar_int_set(ifp, "roam_off", 1);
-       if (err) {
-               brcmf_err("roam_off error (%d)\n", err);
-               goto done;
-       }
-
-       /* Setup join_pref to select target by RSSI(with boost on 5GHz) */
-       join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
-       join_pref_params[0].len = 2;
-       join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
-       join_pref_params[0].band = WLC_BAND_5G;
-       join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
-       join_pref_params[1].len = 2;
-       join_pref_params[1].rssi_gain = 0;
-       join_pref_params[1].band = 0;
-       err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
-                                      sizeof(join_pref_params));
-       if (err)
-               brcmf_err("Set join_pref error (%d)\n", err);
-
-       /* Setup event_msgs, enable E_IF */
-       err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
-                                      BRCMF_EVENTING_MASK_LEN);
-       if (err) {
-               brcmf_err("Get event_msgs error (%d)\n", err);
-               goto done;
-       }
-       setbit(eventmask, BRCMF_E_IF);
-       err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask,
-                                      BRCMF_EVENTING_MASK_LEN);
-       if (err) {
-               brcmf_err("Set event_msgs error (%d)\n", err);
-               goto done;
-       }
-
-       /* Setup default scan channel time */
-       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_CHANNEL_TIME,
-                                   BRCMF_DEFAULT_SCAN_CHANNEL_TIME);
-       if (err) {
-               brcmf_err("BRCMF_C_SET_SCAN_CHANNEL_TIME error (%d)\n",
-                         err);
-               goto done;
-       }
-
-       /* Setup default scan unassoc time */
-       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCAN_UNASSOC_TIME,
-                                   BRCMF_DEFAULT_SCAN_UNASSOC_TIME);
-       if (err) {
-               brcmf_err("BRCMF_C_SET_SCAN_UNASSOC_TIME error (%d)\n",
-                         err);
-               goto done;
-       }
-
-       /* Setup packet filter */
-       brcmf_c_pktfilter_offload_set(ifp, BRCMF_DEFAULT_PACKET_FILTER);
-       brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,
-                                        0, true);
-
-       /* do bus specific preinit here */
-       err = brcmf_bus_preinit(ifp->drvr->bus_if);
-done:
-       return err;
-}
-
-#ifdef CONFIG_BRCM_TRACING
-void __brcmf_err(const char *func, const char *fmt, ...)
-{
-       struct va_format vaf = {
-               .fmt = fmt,
-       };
-       va_list args;
-
-       va_start(args, fmt);
-       vaf.va = &args;
-       pr_err("%s: %pV", func, &vaf);
-       trace_brcmf_err(func, &vaf);
-       va_end(args);
-}
-#endif
-#if defined(CONFIG_BRCM_TRACING) || defined(CONFIG_BRCMDBG)
-void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
-{
-       struct va_format vaf = {
-               .fmt = fmt,
-       };
-       va_list args;
-
-       va_start(args, fmt);
-       vaf.va = &args;
-       if (brcmf_msg_level & level)
-               pr_debug("%s %pV", func, &vaf);
-       trace_brcmf_dbg(level, func, &vaf);
-       va_end(args);
-}
-#endif
index aed53acef456a4404e2f26c9273c2ea966ea5605..931f68aefaa476684a735bdd7389cc6a003f9e4d 100644 (file)
 #include <linux/netdevice.h>
 
 #include <brcm_hw_ids.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
 #include "fwil.h"
 #include "feature.h"
 
-/*
- * firmware error code received if iovar is unsupported.
- */
-#define EBRCMF_FEAT_UNSUPPORTED                23
-
 /*
  * expand feature list to array of feature strings.
  */
index 8ea9f283d2b8065f4766978c2e43e05e6576fba6..0f157f151282ebe4446bd0aab04453d212ff6a77 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/firmware.h>
 #include <linux/module.h>
 
-#include "dhd_dbg.h"
+#include "debug.h"
 #include "firmware.h"
 
 char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
index 1faa929f5fff2c5fcfe667d7b585ca8621448d5a..44f3a84d1999c6b9e93f116d1b5f27a706546164 100644 (file)
@@ -19,9 +19,9 @@
 #include <linux/etherdevice.h>
 #include <brcmu_utils.h>
 
-#include "dhd.h"
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
+#include "core.h"
+#include "debug.h"
+#include "bus.h"
 #include "proto.h"
 #include "flowring.h"
 #include "msgbuf.h"
index 44fc85f68f7aceba2788da99126164b0a946a6a7..7338b335e153ead328b7ca79552ec29070bf85a9 100644 (file)
@@ -18,8 +18,8 @@
 #include "brcmu_wifi.h"
 #include "brcmu_utils.h"
 
-#include "dhd.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "debug.h"
 #include "tracepoint.h"
 #include "fwsignal.h"
 #include "fweh.h"
index ded328f80cd1237454274ce53fd39433249b0e85..51f88c11e642e71747ea7a4be11f2b7b7f9055ab 100644 (file)
@@ -22,9 +22,9 @@
 #include <linux/netdevice.h>
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
 #include "tracepoint.h"
 #include "fwil.h"
 #include "proto.h"
 
 #define MAX_HEX_DUMP_LEN       64
 
+#ifdef DEBUG
+static const char * const brcmf_fil_errstr[] = {
+       "BCME_OK",
+       "BCME_ERROR",
+       "BCME_BADARG",
+       "BCME_BADOPTION",
+       "BCME_NOTUP",
+       "BCME_NOTDOWN",
+       "BCME_NOTAP",
+       "BCME_NOTSTA",
+       "BCME_BADKEYIDX",
+       "BCME_RADIOOFF",
+       "BCME_NOTBANDLOCKED",
+       "BCME_NOCLK",
+       "BCME_BADRATESET",
+       "BCME_BADBAND",
+       "BCME_BUFTOOSHORT",
+       "BCME_BUFTOOLONG",
+       "BCME_BUSY",
+       "BCME_NOTASSOCIATED",
+       "BCME_BADSSIDLEN",
+       "BCME_OUTOFRANGECHAN",
+       "BCME_BADCHAN",
+       "BCME_BADADDR",
+       "BCME_NORESOURCE",
+       "BCME_UNSUPPORTED",
+       "BCME_BADLEN",
+       "BCME_NOTREADY",
+       "BCME_EPERM",
+       "BCME_NOMEM",
+       "BCME_ASSOCIATED",
+       "BCME_RANGE",
+       "BCME_NOTFOUND",
+       "BCME_WME_NOT_ENABLED",
+       "BCME_TSPEC_NOTFOUND",
+       "BCME_ACM_NOTSUPPORTED",
+       "BCME_NOT_WME_ASSOCIATION",
+       "BCME_SDIO_ERROR",
+       "BCME_DONGLE_DOWN",
+       "BCME_VERSION",
+       "BCME_TXFAIL",
+       "BCME_RXFAIL",
+       "BCME_NODEVICE",
+       "BCME_NMODE_DISABLED",
+       "BCME_NONRESIDENT",
+       "BCME_SCANREJECT",
+       "BCME_USAGE_ERROR",
+       "BCME_IOCTL_ERROR",
+       "BCME_SERIAL_PORT_ERR",
+       "BCME_DISABLED",
+       "BCME_DECERR",
+       "BCME_ENCERR",
+       "BCME_MICERR",
+       "BCME_REPLAY",
+       "BCME_IE_NOTFOUND",
+};
+
+static const char *brcmf_fil_get_errstr(u32 err)
+{
+       if (err >= ARRAY_SIZE(brcmf_fil_errstr))
+               return "(unknown)";
+
+       return brcmf_fil_errstr[err];
+}
+#else
+static const char *brcmf_fil_get_errstr(u32 err)
+{
+       return "";
+}
+#endif /* DEBUG */
 
 static s32
 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
@@ -52,11 +122,11 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
                err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
 
        if (err >= 0)
-               err = 0;
-       else
-               brcmf_dbg(FIL, "Failed err=%d\n", err);
+               return 0;
 
-       return err;
+       brcmf_dbg(FIL, "Failed: %s (%d)\n",
+                 brcmf_fil_get_errstr((u32)(-err)), err);
+       return -EBADE;
 }
 
 s32
index 5ff5cd0bb0325f0d23c2ad1359b113b8f69b2cc8..ba64b292f7a516590071beba37f103ec7099d2cf 100644 (file)
 
 /* WOWL bits */
 /* Wakeup on Magic packet: */
-#define WL_WOWL_MAGIC                  (1 << 0)
+#define BRCMF_WOWL_MAGIC               (1 << 0)
 /* Wakeup on Netpattern */
-#define WL_WOWL_NET                    (1 << 1)
+#define BRCMF_WOWL_NET                 (1 << 1)
 /* Wakeup on loss-of-link due to Disassoc/Deauth: */
-#define WL_WOWL_DIS                    (1 << 2)
+#define BRCMF_WOWL_DIS                 (1 << 2)
 /* Wakeup on retrograde TSF: */
-#define WL_WOWL_RETR                   (1 << 3)
+#define BRCMF_WOWL_RETR                        (1 << 3)
 /* Wakeup on loss of beacon: */
-#define WL_WOWL_BCN                    (1 << 4)
+#define BRCMF_WOWL_BCN                 (1 << 4)
 /* Wakeup after test: */
-#define WL_WOWL_TST                    (1 << 5)
+#define BRCMF_WOWL_TST                 (1 << 5)
 /* Wakeup after PTK refresh: */
-#define WL_WOWL_M1                     (1 << 6)
+#define BRCMF_WOWL_M1                  (1 << 6)
 /* Wakeup after receipt of EAP-Identity Req: */
-#define WL_WOWL_EAPID                  (1 << 7)
+#define BRCMF_WOWL_EAPID               (1 << 7)
 /* Wakeind via PME(0) or GPIO(1): */
-#define WL_WOWL_PME_GPIO               (1 << 8)
+#define BRCMF_WOWL_PME_GPIO            (1 << 8)
 /* need tkip phase 1 key to be updated by the driver: */
-#define WL_WOWL_NEEDTKIP1              (1 << 9)
+#define BRCMF_WOWL_NEEDTKIP1           (1 << 9)
 /* enable wakeup if GTK fails: */
-#define WL_WOWL_GTK_FAILURE            (1 << 10)
+#define BRCMF_WOWL_GTK_FAILURE         (1 << 10)
 /* support extended magic packets: */
-#define WL_WOWL_EXTMAGPAT              (1 << 11)
+#define BRCMF_WOWL_EXTMAGPAT           (1 << 11)
 /* support ARP/NS/keepalive offloading: */
-#define WL_WOWL_ARPOFFLOAD             (1 << 12)
+#define BRCMF_WOWL_ARPOFFLOAD          (1 << 12)
 /* read protocol version for EAPOL frames: */
-#define WL_WOWL_WPA2                   (1 << 13)
+#define BRCMF_WOWL_WPA2                        (1 << 13)
 /* If the bit is set, use key rotaton: */
-#define WL_WOWL_KEYROT                 (1 << 14)
+#define BRCMF_WOWL_KEYROT              (1 << 14)
 /* If the bit is set, frm received was bcast frame: */
-#define WL_WOWL_BCAST                  (1 << 15)
+#define BRCMF_WOWL_BCAST               (1 << 15)
 /* If the bit is set, scan offload is enabled: */
-#define WL_WOWL_SCANOL                 (1 << 16)
+#define BRCMF_WOWL_SCANOL              (1 << 16)
 /* Wakeup on tcpkeep alive timeout: */
-#define WL_WOWL_TCPKEEP_TIME           (1 << 17)
+#define BRCMF_WOWL_TCPKEEP_TIME                (1 << 17)
 /* Wakeup on mDNS Conflict Resolution: */
-#define WL_WOWL_MDNS_CONFLICT          (1 << 18)
+#define BRCMF_WOWL_MDNS_CONFLICT       (1 << 18)
 /* Wakeup on mDNS Service Connect: */
-#define WL_WOWL_MDNS_SERVICE           (1 << 19)
+#define BRCMF_WOWL_MDNS_SERVICE                (1 << 19)
 /* tcp keepalive got data: */
-#define WL_WOWL_TCPKEEP_DATA           (1 << 20)
+#define BRCMF_WOWL_TCPKEEP_DATA                (1 << 20)
 /* Firmware died in wowl mode: */
-#define WL_WOWL_FW_HALT                        (1 << 21)
+#define BRCMF_WOWL_FW_HALT             (1 << 21)
 /* Enable detection of radio button changes: */
-#define WL_WOWL_ENAB_HWRADIO           (1 << 22)
+#define BRCMF_WOWL_ENAB_HWRADIO                (1 << 22)
 /* Offloads detected MIC failure(s): */
-#define WL_WOWL_MIC_FAIL               (1 << 23)
+#define BRCMF_WOWL_MIC_FAIL            (1 << 23)
 /* Wakeup in Unassociated state (Net/Magic Pattern): */
-#define WL_WOWL_UNASSOC                        (1 << 24)
+#define BRCMF_WOWL_UNASSOC             (1 << 24)
 /* Wakeup if received matched secured pattern: */
-#define WL_WOWL_SECURE                 (1 << 25)
+#define BRCMF_WOWL_SECURE              (1 << 25)
 /* Link Down indication in WoWL mode: */
-#define WL_WOWL_LINKDOWN               (1 << 31)
+#define BRCMF_WOWL_LINKDOWN            (1 << 31)
+
+#define BRCMF_WOWL_MAXPATTERNS         8
+#define BRCMF_WOWL_MAXPATTERNSIZE      128
+
 
 /* join preference types for join_pref iovar */
 enum brcmf_join_pref_types {
@@ -124,6 +128,12 @@ enum brcmf_fil_p2p_if_types {
        BRCMF_FIL_P2P_IF_DEV,
 };
 
+enum brcmf_wowl_pattern_type {
+       BRCMF_WOWL_PATTERN_TYPE_BITMAP = 0,
+       BRCMF_WOWL_PATTERN_TYPE_ARP,
+       BRCMF_WOWL_PATTERN_TYPE_NA
+};
+
 struct brcmf_fil_p2p_if_le {
        u8 addr[ETH_ALEN];
        __le16 type;
@@ -484,4 +494,29 @@ struct brcmf_rx_mgmt_data {
        __be32  rate;
 };
 
+/**
+ * struct brcmf_fil_wowl_pattern_le - wowl pattern configuration struct.
+ *
+ * @cmd: "add", "del" or "clr".
+ * @masksize: Size of the mask in #of bytes
+ * @offset: Pattern byte offset in packet
+ * @patternoffset: Offset of start of pattern. Starting from field masksize.
+ * @patternsize: Size of the pattern itself in #of bytes
+ * @id: id
+ * @reasonsize: Size of the wakeup reason code
+ * @type: Type of pattern (enum brcmf_wowl_pattern_type)
+ */
+struct brcmf_fil_wowl_pattern_le {
+       u8      cmd[4];
+       __le32  masksize;
+       __le32  offset;
+       __le32  patternoffset;
+       __le32  patternsize;
+       __le32  id;
+       __le32  reasonsize;
+       __le32  type;
+       /* u8 mask[] - Mask follows the structure above */
+       /* u8 pattern[] - Pattern follows the mask is at 'patternoffset' */
+};
+
 #endif /* FWIL_TYPES_H_ */
index 183f08d7fc8c8e1ece4a6965fd604313385580f4..f0dda0ecd23b4395219f31ef88475329e0ab69f2 100644 (file)
 
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
+#include "core.h"
+#include "debug.h"
+#include "bus.h"
 #include "fwil.h"
 #include "fwil_types.h"
 #include "fweh.h"
 #include "fwsignal.h"
 #include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
 #include "proto.h"
 
 /**
index 11cc051f97cd42152ed6530257e1c1fcfbcf46e4..02d39ce8dbcafc9484927ccc19ed11c6319dae69 100644 (file)
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 
-#include "dhd.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "debug.h"
 #include "proto.h"
 #include "msgbuf.h"
 #include "commonring.h"
 #include "flowring.h"
-#include "dhd_bus.h"
+#include "bus.h"
 #include "tracepoint.h"
 
 
index f05f5270fec1095df589b96490308bfe5193568a..eb3fce82a2231612b4b4c1a3991ef84b24d103db 100644 (file)
@@ -21,8 +21,8 @@
 #include <linux/mmc/sdio_func.h>
 
 #include <defs.h>
-#include "dhd_dbg.h"
-#include "sdio_host.h"
+#include "debug.h"
+#include "sdio.h"
 
 void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
 {
index d54c58a32faa52bf9b6dc2cb36edd35c07993302..effb48ebd86450c41d7a3a4d46b85df4f049b946 100644 (file)
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
 #include <defs.h>
-#include <dhd.h>
-#include <dhd_dbg.h>
+#include "core.h"
+#include "debug.h"
 #include "fwil.h"
 #include "fwil_types.h"
 #include "p2p.h"
-#include "wl_cfg80211.h"
+#include "cfg80211.h"
 
 /* parameters used for p2p escan */
 #define P2PAPI_SCAN_NPROBES 1
index 8c0632ec9f7a6041e72a0a3c6e6243a00955d97f..b0ae7993e2e885d6ce81da3a2a8c9a1b95f5d009 100644 (file)
@@ -30,8 +30,8 @@
 #include <brcmu_wifi.h>
 #include <brcm_hw_ids.h>
 
-#include "dhd_dbg.h"
-#include "dhd_bus.h"
+#include "debug.h"
+#include "bus.h"
 #include "commonring.h"
 #include "msgbuf.h"
 #include "pcie.h"
index 62b940723339f825a2ded722e19ec39c8e644dee..26b68c367f57ccc33f9afda71310d10fd61455e0 100644 (file)
@@ -20,9 +20,9 @@
 #include <linux/netdevice.h>
 
 #include <brcmu_wifi.h>
-#include "dhd.h"
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "core.h"
+#include "bus.h"
+#include "debug.h"
 #include "proto.h"
 #include "bcdc.h"
 #include "msgbuf.h"
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
rename to drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index d20d4e6f391ae89706e422e2b817034ee030c0ae..0b0d51a61060cbc42f8f755ba9b2e543b08b9426 100644 (file)
@@ -40,7 +40,7 @@
 #include <brcmu_utils.h>
 #include <brcm_hw_ids.h>
 #include <soc.h>
-#include "sdio_host.h"
+#include "sdio.h"
 #include "chip.h"
 #include "firmware.h"
 
@@ -96,8 +96,8 @@ struct rte_console {
 #endif                         /* DEBUG */
 #include <chipcommon.h>
 
-#include "dhd_bus.h"
-#include "dhd_dbg.h"
+#include "bus.h"
+#include "debug.h"
 #include "tracepoint.h"
 
 #define TXQLEN         2048    /* bulk tx queue length */
@@ -2762,6 +2762,48 @@ static struct pktq *brcmf_sdio_bus_gettxq(struct device *dev)
        return &bus->txq;
 }
 
+static bool brcmf_sdio_prec_enq(struct pktq *q, struct sk_buff *pkt, int prec)
+{
+       struct sk_buff *p;
+       int eprec = -1;         /* precedence to evict from */
+
+       /* Fast case, precedence queue is not full and we are also not
+        * exceeding total queue length
+        */
+       if (!pktq_pfull(q, prec) && !pktq_full(q)) {
+               brcmu_pktq_penq(q, prec, pkt);
+               return true;
+       }
+
+       /* Determine precedence from which to evict packet, if any */
+       if (pktq_pfull(q, prec)) {
+               eprec = prec;
+       } else if (pktq_full(q)) {
+               p = brcmu_pktq_peek_tail(q, &eprec);
+               if (eprec > prec)
+                       return false;
+       }
+
+       /* Evict if needed */
+       if (eprec >= 0) {
+               /* Detect queueing to unconfigured precedence */
+               if (eprec == prec)
+                       return false;   /* refuse newer (incoming) packet */
+               /* Evict packet according to discard policy */
+               p = brcmu_pktq_pdeq_tail(q, eprec);
+               if (p == NULL)
+                       brcmf_err("brcmu_pktq_pdeq_tail() failed\n");
+               brcmu_pkt_buf_free_skb(p);
+       }
+
+       /* Enqueue */
+       p = brcmu_pktq_penq(q, prec, pkt);
+       if (p == NULL)
+               brcmf_err("brcmu_pktq_penq() failed\n");
+
+       return p != NULL;
+}
+
 static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 {
        int ret = -EBADE;
@@ -2787,7 +2829,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
        spin_lock_bh(&bus->txq_lock);
        /* reset bus_flags in packet cb */
        *(u16 *)(pkt->cb) = 0;
-       if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
+       if (!brcmf_sdio_prec_enq(&bus->txq, pkt, prec)) {
                skb_pull(pkt, bus->tx_hdrlen);
                brcmf_err("out of bus->txq !!!\n");
                ret = -ENOSR;
@@ -2797,7 +2839,7 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
 
        if (pktq_len(&bus->txq) >= TXHI) {
                bus->txoff = true;
-               brcmf_txflowblock(bus->sdiodev->dev, true);
+               brcmf_txflowblock(dev, true);
        }
        spin_unlock_bh(&bus->txq_lock);
 
@@ -3948,6 +3990,7 @@ static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
        .txctl = brcmf_sdio_bus_txctl,
        .rxctl = brcmf_sdio_bus_rxctl,
        .gettxq = brcmf_sdio_bus_gettxq,
+       .wowl_config = brcmf_sdio_wowl_config
 };
 
 static void brcmf_sdio_firmware_callback(struct device *dev,
@@ -4074,7 +4117,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 
        /* platform specific configuration:
         *   alignments must be at least 4 bytes for ADMA
-         */
+        */
        bus->head_align = ALIGNMENT;
        bus->sgentry_align = ALIGNMENT;
        if (sdiodev->pdata) {
similarity index 98%
rename from drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
rename to drivers/net/wireless/brcm80211/brcmfmac/sdio.h
index f2d06cae366af25d440cc5d7cd0b2572911c4fd5..8eb42620129cb77162fc03347ca4bae13bc4f733 100644 (file)
@@ -14,8 +14,8 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef        _BRCM_SDH_H_
-#define        _BRCM_SDH_H_
+#ifndef        BRCMFMAC_SDIO_H
+#define        BRCMFMAC_SDIO_H
 
 #include <linux/skbuff.h>
 #include <linux/firmware.h>
@@ -186,6 +186,7 @@ struct brcmf_sdio_dev {
        struct sg_table sgtable;
        char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
        char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
+       bool wowl_enabled;
 };
 
 /* sdio core registers */
@@ -334,5 +335,6 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus);
 void brcmf_sdio_isr(struct brcmf_sdio *bus);
 
 void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick);
+void brcmf_sdio_wowl_config(struct device *dev, bool enabled);
 
-#endif                         /* _BRCM_SDH_H_ */
+#endif /* BRCMFMAC_SDIO_H */
index b505db48c60df10115c09c01a8f5bf3e66f37ab8..a10f35c5eb3daef41697efb7fee2f4ef370410e5 100644 (file)
 #ifndef __CHECKER__
 #define CREATE_TRACE_POINTS
 #include "tracepoint.h"
+
+void __brcmf_err(const char *func, const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+       pr_err("%s: %pV", func, &vaf);
+       trace_brcmf_err(func, &vaf);
+       va_end(args);
+}
+
 #endif
index dc135915470d2cb70efab5480d11a036a0e00d3f..5265aa70b094f3a3ae541532056e9ff5ad76a75c 100644 (file)
 #include <brcmu_utils.h>
 #include <brcm_hw_ids.h>
 #include <brcmu_wifi.h>
-#include <dhd_bus.h>
-#include <dhd_dbg.h>
-
+#include "bus.h"
+#include "debug.h"
 #include "firmware.h"
-#include "usb_rdl.h"
 #include "usb.h"
 
+
 #define IOCTL_RESP_TIMEOUT             2000
 
 #define BRCMF_USB_RESET_GETVER_SPINWAIT        100     /* in unit of ms */
 #define BRCMF_USB_43242_FW_NAME                "brcm/brcmfmac43242a.bin"
 #define BRCMF_USB_43569_FW_NAME                "brcm/brcmfmac43569.bin"
 
+#define TRX_MAGIC              0x30524448      /* "HDR0" */
+#define TRX_MAX_OFFSET         3               /* Max number of file offsets */
+#define TRX_UNCOMP_IMAGE       0x20            /* Trx holds uncompressed img */
+#define TRX_RDL_CHUNK          1500            /* size of each dl transfer */
+#define TRX_OFFSETS_DLFWLEN_IDX        0
+
+/* Control messages: bRequest values */
+#define DL_GETSTATE    0       /* returns the rdl_state_t struct */
+#define DL_CHECK_CRC   1       /* currently unused */
+#define DL_GO          2       /* execute downloaded image */
+#define DL_START       3       /* initialize dl state */
+#define DL_REBOOT      4       /* reboot the device in 2 seconds */
+#define DL_GETVER      5       /* returns the bootrom_id_t struct */
+#define DL_GO_PROTECTED        6       /* execute the downloaded code and set reset
+                                * event to occur in 2 seconds.  It is the
+                                * responsibility of the downloaded code to
+                                * clear this event
+                                */
+#define DL_EXEC                7       /* jump to a supplied address */
+#define DL_RESETCFG    8       /* To support single enum on dongle
+                                * - Not used by bootloader
+                                */
+#define DL_DEFER_RESP_OK 9     /* Potentially defer the response to setup
+                                * if resp unavailable
+                                */
+
+/* states */
+#define DL_WAITING     0       /* waiting to rx first pkt */
+#define DL_READY       1       /* hdr was good, waiting for more of the
+                                * compressed image
+                                */
+#define DL_BAD_HDR     2       /* hdr was corrupted */
+#define DL_BAD_CRC     3       /* compressed image was corrupted */
+#define DL_RUNNABLE    4       /* download was successful,waiting for go cmd */
+#define DL_START_FAIL  5       /* failed to initialize correctly */
+#define DL_NVRAM_TOOBIG        6       /* host specified nvram data exceeds DL_NVRAM
+                                * value
+                                */
+#define DL_IMAGE_TOOBIG        7       /* firmware image too big */
+
+
+struct trx_header_le {
+       __le32 magic;           /* "HDR0" */
+       __le32 len;             /* Length of file including header */
+       __le32 crc32;           /* CRC from flag_version to end of file */
+       __le32 flag_version;    /* 0:15 flags, 16:31 version */
+       __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
+                                        * header
+                                        */
+};
+
+struct rdl_state_le {
+       __le32 state;
+       __le32 bytes;
+};
+
+struct bootrom_id_le {
+       __le32 chip;            /* Chip id */
+       __le32 chiprev;         /* Chip rev */
+       __le32 ramsize;         /* Size of  RAM */
+       __le32 remapbase;       /* Current remap base address */
+       __le32 boardtype;       /* Type of board */
+       __le32 boardrev;        /* Board revision */
+};
+
 struct brcmf_usb_image {
        struct list_head list;
        s8 *fwname;
@@ -93,6 +157,8 @@ struct brcmf_usbdev_info {
        u8 ifnum;
 
        struct urb *bulk_urb; /* used for FW download */
+
+       bool wowl_enabled;
 };
 
 static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
@@ -600,6 +666,16 @@ static int brcmf_usb_up(struct device *dev)
        return 0;
 }
 
+static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
+{
+       if (devinfo->ctl_urb)
+               usb_kill_urb(devinfo->ctl_urb);
+       if (devinfo->bulk_urb)
+               usb_kill_urb(devinfo->bulk_urb);
+       brcmf_usb_free_q(&devinfo->tx_postq, true);
+       brcmf_usb_free_q(&devinfo->rx_postq, true);
+}
+
 static void brcmf_usb_down(struct device *dev)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
@@ -613,14 +689,7 @@ static void brcmf_usb_down(struct device *dev)
 
        brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
 
-       if (devinfo->ctl_urb)
-               usb_kill_urb(devinfo->ctl_urb);
-
-       if (devinfo->bulk_urb)
-               usb_kill_urb(devinfo->bulk_urb);
-       brcmf_usb_free_q(&devinfo->tx_postq, true);
-
-       brcmf_usb_free_q(&devinfo->rx_postq, true);
+       brcmf_cancel_all_urbs(devinfo);
 }
 
 static void
@@ -783,7 +852,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
 
        brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);
 
-       bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
+       bulkchunk = kmalloc(TRX_RDL_CHUNK, GFP_ATOMIC);
        if (bulkchunk == NULL) {
                err = -ENOMEM;
                goto fail;
@@ -810,10 +879,10 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
                /* Wait until the usb device reports it received all
                 * the bytes we sent */
                if ((rdlbytes == sent) && (rdlbytes != dllen)) {
-                       if ((dllen-sent) < RDL_CHUNK)
+                       if ((dllen-sent) < TRX_RDL_CHUNK)
                                sendlen = dllen-sent;
                        else
-                               sendlen = RDL_CHUNK;
+                               sendlen = TRX_RDL_CHUNK;
 
                        /* simply avoid having to send a ZLP by ensuring we
                         * never have an even
@@ -978,21 +1047,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
        kfree(devinfo->rx_reqs);
 }
 
-#define TRX_MAGIC       0x30524448      /* "HDR0" */
-#define TRX_VERSION     1               /* Version 1 */
-#define TRX_MAX_LEN     0x3B0000        /* Max length */
-#define TRX_NO_HEADER   1               /* Do not write TRX header */
-#define TRX_MAX_OFFSET  3               /* Max number of individual files */
-#define TRX_UNCOMP_IMAGE        0x20    /* Trx contains uncompressed image */
-
-struct trx_header_le {
-       __le32 magic;           /* "HDR0" */
-       __le32 len;             /* Length of file including header */
-       __le32 crc32;           /* CRC from flag_version to end of file */
-       __le32 flag_version;    /* 0:15 flags, 16:31 version */
-       __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
-                                        * header */
-};
 
 static int check_file(const u8 *headers)
 {
@@ -1094,11 +1148,24 @@ error:
        return NULL;
 }
 
+static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
+{
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+       brcmf_dbg(USB, "Configuring WOWL, enabled=%d\n", enabled);
+       devinfo->wowl_enabled = enabled;
+       if (enabled)
+               device_set_wakeup_enable(devinfo->dev, true);
+       else
+               device_set_wakeup_enable(devinfo->dev, false);
+}
+
 static struct brcmf_bus_ops brcmf_usb_bus_ops = {
        .txdata = brcmf_usb_tx,
        .stop = brcmf_usb_down,
        .txctl = brcmf_usb_tx_ctlpkt,
        .rxctl = brcmf_usb_rx_ctlpkt,
+       .wowl_config = brcmf_usb_wowl_config,
 };
 
 static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
@@ -1186,6 +1253,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
        bus->ops = &brcmf_usb_bus_ops;
        bus->proto_type = BRCMF_PROTO_BCDC;
        bus->always_use_fws_queue = true;
+#ifdef CONFIG_PM
+       bus->wowl_supported = true;
+#endif
 
        if (!brcmf_usb_dlneeded(devinfo)) {
                ret = brcmf_usb_bus_setup(devinfo);
@@ -1339,7 +1409,10 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
 
        brcmf_dbg(USB, "Enter\n");
        devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
-       brcmf_detach(&usb->dev);
+       if (devinfo->wowl_enabled)
+               brcmf_cancel_all_urbs(devinfo);
+       else
+               brcmf_detach(&usb->dev);
        return 0;
 }
 
@@ -1352,7 +1425,12 @@ static int brcmf_usb_resume(struct usb_interface *intf)
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 
        brcmf_dbg(USB, "Enter\n");
-       return brcmf_usb_bus_setup(devinfo);
+       if (!devinfo->wowl_enabled)
+               return brcmf_usb_bus_setup(devinfo);
+
+       devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
+       brcmf_usb_rx_fill_all(devinfo);
+       return 0;
 }
 
 static int brcmf_usb_reset_resume(struct usb_interface *intf)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h b/drivers/net/wireless/brcm80211/brcmfmac/usb_rdl.h
deleted file mode 100644 (file)
index 0a35c51..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2011 Broadcom Corporation
- *
- * 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_RDL_H
-#define _USB_RDL_H
-
-/* Control messages: bRequest values */
-#define DL_GETSTATE    0       /* returns the rdl_state_t struct */
-#define DL_CHECK_CRC   1       /* currently unused */
-#define DL_GO          2       /* execute downloaded image */
-#define DL_START       3       /* initialize dl state */
-#define DL_REBOOT      4       /* reboot the device in 2 seconds */
-#define DL_GETVER      5       /* returns the bootrom_id_t struct */
-#define DL_GO_PROTECTED        6       /* execute the downloaded code and set reset
-                                * event to occur in 2 seconds.  It is the
-                                * responsibility of the downloaded code to
-                                * clear this event
-                                */
-#define DL_EXEC                7       /* jump to a supplied address */
-#define DL_RESETCFG    8       /* To support single enum on dongle
-                                * - Not used by bootloader
-                                */
-#define DL_DEFER_RESP_OK 9     /* Potentially defer the response to setup
-                                * if resp unavailable
-                                */
-
-/* states */
-#define DL_WAITING     0       /* waiting to rx first pkt */
-#define DL_READY       1       /* hdr was good, waiting for more of the
-                                * compressed image */
-#define DL_BAD_HDR     2       /* hdr was corrupted */
-#define DL_BAD_CRC     3       /* compressed image was corrupted */
-#define DL_RUNNABLE    4       /* download was successful,waiting for go cmd */
-#define DL_START_FAIL  5       /* failed to initialize correctly */
-#define DL_NVRAM_TOOBIG        6       /* host specified nvram data exceeds DL_NVRAM
-                                * value */
-#define DL_IMAGE_TOOBIG        7       /* download image too big (exceeds DATA_START
-                                *  for rdl) */
-
-struct rdl_state_le {
-       __le32 state;
-       __le32 bytes;
-};
-
-struct bootrom_id_le {
-       __le32 chip;    /* Chip id */
-       __le32 chiprev; /* Chip rev */
-       __le32 ramsize; /* Size of  RAM */
-       __le32 remapbase;       /* Current remap base address */
-       __le32 boardtype;       /* Type of board */
-       __le32 boardrev;        /* Board revision */
-};
-
-#define RDL_CHUNK      1500  /* size of each dl transfer */
-
-#define TRX_OFFSETS_DLFWLEN_IDX        0
-#define TRX_OFFSETS_JUMPTO_IDX 1
-#define TRX_OFFSETS_NVM_LEN_IDX        2
-
-#define TRX_OFFSETS_DLBASE_IDX  0
-
-#endif  /* _USB_RDL_H */
index 5960d827508c9d42a5f4a7c29e18ab80e559aacb..222f26a396424715368f3cbc4a94cedd82435821 100644 (file)
 
 #include <brcmu_wifi.h>
 #include "fwil_types.h"
-#include "dhd.h"
+#include "core.h"
 #include "p2p.h"
-#include "dhd_dbg.h"
-#include "wl_cfg80211.h"
+#include "debug.h"
+#include "cfg80211.h"
 #include "vendor.h"
 #include "fwil.h"
 
index a5d4add26f416f31a7413c7a4a41158646232e4f..19740c1b156603bd5c58e3fbadf1f837b59776e3 100644 (file)
@@ -71,48 +71,148 @@ struct dentry *brcms_debugfs_get_devdir(struct brcms_pub *drvr)
 }
 
 static
-ssize_t brcms_debugfs_hardware_read(struct file *f, char __user *data,
-                                       size_t count, loff_t *ppos)
+int brcms_debugfs_hardware_read(struct seq_file *s, void *data)
 {
-       char buf[128];
-       int res;
-       struct brcms_pub *drvr = f->private_data;
-
-       /* only allow read from start */
-       if (*ppos > 0)
-               return 0;
-
-       res = scnprintf(buf, sizeof(buf),
-               "board vendor: %x\n"
-               "board type: %x\n"
-               "board revision: %x\n"
-               "board flags: %x\n"
-               "board flags2: %x\n"
-               "firmware revision: %x\n",
-               drvr->wlc->hw->d11core->bus->boardinfo.vendor,
-               drvr->wlc->hw->d11core->bus->boardinfo.type,
-               drvr->wlc->hw->boardrev,
-               drvr->wlc->hw->boardflags,
-               drvr->wlc->hw->boardflags2,
-               drvr->wlc->ucode_rev
-               );
-
-       return simple_read_from_buffer(data, count, ppos, buf, res);
+       struct brcms_pub *drvr = s->private;
+
+       seq_printf(s, "board vendor: %x\n"
+                  "board type: %x\n"
+                  "board revision: %x\n"
+                  "board flags: %x\n"
+                  "board flags2: %x\n"
+                  "firmware revision: %x\n",
+                  drvr->wlc->hw->d11core->bus->boardinfo.vendor,
+                  drvr->wlc->hw->d11core->bus->boardinfo.type,
+                  drvr->wlc->hw->boardrev,
+                  drvr->wlc->hw->boardflags,
+                  drvr->wlc->hw->boardflags2,
+                  drvr->wlc->ucode_rev);
+
+       return 0;
+}
+
+static int brcms_debugfs_macstat_read(struct seq_file *s, void *data)
+{
+       struct brcms_pub *drvr = s->private;
+       struct brcms_info *wl = drvr->ieee_hw->priv;
+       struct macstat stats;
+       int i;
+
+       spin_lock_bh(&wl->lock);
+       stats = *(drvr->wlc->core->macstat_snapshot);
+       spin_unlock_bh(&wl->lock);
+
+       seq_printf(s, "txallfrm: %d\n", stats.txallfrm);
+       seq_printf(s, "txrtsfrm: %d\n", stats.txrtsfrm);
+       seq_printf(s, "txctsfrm: %d\n", stats.txctsfrm);
+       seq_printf(s, "txackfrm: %d\n", stats.txackfrm);
+       seq_printf(s, "txdnlfrm: %d\n", stats.txdnlfrm);
+       seq_printf(s, "txbcnfrm: %d\n", stats.txbcnfrm);
+       seq_printf(s, "txfunfl[8]:");
+       for (i = 0; i < ARRAY_SIZE(stats.txfunfl); i++)
+               seq_printf(s, " %d", stats.txfunfl[i]);
+       seq_printf(s, "\ntxtplunfl: %d\n", stats.txtplunfl);
+       seq_printf(s, "txphyerr: %d\n", stats.txphyerr);
+       seq_printf(s, "pktengrxducast: %d\n", stats.pktengrxducast);
+       seq_printf(s, "pktengrxdmcast: %d\n", stats.pktengrxdmcast);
+       seq_printf(s, "rxfrmtoolong: %d\n", stats.rxfrmtoolong);
+       seq_printf(s, "rxfrmtooshrt: %d\n", stats.rxfrmtooshrt);
+       seq_printf(s, "rxinvmachdr: %d\n", stats.rxinvmachdr);
+       seq_printf(s, "rxbadfcs: %d\n", stats.rxbadfcs);
+       seq_printf(s, "rxbadplcp: %d\n", stats.rxbadplcp);
+       seq_printf(s, "rxcrsglitch: %d\n", stats.rxcrsglitch);
+       seq_printf(s, "rxstrt: %d\n", stats.rxstrt);
+       seq_printf(s, "rxdfrmucastmbss: %d\n", stats.rxdfrmucastmbss);
+       seq_printf(s, "rxmfrmucastmbss: %d\n", stats.rxmfrmucastmbss);
+       seq_printf(s, "rxcfrmucast: %d\n", stats.rxcfrmucast);
+       seq_printf(s, "rxrtsucast: %d\n", stats.rxrtsucast);
+       seq_printf(s, "rxctsucast: %d\n", stats.rxctsucast);
+       seq_printf(s, "rxackucast: %d\n", stats.rxackucast);
+       seq_printf(s, "rxdfrmocast: %d\n", stats.rxdfrmocast);
+       seq_printf(s, "rxmfrmocast: %d\n", stats.rxmfrmocast);
+       seq_printf(s, "rxcfrmocast: %d\n", stats.rxcfrmocast);
+       seq_printf(s, "rxrtsocast: %d\n", stats.rxrtsocast);
+       seq_printf(s, "rxctsocast: %d\n", stats.rxctsocast);
+       seq_printf(s, "rxdfrmmcast: %d\n", stats.rxdfrmmcast);
+       seq_printf(s, "rxmfrmmcast: %d\n", stats.rxmfrmmcast);
+       seq_printf(s, "rxcfrmmcast: %d\n", stats.rxcfrmmcast);
+       seq_printf(s, "rxbeaconmbss: %d\n", stats.rxbeaconmbss);
+       seq_printf(s, "rxdfrmucastobss: %d\n", stats.rxdfrmucastobss);
+       seq_printf(s, "rxbeaconobss: %d\n", stats.rxbeaconobss);
+       seq_printf(s, "rxrsptmout: %d\n", stats.rxrsptmout);
+       seq_printf(s, "bcntxcancl: %d\n", stats.bcntxcancl);
+       seq_printf(s, "rxf0ovfl: %d\n", stats.rxf0ovfl);
+       seq_printf(s, "rxf1ovfl: %d\n", stats.rxf1ovfl);
+       seq_printf(s, "rxf2ovfl: %d\n", stats.rxf2ovfl);
+       seq_printf(s, "txsfovfl: %d\n", stats.txsfovfl);
+       seq_printf(s, "pmqovfl: %d\n", stats.pmqovfl);
+       seq_printf(s, "rxcgprqfrm: %d\n", stats.rxcgprqfrm);
+       seq_printf(s, "rxcgprsqovfl: %d\n", stats.rxcgprsqovfl);
+       seq_printf(s, "txcgprsfail: %d\n", stats.txcgprsfail);
+       seq_printf(s, "txcgprssuc: %d\n", stats.txcgprssuc);
+       seq_printf(s, "prs_timeout: %d\n", stats.prs_timeout);
+       seq_printf(s, "rxnack: %d\n", stats.rxnack);
+       seq_printf(s, "frmscons: %d\n", stats.frmscons);
+       seq_printf(s, "txnack: %d\n", stats.txnack);
+       seq_printf(s, "txglitch_nack: %d\n", stats.txglitch_nack);
+       seq_printf(s, "txburst: %d\n", stats.txburst);
+       seq_printf(s, "bphy_rxcrsglitch: %d\n", stats.bphy_rxcrsglitch);
+       seq_printf(s, "phywatchdog: %d\n", stats.phywatchdog);
+       seq_printf(s, "bphy_badplcp: %d\n", stats.bphy_badplcp);
+       return 0;
+}
+
+struct brcms_debugfs_entry {
+       int (*read)(struct seq_file *seq, void *data);
+       struct brcms_pub *drvr;
+};
+
+static int brcms_debugfs_entry_open(struct inode *inode, struct file *f)
+{
+       struct brcms_debugfs_entry *entry = inode->i_private;
+
+       return single_open(f, entry->read, entry->drvr);
 }
 
-static const struct file_operations brcms_debugfs_hardware_ops = {
+static const struct file_operations brcms_debugfs_def_ops = {
        .owner = THIS_MODULE,
-       .open = simple_open,
-       .read = brcms_debugfs_hardware_read
+       .open = brcms_debugfs_entry_open,
+       .release = single_release,
+       .read = seq_read,
+       .llseek = seq_lseek
 };
 
+static int
+brcms_debugfs_add_entry(struct brcms_pub *drvr, const char *fn,
+                       int (*read_fn)(struct seq_file *seq, void *data))
+{
+       struct device *dev = &drvr->wlc->hw->d11core->dev;
+       struct dentry *dentry =  drvr->dbgfs_dir;
+       struct brcms_debugfs_entry *entry;
+
+       if (IS_ERR_OR_NULL(dentry))
+               return -ENOENT;
+
+       entry = devm_kzalloc(dev, sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       entry->read = read_fn;
+       entry->drvr = drvr;
+
+       dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry,
+                                    &brcms_debugfs_def_ops);
+
+       return PTR_ERR_OR_ZERO(dentry);
+}
+
 void brcms_debugfs_create_files(struct brcms_pub *drvr)
 {
-       struct dentry *dentry = drvr->dbgfs_dir;
+       if (IS_ERR_OR_NULL(drvr->dbgfs_dir))
+               return;
 
-       if (!IS_ERR_OR_NULL(dentry))
-               debugfs_create_file("hardware", S_IRUGO, dentry,
-                                   drvr, &brcms_debugfs_hardware_ops);
+       brcms_debugfs_add_entry(drvr, "hardware", brcms_debugfs_hardware_read);
+       brcms_debugfs_add_entry(drvr, "macstat", brcms_debugfs_macstat_read);
 }
 
 #define __brcms_fn(fn)                                         \
index 1b474828d5b884fb957daf52ac59ed3c135b4b1c..bc9be78faafa6679b0193be9b0f875fb31f6f0bb 100644 (file)
@@ -3081,7 +3081,7 @@ static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
 static void brcms_c_statsupd(struct brcms_c_info *wlc)
 {
        int i;
-       struct macstat macstats;
+       struct macstat *macstats;
 #ifdef DEBUG
        u16 delta;
        u16 rxf0ovfl;
@@ -3092,31 +3092,31 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc)
        if (!wlc->pub->up)
                return;
 
+       macstats = wlc->core->macstat_snapshot;
+
 #ifdef DEBUG
        /* save last rx fifo 0 overflow count */
-       rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
+       rxf0ovfl = macstats->rxf0ovfl;
 
        /* save last tx fifo  underflow count */
        for (i = 0; i < NFIFO; i++)
-               txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
+               txfunfl[i] = macstats->txfunfl[i];
 #endif                         /* DEBUG */
 
        /* Read mac stats from contiguous shared memory */
-       brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
-                               sizeof(struct macstat), OBJADDR_SHM_SEL);
+       brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, macstats,
+                               sizeof(*macstats), OBJADDR_SHM_SEL);
 
 #ifdef DEBUG
        /* check for rx fifo 0 overflow */
-       delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
+       delta = (u16)(macstats->rxf0ovfl - rxf0ovfl);
        if (delta)
                brcms_err(wlc->hw->d11core, "wl%d: %u rx fifo 0 overflows!\n",
                          wlc->pub->unit, delta);
 
        /* check for tx fifo underflows */
        for (i = 0; i < NFIFO; i++) {
-               delta =
-                   (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
-                             txfunfl[i]);
+               delta = macstats->txfunfl[i] - txfunfl[i];
                if (delta)
                        brcms_err(wlc->hw->d11core,
                                  "wl%d: %u tx fifo %d underflows!\n",
index edc344334a7547006901de8e3b5dcd79db66c0a9..67cad9b05ad821fc720da095aced2a9fe72202b8 100644 (file)
@@ -1363,7 +1363,7 @@ static ssize_t show_cmd_log(struct device *d,
        if (!priv->cmdlog)
                return 0;
        for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
-            (i != priv->cmdlog_pos) && (PAGE_SIZE - len);
+            (i != priv->cmdlog_pos) && (len < PAGE_SIZE);
             i = (i + 1) % priv->cmdlog_len) {
                len +=
                    snprintf(buf + len, PAGE_SIZE - len,
index 5ce2f59d3378ed7ddcc4891769d72401eb66cc0d..b0571618c2edf2a9b7478aee36c61c4cef915020 100644 (file)
@@ -654,10 +654,6 @@ struct libipw_network {
        /* TPC Report - mandatory if spctrm mgmt required */
        struct libipw_tpc_report tpc_report;
 
-       /* IBSS DFS - mandatory if spctrm mgmt required and IBSS
-        * NOTE: This is variable length and so must be allocated dynamically */
-       struct libipw_ibss_dfs *ibss_dfs;
-
        /* Channel Switch Announcement - optional if spctrm mgmt required */
        struct libipw_csa csa;
 
@@ -970,7 +966,6 @@ int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
 /* make sure to set stats->len */
 void libipw_rx_mgt(struct libipw_device *ieee, struct libipw_hdr_4addr *header,
                   struct libipw_rx_stats *stats);
-void libipw_network_reset(struct libipw_network *network);
 
 /* libipw_geo.c */
 const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee);
index 5f31b72a492181657f784408a3d33a11b418f221..60f28740f6afed42ab9e01c1077ae2130646ac69 100644 (file)
@@ -84,25 +84,12 @@ static int libipw_networks_allocate(struct libipw_device *ieee)
        return 0;
 }
 
-void libipw_network_reset(struct libipw_network *network)
-{
-       if (!network)
-               return;
-
-       if (network->ibss_dfs) {
-               kfree(network->ibss_dfs);
-               network->ibss_dfs = NULL;
-       }
-}
-
 static inline void libipw_networks_free(struct libipw_device *ieee)
 {
        int i;
 
-       for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-               kfree(ieee->networks[i]->ibss_dfs);
+       for (i = 0; i < MAX_NETWORK_COUNT; i++)
                kfree(ieee->networks[i]);
-       }
 }
 
 void libipw_networks_age(struct libipw_device *ieee,
index 2d66984079bb1f1bc928c1aed037851285a22ea6..a6877dd6ba7352361f6fb0401a3fd0f4cdf7bac9 100644 (file)
@@ -1298,13 +1298,6 @@ static int libipw_parse_info_param(struct libipw_info_element
                        break;
 
                case WLAN_EID_IBSS_DFS:
-                       if (network->ibss_dfs)
-                               break;
-                       network->ibss_dfs = kmemdup(info_element->data,
-                                                   info_element->len,
-                                                   GFP_ATOMIC);
-                       if (!network->ibss_dfs)
-                               return 1;
                        network->flags |= NETWORK_HAS_IBSS_DFS;
                        break;
 
@@ -1335,9 +1328,7 @@ static int libipw_parse_info_param(struct libipw_info_element
 static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response
                                       *frame, struct libipw_rx_stats *stats)
 {
-       struct libipw_network network_resp = {
-               .ibss_dfs = NULL,
-       };
+       struct libipw_network network_resp = { };
        struct libipw_network *network = &network_resp;
        struct net_device *dev = ieee->dev;
 
@@ -1472,9 +1463,6 @@ static void update_network(struct libipw_network *dst,
        int qos_active;
        u8 old_param;
 
-       libipw_network_reset(dst);
-       dst->ibss_dfs = src->ibss_dfs;
-
        /* We only update the statistics if they were created by receiving
         * the network information on the actual channel the network is on.
         *
@@ -1548,9 +1536,7 @@ static void libipw_process_probe_response(struct libipw_device
                                                    *stats)
 {
        struct net_device *dev = ieee->dev;
-       struct libipw_network network = {
-               .ibss_dfs = NULL,
-       };
+       struct libipw_network network = { };
        struct libipw_network *target;
        struct libipw_network *oldest = NULL;
 #ifdef CONFIG_LIBIPW_DEBUG
@@ -1618,7 +1604,6 @@ static void libipw_process_probe_response(struct libipw_device
                        LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
                                          target->ssid_len, target->ssid,
                                          target->bssid);
-                       libipw_network_reset(target);
                } else {
                        /* Otherwise just pull from the free list */
                        target = list_entry(ieee->network_free_list.next,
@@ -1634,7 +1619,6 @@ static void libipw_process_probe_response(struct libipw_device
                                  "BEACON" : "PROBE RESPONSE");
 #endif
                memcpy(target, &network, sizeof(*target));
-               network.ibss_dfs = NULL;
                list_add_tail(&target->list, &ieee->network_list);
        } else {
                LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
@@ -1643,7 +1627,6 @@ static void libipw_process_probe_response(struct libipw_device
                                  is_beacon(beacon->header.frame_ctl) ?
                                  "BEACON" : "PROBE RESPONSE");
                update_network(target, &network);
-               network.ibss_dfs = NULL;
        }
 
        spin_unlock_irqrestore(&ieee->lock, flags);
index 26fec54dcd0300a7f6ec5cc96267acc917de56ea..2748fde4b90c0fa5113240765b06aaceeeeeb331 100644 (file)
@@ -6063,7 +6063,7 @@ il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 }
 
 void
-il4965_mac_channel_switch(struct ieee80211_hw *hw,
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                          struct ieee80211_channel_switch *ch_switch)
 {
        struct il_priv *il = hw->priv;
index 337dfcf3bbde7c58fe4681268f63b9d29ea8f5fa..3a57f71b8ed57fbb98761901968ee4e4cc0110f8 100644 (file)
@@ -187,8 +187,9 @@ int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            u8 buf_size);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
-void il4965_mac_channel_switch(struct ieee80211_hw *hw,
-                              struct ieee80211_channel_switch *ch_switch);
+void
+il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                         struct ieee80211_channel_switch *ch_switch);
 
 void il4965_led_enable(struct il_priv *il);
 
index 267e48a2915e7885993979337619d777c8cb74c8..139de90c2aaff46e8bed7c3def3c85499313c7a9 100644 (file)
@@ -59,6 +59,7 @@ config IWLDVM
 
 config IWLMVM
        tristate "Intel Wireless WiFi MVM Firmware support"
+       select BACKPORT_WANT_DEV_COREDUMP
        help
          This is the driver that supports the MVM firmware which is
          currently only available for 7260 and 3160 devices.
index 2191621d69c1618375482d3e3a1dc7d8f2b7f192..02e4ede2b04220beb03fc3701b541fb89658a66a 100644 (file)
@@ -418,8 +418,8 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena)
 
 static bool iwlagn_bt_traffic_is_sco(struct iwl_bt_uart_msg *uart_msg)
 {
-       return BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3 >>
-                       BT_UART_MSG_FRAME3SCOESCO_POS;
+       return (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3) >>
+               BT_UART_MSG_FRAME3SCOESCO_POS;
 }
 
 static void iwlagn_bt_traffic_change_work(struct work_struct *work)
index cae692ff1013f9ee00b93861558c6144cfad4cc1..47e64e8b9517d97dff6b96e544a731d498412ba1 100644 (file)
@@ -941,6 +941,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
 }
 
 static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
                                      struct ieee80211_channel_switch *ch_switch)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
index d2b7234b1c73e00f76ed17094d52e0e18431d81f..896ea906549c89d50eed5bb5069c4a22b61c6fe1 100644 (file)
@@ -104,6 +104,7 @@ static const struct iwl_base_params iwl8000_base_params = {
 };
 
 static const struct iwl_ht_params iwl8000_ht_params = {
+       .stbc = true,
        .ldpc = true,
        .ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
 };
index 2ef83a39ff10bb877f9ff15430a10b9ac2b3b836..f8aa9cf0827913e1c242b95609eeb821a83cd12a 100644 (file)
@@ -87,6 +87,16 @@ enum iwl_device_family {
        IWL_DEVICE_FAMILY_8000,
 };
 
+static inline bool iwl_has_secure_boot(u32 hw_rev,
+                                      enum iwl_device_family family)
+{
+       /* return 1 only for family 8000 B0 */
+       if ((family == IWL_DEVICE_FAMILY_8000) && (hw_rev & 0xC))
+               return 1;
+
+       return 0;
+}
+
 /*
  * LED mode
  *    IWL_LED_DEFAULT:  use device default
@@ -246,6 +256,7 @@ struct iwl_pwr_tx_backoff {
  * @nvm_hw_section_num: the ID of the HW NVM section
  * @pwr_tx_backoffs: translation table between power limits and backoffs
  * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response
+ * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -285,6 +296,7 @@ struct iwl_cfg {
        const char *default_nvm_file;
        unsigned int max_rx_agg_size;
        bool disable_dummy_notification;
+       unsigned int max_tx_agg_size;
 };
 
 /*
index 0f1084f09caabfdf1265c4e34ba54bbd682cffaa..d9fa8e034da2cfbf206d0f5cc9e06e29c0391a5b 100644 (file)
@@ -807,19 +807,16 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
                                            tlv_len);
                        drv->fw.mvm_fw = true;
-                       drv->fw.img[IWL_UCODE_REGULAR].is_secure = true;
                        break;
                case IWL_UCODE_TLV_SECURE_SEC_INIT:
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
                                            tlv_len);
                        drv->fw.mvm_fw = true;
-                       drv->fw.img[IWL_UCODE_INIT].is_secure = true;
                        break;
                case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
                        iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
                                            tlv_len);
                        drv->fw.mvm_fw = true;
-                       drv->fw.img[IWL_UCODE_WOWLAN].is_secure = true;
                        break;
                case IWL_UCODE_TLV_NUM_OF_CPU:
                        if (tlv_len != sizeof(u32))
index 4f6e66892acc4658473aed57fc4c6cc72dd33fc4..6f7ae5f7bdaeb62e7b98be4dec53740de2b0a592 100644 (file)
@@ -227,7 +227,6 @@ struct fw_desc {
 
 struct fw_img {
        struct fw_desc sec[IWL_UCODE_SECTION_MAX];
-       bool is_secure;
        bool is_dual_cpus;
 };
 
index d8fc548c0d6cd561993eebb6df185e3ccad0d6ac..0768f83e709d3f117139d6e331f610aaac750a97 100644 (file)
@@ -535,9 +535,7 @@ struct iwl_trans_ops {
        void (*ref)(struct iwl_trans *trans);
        void (*unref)(struct iwl_trans *trans);
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
        struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans);
-#endif
 };
 
 /**
@@ -704,7 +702,6 @@ static inline void iwl_trans_unref(struct iwl_trans *trans)
                trans->ops->unref(trans);
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
 static inline struct iwl_trans_dump_data *
 iwl_trans_dump_data(struct iwl_trans *trans)
 {
@@ -712,7 +709,6 @@ iwl_trans_dump_data(struct iwl_trans *trans)
                return NULL;
        return trans->ops->dump_data(trans);
 }
-#endif
 
 static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
                                     struct iwl_host_cmd *cmd)
index da2ffb78519431a1b14e9b355280a3c7a3446ed6..508c81359e41b7fef1e6c7025a355481ae888aae 100644 (file)
@@ -72,8 +72,6 @@
 #include "mvm.h"
 #include "iwl-debug.h"
 
-#define BT_ANTENNA_COUPLING_THRESHOLD          (30)
-
 const u32 iwl_bt_ctl_kill_msk[BT_KILL_MSK_MAX] = {
        [BT_KILL_MSK_DEFAULT] = 0xfffffc00,
        [BT_KILL_MSK_NEVER] = 0xffffffff,
@@ -302,11 +300,6 @@ static const __le64 iwl_ci_mask[][3] = {
        },
 };
 
-static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
-       cpu_to_le32(0x2e402280),
-       cpu_to_le32(0x7711a751),
-};
-
 struct corunning_block_luts {
        u8 range;
        __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
@@ -605,7 +598,7 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
 
        bt_cmd->max_kill = cpu_to_le32(5);
        bt_cmd->bt4_antenna_isolation_thr =
-                               cpu_to_le32(BT_ANTENNA_COUPLING_THRESHOLD);
+               cpu_to_le32(IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS);
        bt_cmd->bt4_tx_tx_delta_freq_thr = cpu_to_le32(15);
        bt_cmd->bt4_tx_rx_max_freq0 = cpu_to_le32(15);
        bt_cmd->override_primary_lut = cpu_to_le32(BT_COEX_INVALID_LUT);
@@ -638,8 +631,8 @@ int iwl_send_bt_init_conf(struct iwl_mvm *mvm)
 
        memcpy(&bt_cmd->mplut_prio_boost, iwl_bt_prio_boost,
               sizeof(iwl_bt_prio_boost));
-       memcpy(&bt_cmd->multiprio_lut, iwl_bt_mprio_lut,
-              sizeof(iwl_bt_mprio_lut));
+       bt_cmd->multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
+       bt_cmd->multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
 
 send_cmd:
        memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
index 8a1d2f33d5b7da2768a7e5849e305b6386b0b480..b571e1b0550c6131fe1c53905035cd99661c63df 100644 (file)
@@ -102,8 +102,6 @@ static const u8 iwl_bt_prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX] = {
 
 #undef EVENT_PRIO_ANT
 
-#define BT_ANTENNA_COUPLING_THRESHOLD          (30)
-
 static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm)
 {
        if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS))
@@ -290,11 +288,6 @@ static const __le64 iwl_ci_mask[][3] = {
        },
 };
 
-static const __le32 iwl_bt_mprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE] = {
-       cpu_to_le32(0x2e402280),
-       cpu_to_le32(0x7711a751),
-};
-
 struct corunning_block_luts {
        u8 range;
        __le32 lut20[BT_COEX_CORUN_LUT_SIZE];
@@ -593,7 +586,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
        }
 
        bt_cmd->max_kill = 5;
-       bt_cmd->bt4_antenna_isolation_thr = BT_ANTENNA_COUPLING_THRESHOLD;
+       bt_cmd->bt4_antenna_isolation_thr =
+               IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS;
        bt_cmd->bt4_antenna_isolation = iwlwifi_mod_params.ant_coupling;
        bt_cmd->bt4_tx_tx_delta_freq_thr = 15;
        bt_cmd->bt4_tx_rx_max_freq0 = 15;
@@ -649,8 +643,8 @@ int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm)
 
        memcpy(&bt_cmd->bt_prio_boost, iwl_bt_prio_boost,
               sizeof(iwl_bt_prio_boost));
-       memcpy(&bt_cmd->bt4_multiprio_lut, iwl_bt_mprio_lut,
-              sizeof(iwl_bt_mprio_lut));
+       bt_cmd->bt4_multiprio_lut[0] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG0);
+       bt_cmd->bt4_multiprio_lut[1] = cpu_to_le32(IWL_MVM_BT_COEX_MPLUT_REG1);
 
 send_cmd:
        memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
index d4dfbe4cb66da5330b9e06251e0766a2ceaa8bea..5c1ea80d5e3b0febb83e003d639844d1941b0bf1 100644 (file)
 #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_MPLUT_REG0             0x2e402280
+#define IWL_MVM_BT_COEX_MPLUT_REG1             0x7711a751
+#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS  30
 #define IWL_MVM_FW_MCAST_FILTER_PASS_ALL       0
+#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL       0
 #define IWL_MVM_QUOTA_THRESHOLD                        8
 #define IWL_MVM_RS_RSSI_BASED_INIT_RATE         0
+#define IWL_MVM_RS_DISABLE_MIMO                        0
 
 #endif /* __MVM_CONSTANTS_H */
index c17be0fb7283a4f51c570002d1fc7c743d354daa..3bbb511b0b3883ddc2f5c08808d0cabc5d15515b 100644 (file)
@@ -601,33 +601,6 @@ static int iwl_mvm_send_remote_wake_cfg(struct iwl_mvm *mvm,
        return ret;
 }
 
-struct iwl_d3_iter_data {
-       struct iwl_mvm *mvm;
-       struct ieee80211_vif *vif;
-       bool error;
-};
-
-static void iwl_mvm_d3_iface_iterator(void *_data, u8 *mac,
-                                     struct ieee80211_vif *vif)
-{
-       struct iwl_d3_iter_data *data = _data;
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
-       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
-               return;
-
-       if (mvmvif->ap_sta_id == IWL_MVM_STATION_COUNT)
-               return;
-
-       if (data->vif) {
-               IWL_ERR(data->mvm, "More than one managed interface active!\n");
-               data->error = true;
-               return;
-       }
-
-       data->vif = vif;
-}
-
 static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                                struct ieee80211_sta *ap_sta)
 {
@@ -783,6 +756,35 @@ void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                IWL_ERR(mvm, "failed to set non-QoS seqno\n");
 }
 
+static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
+{
+       iwl_mvm_cancel_scan(mvm);
+
+       iwl_trans_stop_device(mvm->trans);
+
+       /*
+        * Set the HW restart bit -- this is mostly true as we're
+        * going to load new firmware and reprogram that, though
+        * the reprogramming is going to be manual to avoid adding
+        * all the MACs that aren't support.
+        * We don't have to clear up everything though because the
+        * reprogramming is manual. When we resume, we'll actually
+        * go through a proper restart sequence again to switch
+        * back to the runtime firmware image.
+        */
+       set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
+       /* We reprogram keys and shouldn't allocate new key indices */
+       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
+
+       mvm->ptk_ivlen = 0;
+       mvm->ptk_icvlen = 0;
+       mvm->ptk_ivlen = 0;
+       mvm->ptk_icvlen = 0;
+
+       return iwl_mvm_load_d3_fw(mvm);
+}
+
 static int
 iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
                               const struct iwl_wowlan_config_cmd_v3 *cmd)
@@ -797,116 +799,52 @@ iwl_mvm_send_wowlan_config_cmd(struct iwl_mvm *mvm,
                                    cmd_len, cmd);
 }
 
-static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
-                            struct cfg80211_wowlan *wowlan,
-                            bool test)
+static int
+iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
+                         struct cfg80211_wowlan *wowlan,
+                         struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
+                         struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
+                         struct ieee80211_sta *ap_sta)
 {
-       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-       struct iwl_d3_iter_data suspend_iter_data = {
-               .mvm = mvm,
-       };
-       struct ieee80211_vif *vif;
-       struct iwl_mvm_vif *mvmvif;
-       struct ieee80211_sta *ap_sta;
-       struct iwl_mvm_sta *mvm_ap_sta;
-       struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
-       struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
-       struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct iwl_d3_manager_config d3_cfg_cmd_data = {
-               /*
-                * Program the minimum sleep time to 10 seconds, as many
-                * platforms have issues processing a wakeup signal while
-                * still being in the process of suspending.
-                */
-               .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
-       };
-       struct iwl_host_cmd d3_cfg_cmd = {
-               .id = D3_CONFIG_CMD,
-               .flags = CMD_WANT_SKB,
-               .data[0] = &d3_cfg_cmd_data,
-               .len[0] = sizeof(d3_cfg_cmd_data),
-       };
-       struct wowlan_key_data key_data = {
-               .use_rsc_tsc = false,
-               .tkip = &tkip_cmd,
-               .use_tkip = false,
-       };
        int ret;
-       int len __maybe_unused;
-
-       if (!wowlan) {
-               /*
-                * mac80211 shouldn't get here, but for D3 test
-                * it doesn't warrant a warning
-                */
-               WARN_ON(!test);
-               return -EINVAL;
-       }
-
-       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-       if (!key_data.rsc_tsc)
-               return -ENOMEM;
-
-       mutex_lock(&mvm->mutex);
-
-       /* see if there's only a single BSS vif and it's associated */
-       ieee80211_iterate_active_interfaces_atomic(
-               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-               iwl_mvm_d3_iface_iterator, &suspend_iter_data);
-
-       if (suspend_iter_data.error || !suspend_iter_data.vif) {
-               ret = 1;
-               goto out_noreset;
-       }
-
-       vif = suspend_iter_data.vif;
-       mvmvif = iwl_mvm_vif_from_mac80211(vif);
-
-       ap_sta = rcu_dereference_protected(
-                       mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
-                       lockdep_is_held(&mvm->mutex));
-       if (IS_ERR_OR_NULL(ap_sta)) {
-               ret = -EINVAL;
-               goto out_noreset;
-       }
-
-       mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+       struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
 
-       /* TODO: wowlan_config_cmd.common.wowlan_ba_teardown_tids */
+       /* TODO: wowlan_config_cmd->common.wowlan_ba_teardown_tids */
 
-       wowlan_config_cmd.common.is_11n_connection =
+       wowlan_config_cmd->common.is_11n_connection =
                                        ap_sta->ht_cap.ht_supported;
 
        /* Query the last used seqno and set it */
        ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
        if (ret < 0)
-               goto out_noreset;
-       wowlan_config_cmd.common.non_qos_seq = cpu_to_le16(ret);
+               return ret;
 
-       iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd.common);
+       wowlan_config_cmd->common.non_qos_seq = cpu_to_le16(ret);
+
+       iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, &wowlan_config_cmd->common);
 
        if (wowlan->disconnect)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS |
                                    IWL_WOWLAN_WAKEUP_LINK_CHANGE);
        if (wowlan->magic_pkt)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_MAGIC_PACKET);
        if (wowlan->gtk_rekey_failure)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
        if (wowlan->eap_identity_req)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_EAP_IDENT_REQ);
        if (wowlan->four_way_handshake)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
        if (wowlan->n_patterns)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_PATTERN_MATCH);
 
        if (wowlan->rfkill_release)
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_RF_KILL_DEASSERT);
 
        if (wowlan->tcp) {
@@ -914,44 +852,39 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                 * Set the "link change" (really "link lost") flag as well
                 * since that implies losing the TCP connection.
                 */
-               wowlan_config_cmd.common.wakeup_filter |=
+               wowlan_config_cmd->common.wakeup_filter |=
                        cpu_to_le32(IWL_WOWLAN_WAKEUP_REMOTE_LINK_LOSS |
                                    IWL_WOWLAN_WAKEUP_REMOTE_SIGNATURE_TABLE |
                                    IWL_WOWLAN_WAKEUP_REMOTE_WAKEUP_PACKET |
                                    IWL_WOWLAN_WAKEUP_LINK_CHANGE);
        }
 
-       iwl_mvm_cancel_scan(mvm);
-
-       iwl_trans_stop_device(mvm->trans);
-
-       /*
-        * Set the HW restart bit -- this is mostly true as we're
-        * going to load new firmware and reprogram that, though
-        * the reprogramming is going to be manual to avoid adding
-        * all the MACs that aren't support.
-        * We don't have to clear up everything though because the
-        * reprogramming is manual. When we resume, we'll actually
-        * go through a proper restart sequence again to switch
-        * back to the runtime firmware image.
-        */
-       set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
-
-       /* We reprogram keys and shouldn't allocate new key indices */
-       memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
-
-       mvm->ptk_ivlen = 0;
-       mvm->ptk_icvlen = 0;
-       mvm->ptk_ivlen = 0;
-       mvm->ptk_icvlen = 0;
+       return 0;
+}
 
-       ret = iwl_mvm_load_d3_fw(mvm);
-       if (ret)
-               goto out;
+static int
+iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
+                     struct cfg80211_wowlan *wowlan,
+                     struct iwl_wowlan_config_cmd_v3 *wowlan_config_cmd,
+                     struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
+                     struct ieee80211_sta *ap_sta)
+{
+       struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {};
+       struct iwl_wowlan_tkip_params_cmd tkip_cmd = {};
+       struct wowlan_key_data key_data = {
+               .use_rsc_tsc = false,
+               .tkip = &tkip_cmd,
+               .use_tkip = false,
+       };
+       int ret;
 
        ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
        if (ret)
-               goto out;
+               return ret;
+
+       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+       if (!key_data.rsc_tsc)
+               return -ENOMEM;
 
        if (!iwlwifi_mod_params.sw_crypto) {
                /*
@@ -1010,7 +943,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                }
        }
 
-       ret = iwl_mvm_send_wowlan_config_cmd(mvm, &wowlan_config_cmd);
+       ret = iwl_mvm_send_wowlan_config_cmd(mvm, wowlan_config_cmd);
        if (ret)
                goto out;
 
@@ -1023,8 +956,93 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                goto out;
 
        ret = iwl_mvm_send_remote_wake_cfg(mvm, vif, wowlan->tcp);
-       if (ret)
-               goto out;
+
+out:
+       kfree(key_data.rsc_tsc);
+       return ret;
+}
+
+static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
+                            struct cfg80211_wowlan *wowlan,
+                            bool test)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       struct ieee80211_vif *vif = NULL;
+       struct iwl_mvm_vif *mvmvif = NULL;
+       struct ieee80211_sta *ap_sta = NULL;
+       struct iwl_wowlan_config_cmd_v3 wowlan_config_cmd = {};
+       struct iwl_d3_manager_config d3_cfg_cmd_data = {
+               /*
+                * Program the minimum sleep time to 10 seconds, as many
+                * platforms have issues processing a wakeup signal while
+                * still being in the process of suspending.
+                */
+               .min_sleep_time = cpu_to_le32(10 * 1000 * 1000),
+       };
+       struct iwl_host_cmd d3_cfg_cmd = {
+               .id = D3_CONFIG_CMD,
+               .flags = CMD_WANT_SKB,
+               .data[0] = &d3_cfg_cmd_data,
+               .len[0] = sizeof(d3_cfg_cmd_data),
+       };
+       int ret;
+       int len __maybe_unused;
+
+       if (!wowlan) {
+               /*
+                * mac80211 shouldn't get here, but for D3 test
+                * it doesn't warrant a warning
+                */
+               WARN_ON(!test);
+               return -EINVAL;
+       }
+
+       mutex_lock(&mvm->mutex);
+
+       vif = iwl_mvm_get_bss_vif(mvm);
+       if (IS_ERR_OR_NULL(vif)) {
+               ret = 1;
+               goto out_noreset;
+       }
+
+       mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+       /* if we're associated, this is wowlan */
+       if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+               ap_sta = rcu_dereference_protected(
+                       mvm->fw_id_to_mac_id[mvmvif->ap_sta_id],
+                       lockdep_is_held(&mvm->mutex));
+               if (IS_ERR_OR_NULL(ap_sta)) {
+                       ret = -EINVAL;
+                       goto out_noreset;
+               }
+
+               ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
+                                               vif, mvmvif, ap_sta);
+               if (ret)
+                       goto out_noreset;
+
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       goto out;
+
+               ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
+                                           vif, mvmvif, ap_sta);
+               if (ret)
+                       goto out;
+       } else if (mvm->nd_config) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       goto out;
+
+               ret = iwl_mvm_scan_offload_start(mvm, vif, mvm->nd_config,
+                                                mvm->nd_ies);
+               if (ret)
+                       goto out;
+       } else {
+               ret = 1;
+               goto out_noreset;
+       }
 
        ret = iwl_mvm_power_update_device(mvm);
        if (ret)
@@ -1060,8 +1078,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        if (ret < 0)
                ieee80211_restart_hw(mvm->hw);
  out_noreset:
-       kfree(key_data.rsc_tsc);
-
        mutex_unlock(&mvm->mutex);
 
        return ret;
@@ -1592,9 +1608,6 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
 
 static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 {
-       struct iwl_d3_iter_data resume_iter_data = {
-               .mvm = mvm,
-       };
        struct ieee80211_vif *vif = NULL;
        int ret;
        enum iwl_d3_status d3_status;
@@ -1603,15 +1616,10 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        mutex_lock(&mvm->mutex);
 
        /* get the BSS vif pointer again */
-       ieee80211_iterate_active_interfaces_atomic(
-               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-               iwl_mvm_d3_iface_iterator, &resume_iter_data);
-
-       if (WARN_ON(resume_iter_data.error || !resume_iter_data.vif))
+       vif = iwl_mvm_get_bss_vif(mvm);
+       if (IS_ERR_OR_NULL(vif))
                goto out_unlock;
 
-       vif = resume_iter_data.vif;
-
        ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
        if (ret)
                goto out_unlock;
@@ -1741,7 +1749,9 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
        int remaining_time = 10;
 
        mvm->d3_test_active = false;
+       rtnl_lock();
        __iwl_mvm_resume(mvm, true);
+       rtnl_unlock();
        iwl_abort_notification_waits(&mvm->notif_wait);
        ieee80211_restart_hw(mvm->hw);
 
index 50527a9bb26739b572e1b0faad8b7afa5114662d..51b7116965ed8a9d68383f043d139c11071a5ac1 100644 (file)
@@ -121,78 +121,6 @@ static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf,
        return ret;
 }
 
-static int iwl_dbgfs_fw_error_dump_open(struct inode *inode, struct file *file)
-{
-       struct iwl_mvm *mvm = inode->i_private;
-       int ret;
-
-       if (!mvm)
-               return -EINVAL;
-
-       mutex_lock(&mvm->mutex);
-       if (!mvm->fw_error_dump) {
-               ret = -ENODATA;
-               goto out;
-       }
-
-       file->private_data = mvm->fw_error_dump;
-       mvm->fw_error_dump = NULL;
-       ret = 0;
-
-out:
-       mutex_unlock(&mvm->mutex);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_fw_error_dump_read(struct file *file,
-                                           char __user *user_buf,
-                                           size_t count, loff_t *ppos)
-{
-       struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-       ssize_t bytes_read = 0;
-       ssize_t bytes_read_trans = 0;
-
-       if (*ppos < dump_ptrs->op_mode_len)
-               bytes_read +=
-                       simple_read_from_buffer(user_buf, count, ppos,
-                                               dump_ptrs->op_mode_ptr,
-                                               dump_ptrs->op_mode_len);
-
-       if (bytes_read < 0 || *ppos < dump_ptrs->op_mode_len)
-               return bytes_read;
-
-       if (dump_ptrs->trans_ptr) {
-               *ppos -= dump_ptrs->op_mode_len;
-               bytes_read_trans =
-                       simple_read_from_buffer(user_buf + bytes_read,
-                                               count - bytes_read, ppos,
-                                               dump_ptrs->trans_ptr->data,
-                                               dump_ptrs->trans_ptr->len);
-               *ppos += dump_ptrs->op_mode_len;
-
-               if (bytes_read_trans >= 0)
-                       bytes_read += bytes_read_trans;
-               else if (!bytes_read)
-                       /* propagate the failure */
-                       return bytes_read_trans;
-       }
-
-       return bytes_read;
-
-}
-
-static int iwl_dbgfs_fw_error_dump_release(struct inode *inode,
-                                          struct file *file)
-{
-       struct iwl_mvm_dump_ptrs *dump_ptrs = (void *)file->private_data;
-
-       vfree(dump_ptrs->op_mode_ptr);
-       vfree(dump_ptrs->trans_ptr);
-       kfree(dump_ptrs);
-
-       return 0;
-}
-
 static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
                                   size_t count, loff_t *ppos)
 {
@@ -1250,6 +1178,126 @@ static ssize_t iwl_dbgfs_d3_sram_read(struct file *file, char __user *user_buf,
 
        return ret;
 }
+
+#define MAX_NUM_ND_MATCHSETS 10
+
+static ssize_t iwl_dbgfs_netdetect_write(struct iwl_mvm *mvm, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       const char *seps = ",\n";
+       char *buf_ptr = buf;
+       char *value_str = NULL;
+       int ret, i;
+
+       /* TODO: don't free if write is being called several times in one go */
+       if (mvm->nd_config) {
+               kfree(mvm->nd_config->match_sets);
+               kfree(mvm->nd_config);
+               mvm->nd_config = NULL;
+               kfree(mvm->nd_ies);
+               mvm->nd_ies = NULL;
+       }
+
+       mvm->nd_ies = kzalloc(sizeof(*mvm->nd_ies), GFP_KERNEL);
+       if (!mvm->nd_ies)
+               return -ENOMEM;
+
+       mvm->nd_config = kzalloc(sizeof(*mvm->nd_config) +
+                                (11 * sizeof(struct ieee80211_channel *)),
+                                GFP_KERNEL);
+       if (!mvm->nd_config) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       mvm->nd_config->n_channels = 11;
+       mvm->nd_config->scan_width = NL80211_BSS_CHAN_WIDTH_20;
+       mvm->nd_config->interval = 5;
+       mvm->nd_config->min_rssi_thold = -80;
+       for (i = 0; i < mvm->nd_config->n_channels; i++)
+               mvm->nd_config->channels[i] = &mvm->nvm_data->channels[i];
+
+       mvm->nd_config->match_sets =
+               kcalloc(MAX_NUM_ND_MATCHSETS,
+                       sizeof(*mvm->nd_config->match_sets),
+                       GFP_KERNEL);
+       if (!mvm->nd_config->match_sets) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       while ((value_str = strsep(&buf_ptr, seps)) &&
+              strlen(value_str)) {
+               struct cfg80211_match_set *set;
+
+               if (mvm->nd_config->n_match_sets >= MAX_NUM_ND_MATCHSETS) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
+
+               set = &mvm->nd_config->match_sets[mvm->nd_config->n_match_sets];
+               set->ssid.ssid_len = strlen(value_str);
+
+               if (set->ssid.ssid_len > IEEE80211_MAX_SSID_LEN) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
+
+               memcpy(set->ssid.ssid, value_str, set->ssid.ssid_len);
+
+               mvm->nd_config->n_match_sets++;
+       }
+
+       ret = count;
+
+       if (mvm->nd_config->n_match_sets)
+               goto out;
+
+out_free:
+       if (mvm->nd_config)
+               kfree(mvm->nd_config->match_sets);
+       kfree(mvm->nd_config);
+       mvm->nd_config = NULL;
+       kfree(mvm->nd_ies);
+       mvm->nd_ies = NULL;
+out:
+       return ret;
+}
+
+static ssize_t
+iwl_dbgfs_netdetect_read(struct file *file, char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm *mvm = file->private_data;
+       size_t bufsz, ret;
+       char *buf;
+       int i, n_match_sets, pos = 0;
+
+       n_match_sets = mvm->nd_config ? mvm->nd_config->n_match_sets : 0;
+
+       bufsz = n_match_sets * (IEEE80211_MAX_SSID_LEN + 1) + 1;
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < n_match_sets; i++) {
+               if (pos +
+                   mvm->nd_config->match_sets[i].ssid.ssid_len + 2 > bufsz) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               memcpy(buf + pos, mvm->nd_config->match_sets[i].ssid.ssid,
+                      mvm->nd_config->match_sets[i].ssid.ssid_len);
+               pos += mvm->nd_config->match_sets[i].ssid.ssid_len;
+               buf[pos++] = '\n';
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+out:
+       kfree(buf);
+       return ret;
+}
 #endif
 
 #define PRINT_MVM_REF(ref) do {                                                \
@@ -1415,12 +1463,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
 
-static const struct file_operations iwl_dbgfs_fw_error_dump_ops = {
-       .open = iwl_dbgfs_fw_error_dump_open,
-       .read = iwl_dbgfs_fw_error_dump_read,
-       .release = iwl_dbgfs_fw_error_dump_release,
-};
-
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
@@ -1428,6 +1470,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters_macs, 256);
 
 #ifdef CONFIG_PM_SLEEP
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(d3_sram, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(netdetect, 384);
 #endif
 
 int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
@@ -1446,7 +1489,6 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
                             S_IWUSR | S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR);
-       MVM_DEBUGFS_ADD_FILE(fw_error_dump, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR);
        MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir,
@@ -1487,6 +1529,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR,
                                 mvm->debugfs_dir, &mvm->d3_wake_sysassert))
                goto err;
+       MVM_DEBUGFS_ADD_FILE(netdetect, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
 #endif
 
        if (!debugfs_create_u8("low_latency_agg_frame_limit", S_IRUSR | S_IWUSR,
index 0c5c0b0e23f5bbe167193c12bb954fbd2dfe8ba1..b8ab4a108720240786d320c477e919081d6bf123 100644 (file)
@@ -197,8 +197,7 @@ static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
 /*
  * Get the mask of the queues used by the vif
  */
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
-                               struct ieee80211_vif *vif)
+u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
 {
        u32 qmask = 0, ac;
 
@@ -227,7 +226,7 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
        }
 
        /* Mark the queues used by the vif */
-       data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(data->mvm, vif);
+       data->used_hw_queues |= iwl_mvm_mac_get_queues_mask(vif);
 
        /* Mark MAC IDs as used by clearing the available bit, and
         * (below) mark TSFs as used if their existing use is not
index 585fe5b7100fb8750bed29eda65d91121422497c..f308e52781f6f060e61d21608b313505b145ac48 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ip.h>
 #include <linux/if_arp.h>
+#include <linux/devcoredump.h>
 #include <net/mac80211.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/tcp.h>
@@ -679,10 +680,51 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
        memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
 }
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
+static ssize_t iwl_mvm_read_coredump(char *buffer, loff_t offset, size_t count,
+                                    const void *data, size_t datalen)
+{
+       const struct iwl_mvm_dump_ptrs *dump_ptrs = data;
+       ssize_t bytes_read;
+       ssize_t bytes_read_trans;
+
+       if (offset < dump_ptrs->op_mode_len) {
+               bytes_read = min_t(ssize_t, count,
+                                  dump_ptrs->op_mode_len - offset);
+               memcpy(buffer, (u8 *)dump_ptrs->op_mode_ptr + offset,
+                      bytes_read);
+               offset += bytes_read;
+               count -= bytes_read;
+
+               if (count == 0)
+                       return bytes_read;
+       } else {
+               bytes_read = 0;
+       }
+
+       if (!dump_ptrs->trans_ptr)
+               return bytes_read;
+
+       offset -= dump_ptrs->op_mode_len;
+       bytes_read_trans = min_t(ssize_t, count,
+                                dump_ptrs->trans_ptr->len - offset);
+       memcpy(buffer + bytes_read,
+              (u8 *)dump_ptrs->trans_ptr->data + offset,
+              bytes_read_trans);
+
+       return bytes_read + bytes_read_trans;
+}
+
+static void iwl_mvm_free_coredump(const void *data)
+{
+       const struct iwl_mvm_dump_ptrs *fw_error_dump = data;
+
+       vfree(fw_error_dump->op_mode_ptr);
+       vfree(fw_error_dump->trans_ptr);
+       kfree(fw_error_dump);
+}
+
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 {
-       static char *env[] = { "DRIVER=iwlwifi", "EVENT=error_dump", NULL };
        struct iwl_fw_error_dump_file *dump_file;
        struct iwl_fw_error_dump_data *dump_data;
        struct iwl_fw_error_dump_info *dump_info;
@@ -695,10 +737,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (mvm->fw_error_dump)
-               return;
-
-       fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
+       fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
        if (!fw_error_dump)
                return;
 
@@ -773,12 +812,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        if (fw_error_dump->trans_ptr)
                file_len += fw_error_dump->trans_ptr->len;
        dump_file->file_len = cpu_to_le32(file_len);
-       mvm->fw_error_dump = fw_error_dump;
 
-       /* notify the userspace about the error we had */
-       kobject_uevent_env(&mvm->hw->wiphy->dev.kobj, KOBJ_CHANGE, env);
+       dev_coredumpm(mvm->trans->dev, THIS_MODULE, fw_error_dump, 0,
+                     GFP_KERNEL, iwl_mvm_read_coredump, iwl_mvm_free_coredump);
 }
-#endif
 
 static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
 {
@@ -858,9 +895,8 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
        return ret;
 }
 
-static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
+static void iwl_mvm_restart_complete(struct iwl_mvm *mvm)
 {
-       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        int ret;
 
        mutex_lock(&mvm->mutex);
@@ -878,6 +914,21 @@ static void iwl_mvm_mac_restart_complete(struct ieee80211_hw *hw)
        mutex_unlock(&mvm->mutex);
 }
 
+static void
+iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw,
+                             enum ieee80211_reconfig_type reconfig_type)
+{
+       struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+
+       switch (reconfig_type) {
+       case IEEE80211_RECONFIG_TYPE_RESTART:
+               iwl_mvm_restart_complete(mvm);
+               break;
+       case IEEE80211_RECONFIG_TYPE_SUSPEND:
+               break;
+       }
+}
+
 void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
 {
        lockdep_assert_held(&mvm->mutex);
@@ -1086,7 +1137,7 @@ 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(mvm, vif);
+       u32 tfd_msk = iwl_mvm_mac_get_queues_mask(vif);
 
        if (tfd_msk) {
                mutex_lock(&mvm->mutex);
@@ -1382,6 +1433,9 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
                .cmd = cmd,
        };
 
+       if (IWL_MVM_FW_BCAST_FILTER_PASS_ALL)
+               return false;
+
        memset(cmd, 0, sizeof(*cmd));
        cmd->max_bcast_filters = ARRAY_SIZE(cmd->filters);
        cmd->max_macs = ARRAY_SIZE(cmd->macs);
@@ -2170,25 +2224,9 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
 
        mvm->scan_status = IWL_MVM_SCAN_SCHED;
 
-       if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
-               ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
-               if (ret)
-                       goto err;
-       }
-
-       ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+       ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies);
        if (ret)
-               goto err;
-
-       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
-               ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
-       else
-               ret = iwl_mvm_sched_scan_start(mvm, req);
-
-       if (!ret)
-               goto out;
-err:
-       mvm->scan_status = IWL_MVM_SCAN_NONE;
+               mvm->scan_status = IWL_MVM_SCAN_NONE;
 out:
        mutex_unlock(&mvm->mutex);
        return ret;
@@ -3010,25 +3048,31 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
        mvmvif = iwl_mvm_vif_from_mac80211(vif);
        mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
 
-       if (WARN_ON_ONCE(!mvmsta))
-               goto done;
+       if (WARN_ON_ONCE(!mvmsta)) {
+               mutex_unlock(&mvm->mutex);
+               return;
+       }
 
        if (drop) {
                if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true))
                        IWL_ERR(mvm, "flush request fail\n");
+               mutex_unlock(&mvm->mutex);
        } else {
-               iwl_trans_wait_tx_queue_empty(mvm->trans,
-                                             mvmsta->tfd_queue_msk);
+               u32 tfd_queue_msk = mvmsta->tfd_queue_msk;
+               mutex_unlock(&mvm->mutex);
+
+               /* this can take a while, and we may need/want other operations
+                * to succeed while doing this, so do it without the mutex held
+                */
+               iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk);
        }
-done:
-       mutex_unlock(&mvm->mutex);
 }
 
 const struct ieee80211_ops iwl_mvm_hw_ops = {
        .tx = iwl_mvm_mac_tx,
        .ampdu_action = iwl_mvm_mac_ampdu_action,
        .start = iwl_mvm_mac_start,
-       .restart_complete = iwl_mvm_mac_restart_complete,
+       .reconfig_complete = iwl_mvm_mac_reconfig_complete,
        .stop = iwl_mvm_mac_stop,
        .add_interface = iwl_mvm_mac_add_interface,
        .remove_interface = iwl_mvm_mac_remove_interface,
index b153ced7015bfef8984a9ecb78f844d4533ed7d9..256765accbc659f9d431899d110ced3afa26c8f0 100644 (file)
@@ -648,7 +648,6 @@ struct iwl_mvm {
        /* -1 for always, 0 for never, >0 for that many times */
        s8 restart_fw;
        struct work_struct fw_error_dump_wk;
-       struct iwl_mvm_dump_ptrs *fw_error_dump;
 
 #ifdef CONFIG_IWLWIFI_LEDS
        struct led_classdev led;
@@ -659,6 +658,10 @@ struct iwl_mvm {
 #ifdef CONFIG_PM_SLEEP
        struct wiphy_wowlan_support wowlan;
        int gtk_ivlen, gtk_icvlen, ptk_ivlen, ptk_icvlen;
+
+       /* sched scan settings for net detect */
+       struct cfg80211_sched_scan_request *nd_config;
+       struct ieee80211_scan_ies *nd_ies;
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        u32 d3_wake_sysassert; /* must be u32 for debugfs_create_bool */
        bool d3_test_active;
@@ -905,8 +908,7 @@ 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);
 int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
-u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
-                               struct ieee80211_vif *vif);
+u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif);
 int iwl_mvm_mac_ctxt_beacon_changed(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif);
 int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
@@ -949,6 +951,10 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
                                       struct cfg80211_sched_scan_request *req);
 int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                             struct cfg80211_sched_scan_request *req);
+int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
+                              struct ieee80211_vif *vif,
+                              struct cfg80211_sched_scan_request *req,
+                              struct ieee80211_scan_ies *ies);
 int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
 int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
                                    struct iwl_rx_cmd_buffer *rxb,
@@ -1206,11 +1212,9 @@ void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
                                           struct ieee80211_vif *vif);
 
+struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
+
 void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
-#ifdef CONFIG_IWLWIFI_DEBUGFS
 void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
-#else
-static inline void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm) {}
-#endif
 
 #endif /* __IWL_MVM_H__ */
index 48cb25a93591a44678fd051e390dc15c02078744..bd52ecfabedba1b3d6d36c416e42a6a011e06d08 100644 (file)
@@ -403,6 +403,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        if (cfg->max_rx_agg_size)
                hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size;
 
+       if (cfg->max_tx_agg_size)
+               hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size;
+
        op_mode = hw->priv;
        op_mode->ops = &iwl_mvm_ops;
 
@@ -584,16 +587,18 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
        ieee80211_unregister_hw(mvm->hw);
 
        kfree(mvm->scan_cmd);
-       if (mvm->fw_error_dump) {
-               vfree(mvm->fw_error_dump->op_mode_ptr);
-               vfree(mvm->fw_error_dump->trans_ptr);
-               kfree(mvm->fw_error_dump);
-       }
        kfree(mvm->mcast_filter_cmd);
        mvm->mcast_filter_cmd = NULL;
 
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
        kfree(mvm->d3_resume_sram);
+       if (mvm->nd_config) {
+               kfree(mvm->nd_config->match_sets);
+               kfree(mvm->nd_config);
+               mvm->nd_config = NULL;
+               kfree(mvm->nd_ies);
+               mvm->nd_ies = NULL;
+       }
 #endif
 
        iwl_trans_op_mode_leave(mvm->trans);
index 18a539999580410dbb9caafdae6d975d15def1fe..ce884847cc8a84c7d04943bf21fed89ad44b9233 100644 (file)
@@ -505,10 +505,11 @@ static const char *rs_pretty_lq_type(enum iwl_table_type type)
 static inline void rs_dump_rate(struct iwl_mvm *mvm, const struct rs_rate *rate,
                                const char *prefix)
 {
-       IWL_DEBUG_RATE(mvm, "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d\n",
+       IWL_DEBUG_RATE(mvm,
+                      "%s: (%s: %d) ANT: %s BW: %d SGI: %d LDPC: %d STBC %d\n",
                       prefix, rs_pretty_lq_type(rate->type),
                       rate->index, rs_pretty_ant(rate->ant),
-                      rate->bw, rate->sgi, rate->ldpc);
+                      rate->bw, rate->sgi, rate->ldpc, rate->stbc);
 }
 
 static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
@@ -741,6 +742,12 @@ static u32 ucode_rate_from_rs_rate(struct iwl_mvm *mvm,
                IWL_ERR(mvm, "Invalid rate->type %d\n", rate->type);
        }
 
+       if (is_siso(rate) && rate->stbc) {
+               /* To enable STBC we need to set both a flag and ANT_AB */
+               ucode_rate |= RATE_MCS_ANT_AB_MSK;
+               ucode_rate |= RATE_MCS_VHT_STBC_MSK;
+       }
+
        ucode_rate |= rate->bw;
        if (rate->sgi)
                ucode_rate |= RATE_MCS_SGI_MSK;
@@ -785,6 +792,8 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
                rate->sgi = true;
        if (ucode_rate & RATE_MCS_LDPC_MSK)
                rate->ldpc = true;
+       if (ucode_rate & RATE_MCS_VHT_STBC_MSK)
+               rate->stbc = true;
 
        rate->bw = ucode_rate & RATE_MCS_CHAN_WIDTH_MSK;
 
@@ -794,7 +803,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
 
                if (nss == 1) {
                        rate->type = LQ_HT_SISO;
-                       WARN_ON_ONCE(num_of_ant != 1);
+                       WARN_ON_ONCE(!rate->stbc && num_of_ant != 1);
                } else if (nss == 2) {
                        rate->type = LQ_HT_MIMO2;
                        WARN_ON_ONCE(num_of_ant != 2);
@@ -992,7 +1001,15 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
 static inline bool rs_rate_match(struct rs_rate *a,
                                 struct rs_rate *b)
 {
-       return (a->type == b->type) && (a->ant == b->ant) && (a->sgi == b->sgi);
+       bool ant_match;
+
+       if (a->stbc)
+               ant_match = (b->ant == ANT_A || b->ant == ANT_B);
+       else
+               ant_match = (a->ant == b->ant);
+
+       return (a->type == b->type) && (a->bw == b->bw) && (a->sgi == b->sgi)
+               && ant_match;
 }
 
 static u32 rs_ch_width_from_mac_flags(enum mac80211_rate_control_flags flags)
@@ -1225,7 +1242,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        IWL_DEBUG_RATE(mvm, "reduced txpower: %d\n", reduced_txp);
 done:
        /* See if there's a better rate or modulation mode to try. */
-       if (sta && sta->supp_rates[info->band])
+       if (sta->supp_rates[info->band])
                rs_rate_scale_perform(mvm, sta, lq_sta, tid);
 }
 
@@ -1623,6 +1640,8 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
                else
                        rate->type = LQ_LEGACY_G;
 
+               rate->bw = RATE_MCS_CHAN_WIDTH_20;
+               rate->ldpc = false;
                rate_mask = lq_sta->active_legacy_rate;
        } else if (column->mode == RS_SISO) {
                rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO;
@@ -1634,8 +1653,11 @@ static int rs_switch_to_column(struct iwl_mvm *mvm,
                WARN_ON_ONCE("Bad column mode");
        }
 
-       rate->bw = rs_bw_from_sta_bw(sta);
-       rate->ldpc = lq_sta->ldpc;
+       if (column->mode != RS_LEGACY) {
+               rate->bw = rs_bw_from_sta_bw(sta);
+               rate->ldpc = lq_sta->ldpc;
+       }
+
        search_tbl->column = col_id;
        rs_set_expected_tpt_table(lq_sta, search_tbl);
 
@@ -1754,6 +1776,29 @@ out:
        return action;
 }
 
+static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+                         struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+       struct ieee80211_vif *vif = mvmsta->vif;
+       bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
+                               !vif->bss_conf.ps);
+
+       /* Our chip supports Tx STBC and the peer is an HT/VHT STA which
+        * supports STBC of at least 1*SS
+        */
+       if (!lq_sta->stbc)
+               return false;
+
+       if (!mvm->ps_disabled && !sta_ps_disabled)
+               return false;
+
+       if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+               return false;
+
+       return true;
+}
+
 static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
                                int *weaker, int *stronger)
 {
@@ -2675,6 +2720,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                if (mvm->cfg->ht_params->ldpc &&
                    (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
                        lq_sta->ldpc = true;
+
+               if (mvm->cfg->ht_params->stbc &&
+                   (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+                   (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
+                       lq_sta->stbc = true;
        } else {
                rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
                lq_sta->is_vht = true;
@@ -2682,8 +2732,16 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                if (mvm->cfg->ht_params->ldpc &&
                    (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
                        lq_sta->ldpc = true;
+
+               if (mvm->cfg->ht_params->stbc &&
+                   (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
+                   (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
+                       lq_sta->stbc = true;
        }
 
+       if (IWL_MVM_RS_DISABLE_MIMO)
+               lq_sta->active_mimo2_rate = 0;
+
        lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
                                                    BITS_PER_LONG);
        lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
@@ -2692,11 +2750,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                                                   BITS_PER_LONG);
 
        IWL_DEBUG_RATE(mvm,
-                      "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d\n",
+                      "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
                       lq_sta->active_legacy_rate,
                       lq_sta->active_siso_rate,
                       lq_sta->active_mimo2_rate,
-                      lq_sta->is_vht, lq_sta->ldpc);
+                      lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
        IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
                       lq_sta->max_legacy_rate_idx,
                       lq_sta->max_siso_rate_idx,
@@ -2820,6 +2878,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
  * rate[15] 0x800D Legacy | ANT: B Rate: 6 Mbps
  */
 static void rs_build_rates_table(struct iwl_mvm *mvm,
+                                struct ieee80211_sta *sta,
                                 struct iwl_lq_sta *lq_sta,
                                 const struct rs_rate *initial_rate)
 {
@@ -2832,6 +2891,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
        memcpy(&rate, initial_rate, sizeof(rate));
 
        valid_tx_ant = mvm->fw->valid_tx_ant;
+       rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
 
        if (is_siso(&rate)) {
                num_rates = RS_INITIAL_SISO_NUM_RATES;
@@ -2903,7 +2963,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
        if (WARN_ON_ONCE(!sta || !initial_rate))
                return;
 
-       rs_build_rates_table(mvm, lq_sta, initial_rate);
+       rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
 
        if (num_of_ant(initial_rate->ant) == 1)
                lq_cmd->single_stream_ant_msk = initial_rate->ant;
index eb34c1209acc2d6fdd9d35fd2b03d2ea3e565780..defd70a6d9e66da6f64cd39989a607f286821966 100644 (file)
@@ -208,6 +208,7 @@ struct rs_rate {
        u32 bw;
        bool sgi;
        bool ldpc;
+       bool stbc;
 };
 
 
@@ -331,6 +332,7 @@ struct iwl_lq_sta {
        u64 last_tx;
        bool is_vht;
        bool ldpc;              /* LDPC Rx is supported by the STA */
+       bool stbc;              /* Tx STBC is supported by chip and Rx by STA */
        enum ieee80211_band band;
 
        /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
index b280d5d87127e87ea80f1eb36a477dad3dfcc6e2..5cd59a43e1da51acb1fd4debb21ce8e9f38be1c0 100644 (file)
@@ -270,7 +270,8 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        bool *global_bound = data;
 
-       if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
+       if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
+           mvmvif->phy_ctxt->id < MAX_PHYS)
                *global_bound = true;
 }
 
@@ -672,6 +673,7 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
                mvm->scan_status = IWL_MVM_SCAN_NONE;
                ieee80211_scan_completed(mvm->hw,
                                         status == IWL_SCAN_OFFLOAD_ABORTED);
+               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
        }
 
        mvm->last_ebs_successful = !ebs_status;
@@ -1007,6 +1009,31 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
                                    sizeof(scan_req), &scan_req);
 }
 
+int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
+                              struct ieee80211_vif *vif,
+                              struct cfg80211_sched_scan_request *req,
+                              struct ieee80211_scan_ies *ies)
+{
+       int ret;
+
+       if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
+               ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+               if (ret)
+                       return ret;
+               ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
+       } else {
+               ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
+               if (ret)
+                       return ret;
+               ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
+               if (ret)
+                       return ret;
+               ret = iwl_mvm_sched_scan_start(mvm, req);
+       }
+
+       return ret;
+}
+
 static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
 {
        int ret;
@@ -1081,8 +1108,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        /*
         * Clear the scan status so the next scan requests will succeed. This
         * also ensures the Rx handler doesn't do anything, as the scan was
-        * stopped from above.
+        * stopped from above. Since the rx handler won't do anything now,
+        * we have to release the scan reference here.
         */
+       if (mvm->scan_status == IWL_MVM_SCAN_OS)
+               iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
+
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
index 1731c205c81db57929da67a4527b90190316fa71..dd0dc5bf8583960a82830a61c0527b5a32f946d7 100644 (file)
@@ -609,7 +609,7 @@ int iwl_mvm_alloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 
        lockdep_assert_held(&mvm->mutex);
 
-       qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
+       qmask = iwl_mvm_mac_get_queues_mask(vif);
 
        /*
         * The firmware defines the TFD queue mask to only be relevant
index acca44a450864cc446d3a0a653c20e85314465fd..d4f2c29025c74d021558b1d52e35c3aeea9cff49 100644 (file)
  *****************************************************************************/
 
 #include "mvm.h"
-#include "iwl-config.h"
-#include "iwl-io.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
 
 #define IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT        HZ
 
index c6a517c771df5045cd5d2cecc80b4b29848a6c9c..8d848735cdb8199b5eff0aef2ff182100c54036d 100644 (file)
@@ -189,8 +189,10 @@ static void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm,
 
        /* HT rate doesn't make sense for a non data frame */
        WARN_ONCE(info->control.rates[0].flags & IEEE80211_TX_RC_MCS,
-                 "Got an HT rate for a non data frame 0x%x\n",
-                 info->control.rates[0].flags);
+                 "Got an HT rate (flags:0x%x/mcs:%d) for a non data frame (fc:0x%x)\n",
+                 info->control.rates[0].flags,
+                 info->control.rates[0].idx,
+                 le16_to_cpu(fc));
 
        rate_idx = info->control.rates[0].idx;
        /* if the rate isn't a well known legacy rate, take the lowest one */
index 8021f6eec27f7d8a918b41404383d85cc317b7ca..e56e77ef5d2e3d28d9a30185ef257aa43912ed23 100644 (file)
@@ -734,3 +734,40 @@ bool iwl_mvm_is_idle(struct iwl_mvm *mvm)
 
        return idle;
 }
+
+struct iwl_bss_iter_data {
+       struct ieee80211_vif *vif;
+       bool error;
+};
+
+static void iwl_mvm_bss_iface_iterator(void *_data, u8 *mac,
+                                      struct ieee80211_vif *vif)
+{
+       struct iwl_bss_iter_data *data = _data;
+
+       if (vif->type != NL80211_IFTYPE_STATION || vif->p2p)
+               return;
+
+       if (data->vif) {
+               data->error = true;
+               return;
+       }
+
+       data->vif = vif;
+}
+
+struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm)
+{
+       struct iwl_bss_iter_data bss_iter_data = {};
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+               iwl_mvm_bss_iface_iterator, &bss_iter_data);
+
+       if (bss_iter_data.error) {
+               IWL_ERR(mvm, "More than one managed interface active!\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       return bss_iter_data.vif;
+}
index 3781b029e54a328f6304bfb6cf61d52c053cbce7..40a290603eade3ffc9eb173e846ad9dd2a711a9f 100644 (file)
@@ -133,7 +133,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans)
                break;
        }
 
-       if (!page)
+       if (WARN_ON_ONCE(!page))
                return;
 
        trans_pcie->fw_mon_page = page;
@@ -746,15 +746,12 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        int ret = 0;
        int first_ucode_section;
 
-       IWL_DEBUG_FW(trans,
-                    "working with %s image\n",
-                    image->is_secure ? "Secured" : "Non Secured");
        IWL_DEBUG_FW(trans,
                     "working with %s CPU\n",
                     image->is_dual_cpus ? "Dual" : "Single");
 
        /* configure the ucode to be ready to get the secured image */
-       if (image->is_secure) {
+       if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
                /* set secure boot inspector addresses */
                iwl_write_prph(trans,
                               LMPM_SECURE_INSPECTOR_CODE_ADDR,
@@ -790,7 +787,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
                               LMPM_SECURE_CPU2_HDR_MEM_SPACE);
 
                /* load to FW the binary sections of CPU2 */
-               if (image->is_secure)
+               if (iwl_has_secure_boot(trans->hw_rev,
+                                       trans->cfg->device_family))
                        ret = iwl_pcie_load_cpu_secured_sections(
                                                        trans, image, 2,
                                                        &first_ucode_section);
@@ -821,7 +819,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
        else
                iwl_write32(trans, CSR_RESET, 0);
 
-       if (image->is_secure) {
+       if (iwl_has_secure_boot(trans->hw_rev, trans->cfg->device_family)) {
                /* wait for image verification to complete  */
                ret = iwl_poll_prph_bit(trans,
                                        LMPM_SECURE_BOOT_CPU1_STATUS_ADDR,
@@ -1023,14 +1021,6 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                return 0;
        }
 
-       iwl_pcie_set_pwr(trans, false);
-
-       val = iwl_read32(trans, CSR_RESET);
-       if (val & CSR_RESET_REG_FLAG_NEVO_RESET) {
-               *status = IWL_D3_STATUS_RESET;
-               return 0;
-       }
-
        /*
         * Also enables interrupts - none will happen as the device doesn't
         * know we're waking it up, only when the opmode actually tells it
@@ -1050,6 +1040,8 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                return ret;
        }
 
+       iwl_pcie_set_pwr(trans, false);
+
        iwl_trans_pcie_tx_reset(trans);
 
        ret = iwl_pcie_rx_init(trans);
@@ -1058,7 +1050,12 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                return ret;
        }
 
-       *status = IWL_D3_STATUS_ALIVE;
+       val = iwl_read32(trans, CSR_RESET);
+       if (val & CSR_RESET_REG_FLAG_NEVO_RESET)
+               *status = IWL_D3_STATUS_RESET;
+       else
+               *status = IWL_D3_STATUS_ALIVE;
+
        return 0;
 }
 
@@ -1767,6 +1764,13 @@ err:
        IWL_ERR(trans, "failed to create the trans debugfs entry\n");
        return -ENOMEM;
 }
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                        struct dentry *dir)
+{
+       return 0;
+}
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 static u32 iwl_trans_pcie_get_cmdlen(struct iwl_tfd *tfd)
 {
@@ -2045,13 +2049,6 @@ struct iwl_trans_dump_data *iwl_trans_pcie_dump_data(struct iwl_trans *trans)
 
        return dump_data;
 }
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                        struct dentry *dir)
-{
-       return 0;
-}
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
 
 static const struct iwl_trans_ops trans_ops_pcie = {
        .start_hw = iwl_trans_pcie_start_hw,
@@ -2088,9 +2085,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .release_nic_access = iwl_trans_pcie_release_nic_access,
        .set_bits_mask = iwl_trans_pcie_set_bits_mask,
 
-#ifdef CONFIG_IWLWIFI_DEBUGFS
        .dump_data = iwl_trans_pcie_dump_data,
-#endif
 };
 
 struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
index babbdc1ce741c62024bc6220fdcf2a7bd3487790..209db62ee627e4efd9999efe5dda9d1bce01ea6c 100644 (file)
@@ -412,6 +412,9 @@ struct mac80211_hwsim_data {
        struct mac_address addresses[2];
        int channels, idx;
        bool use_chanctx;
+       bool destroy_on_close;
+       struct work_struct destroy_work;
+       u32 portid;
 
        struct ieee80211_channel *tmp_chan;
        struct delayed_work roc_done;
@@ -436,7 +439,7 @@ struct mac80211_hwsim_data {
        /*
         * Only radios in the same group can communicate together (the
         * channel has to match too). Each bit represents a group. A
-        * radio can be in more then one group.
+        * radio can be in more than one group.
         */
        u64 group;
 
@@ -447,6 +450,14 @@ struct mac80211_hwsim_data {
        s64 bcn_delta;
        /* absolute beacon transmission time. Used to cover up "tx" delay. */
        u64 abs_bcn_ts;
+
+       /* Stats */
+       u64 tx_pkts;
+       u64 rx_pkts;
+       u64 tx_bytes;
+       u64 rx_bytes;
+       u64 tx_dropped;
+       u64 tx_failed;
 };
 
 
@@ -476,6 +487,14 @@ static struct genl_family hwsim_genl_family = {
        .maxattr = HWSIM_ATTR_MAX,
 };
 
+enum hwsim_multicast_groups {
+       HWSIM_MCGRP_CONFIG,
+};
+
+static const struct genl_multicast_group hwsim_mcgrps[] = {
+       [HWSIM_MCGRP_CONFIG] = { .name = "config", },
+};
+
 /* MAC80211_HWSIM netlink policy */
 
 static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
@@ -496,6 +515,10 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
        [HWSIM_ATTR_REG_CUSTOM_REG] = { .type = NLA_U32 },
        [HWSIM_ATTR_REG_STRICT_REG] = { .type = NLA_FLAG },
        [HWSIM_ATTR_SUPPORT_P2P_DEVICE] = { .type = NLA_FLAG },
+       [HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE] = { .type = NLA_FLAG },
+       [HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING },
+       [HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG },
+       [HWSIM_ATTR_FREQ] = { .type = NLA_U32 },
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -861,8 +884,10 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        /* If the queue contains MAX_QUEUE skb's drop some */
        if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
                /* Droping until WARN_QUEUE level */
-               while (skb_queue_len(&data->pending) >= WARN_QUEUE)
-                       skb_dequeue(&data->pending);
+               while (skb_queue_len(&data->pending) >= WARN_QUEUE) {
+                       ieee80211_free_txskb(hw, skb_dequeue(&data->pending));
+                       data->tx_dropped++;
+               }
        }
 
        skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
@@ -896,6 +921,9 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        if (nla_put_u32(skb, HWSIM_ATTR_FLAGS, hwsim_flags))
                goto nla_put_failure;
 
+       if (nla_put_u32(skb, HWSIM_ATTR_FREQ, data->channel->center_freq))
+               goto nla_put_failure;
+
        /* We get the tx control (rate and retries) info*/
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
@@ -917,10 +945,14 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
 
        /* Enqueue the packet */
        skb_queue_tail(&data->pending, my_skb);
+       data->tx_pkts++;
+       data->tx_bytes += my_skb->len;
        return;
 
 nla_put_failure:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
+       ieee80211_free_txskb(hw, my_skb);
+       data->tx_failed++;
 }
 
 static bool hwsim_chans_compat(struct ieee80211_channel *c1,
@@ -1066,6 +1098,8 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
                rx_status.mactime = now + data2->tsf_offset;
 
                memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+               data2->rx_pkts++;
+               data2->rx_bytes += nskb->len;
                ieee80211_rx_irqsafe(data2->hw, nskb);
        }
        spin_unlock(&hwsim_radio_lock);
@@ -1133,6 +1167,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
                return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
 
        /* NO wmediumd detected, perfect medium simulation */
+       data->tx_pkts++;
+       data->tx_bytes += skb->len;
        ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
 
        if (ack && skb->len >= 16) {
@@ -1916,6 +1952,57 @@ static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw,
        hwsim_check_chanctx_magic(ctx);
 }
 
+static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = {
+       "tx_pkts_nic",
+       "tx_bytes_nic",
+       "rx_pkts_nic",
+       "rx_bytes_nic",
+       "d_tx_dropped",
+       "d_tx_failed",
+       "d_ps_mode",
+       "d_group",
+       "d_tx_power",
+};
+
+#define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats)
+
+static void mac80211_hwsim_get_et_strings(struct ieee80211_hw *hw,
+                                         struct ieee80211_vif *vif,
+                                         u32 sset, u8 *data)
+{
+       if (sset == ETH_SS_STATS)
+               memcpy(data, *mac80211_hwsim_gstrings_stats,
+                      sizeof(mac80211_hwsim_gstrings_stats));
+}
+
+static int mac80211_hwsim_get_et_sset_count(struct ieee80211_hw *hw,
+                                           struct ieee80211_vif *vif, int sset)
+{
+       if (sset == ETH_SS_STATS)
+               return MAC80211_HWSIM_SSTATS_LEN;
+       return 0;
+}
+
+static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif,
+                                       struct ethtool_stats *stats, u64 *data)
+{
+       struct mac80211_hwsim_data *ar = hw->priv;
+       int i = 0;
+
+       data[i++] = ar->tx_pkts;
+       data[i++] = ar->tx_bytes;
+       data[i++] = ar->rx_pkts;
+       data[i++] = ar->rx_bytes;
+       data[i++] = ar->tx_dropped;
+       data[i++] = ar->tx_failed;
+       data[i++] = ar->ps;
+       data[i++] = ar->group;
+       data[i++] = ar->power_level;
+
+       WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN);
+}
+
 static const struct ieee80211_ops mac80211_hwsim_ops = {
        .tx = mac80211_hwsim_tx,
        .start = mac80211_hwsim_start,
@@ -1939,14 +2026,131 @@ static const struct ieee80211_ops mac80211_hwsim_ops = {
        .flush = mac80211_hwsim_flush,
        .get_tsf = mac80211_hwsim_get_tsf,
        .set_tsf = mac80211_hwsim_set_tsf,
+       .get_et_sset_count = mac80211_hwsim_get_et_sset_count,
+       .get_et_stats = mac80211_hwsim_get_et_stats,
+       .get_et_strings = mac80211_hwsim_get_et_strings,
 };
 
 static struct ieee80211_ops mac80211_hwsim_mchan_ops;
 
-static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
-                                      const struct ieee80211_regdomain *regd,
-                                      bool reg_strict, bool p2p_device,
-                                      bool use_chanctx)
+struct hwsim_new_radio_params {
+       unsigned int channels;
+       const char *reg_alpha2;
+       const struct ieee80211_regdomain *regd;
+       bool reg_strict;
+       bool p2p_device;
+       bool use_chanctx;
+       bool destroy_on_close;
+       const char *hwname;
+       bool no_vif;
+};
+
+static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
+                                  struct genl_info *info)
+{
+       if (info)
+               genl_notify(&hwsim_genl_family, mcast_skb,
+                           genl_info_net(info), info->snd_portid,
+                           HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
+       else
+               genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
+                                 HWSIM_MCGRP_CONFIG, GFP_KERNEL);
+}
+
+static struct sk_buff *build_radio_msg(int cmd, int id,
+                                      struct hwsim_new_radio_params *param)
+{
+       struct sk_buff *skb;
+       void *data;
+       int ret;
+
+       skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb)
+               return NULL;
+
+       data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, cmd);
+       if (!data)
+               goto error;
+
+       ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+       if (ret < 0)
+               goto error;
+
+       if (param->channels) {
+               ret = nla_put_u32(skb, HWSIM_ATTR_CHANNELS, param->channels);
+               if (ret < 0)
+                       goto error;
+       }
+
+       if (param->reg_alpha2) {
+               ret = nla_put(skb, HWSIM_ATTR_REG_HINT_ALPHA2, 2,
+                             param->reg_alpha2);
+               if (ret < 0)
+                       goto error;
+       }
+
+       if (param->regd) {
+               int i;
+
+               for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
+                    i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
+                       ;
+
+               if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
+                       ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
+                       if (ret < 0)
+                               goto error;
+               }
+       }
+
+       if (param->reg_strict) {
+               ret = nla_put_flag(skb, HWSIM_ATTR_REG_STRICT_REG);
+               if (ret < 0)
+                       goto error;
+       }
+
+       if (param->p2p_device) {
+               ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_P2P_DEVICE);
+               if (ret < 0)
+                       goto error;
+       }
+
+       if (param->use_chanctx) {
+               ret = nla_put_flag(skb, HWSIM_ATTR_USE_CHANCTX);
+               if (ret < 0)
+                       goto error;
+       }
+
+       if (param->hwname) {
+               ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME,
+                             strlen(param->hwname), param->hwname);
+               if (ret < 0)
+                       goto error;
+       }
+
+       genlmsg_end(skb, data);
+
+       return skb;
+
+error:
+       nlmsg_free(skb);
+       return NULL;
+}
+
+static void hswim_mcast_new_radio(int id, struct genl_info *info,
+                                 struct hwsim_new_radio_params *param)
+{
+       struct sk_buff *mcast_skb;
+
+       mcast_skb = build_radio_msg(HWSIM_CMD_NEW_RADIO, id, param);
+       if (!mcast_skb)
+               return;
+
+       hwsim_mcast_config_msg(mcast_skb, info);
+}
+
+static int mac80211_hwsim_new_radio(struct genl_info *info,
+                                   struct hwsim_new_radio_params *param)
 {
        int err;
        u8 addr[ETH_ALEN];
@@ -1956,16 +2160,16 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        const struct ieee80211_ops *ops = &mac80211_hwsim_ops;
        int idx;
 
-       if (WARN_ON(channels > 1 && !use_chanctx))
+       if (WARN_ON(param->channels > 1 && !param->use_chanctx))
                return -EINVAL;
 
        spin_lock_bh(&hwsim_radio_lock);
        idx = hwsim_radio_idx++;
        spin_unlock_bh(&hwsim_radio_lock);
 
-       if (use_chanctx)
+       if (param->use_chanctx)
                ops = &mac80211_hwsim_mchan_ops;
-       hw = ieee80211_alloc_hw(sizeof(*data), ops);
+       hw = ieee80211_alloc_hw_nm(sizeof(*data), ops, param->hwname);
        if (!hw) {
                printk(KERN_DEBUG "mac80211_hwsim: ieee80211_alloc_hw failed\n");
                err = -ENOMEM;
@@ -2003,9 +2207,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        hw->wiphy->n_addresses = 2;
        hw->wiphy->addresses = data->addresses;
 
-       data->channels = channels;
-       data->use_chanctx = use_chanctx;
+       data->channels = param->channels;
+       data->use_chanctx = param->use_chanctx;
        data->idx = idx;
+       data->destroy_on_close = param->destroy_on_close;
+       if (info)
+               data->portid = info->snd_portid;
 
        if (data->use_chanctx) {
                hw->wiphy->max_scan_ssids = 255;
@@ -2014,12 +2221,12 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                /* For channels > 1 DFS is not allowed */
                hw->wiphy->n_iface_combinations = 1;
                hw->wiphy->iface_combinations = &data->if_combination;
-               if (p2p_device)
+               if (param->p2p_device)
                        data->if_combination = hwsim_if_comb_p2p_dev[0];
                else
                        data->if_combination = hwsim_if_comb[0];
                data->if_combination.num_different_channels = data->channels;
-       } else if (p2p_device) {
+       } else if (param->p2p_device) {
                hw->wiphy->iface_combinations = hwsim_if_comb_p2p_dev;
                hw->wiphy->n_iface_combinations =
                        ARRAY_SIZE(hwsim_if_comb_p2p_dev);
@@ -2040,7 +2247,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                                     BIT(NL80211_IFTYPE_ADHOC) |
                                     BIT(NL80211_IFTYPE_MESH_POINT);
 
-       if (p2p_device)
+       if (param->p2p_device)
                hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_DEVICE);
 
        hw->flags = IEEE80211_HW_MFP_CAPABLE |
@@ -2095,6 +2302,7 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
                sband->ht_cap.ht_supported = true;
                sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
                                    IEEE80211_HT_CAP_GRN_FLD |
+                                   IEEE80211_HT_CAP_SGI_20 |
                                    IEEE80211_HT_CAP_SGI_40 |
                                    IEEE80211_HT_CAP_DSSSCCK40;
                sband->ht_cap.ampdu_factor = 0x3;
@@ -2142,15 +2350,18 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        hw->max_rates = 4;
        hw->max_rate_tries = 11;
 
-       if (reg_strict)
+       if (param->reg_strict)
                hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
-       if (regd) {
+       if (param->regd) {
                hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
-               wiphy_apply_custom_regulatory(hw->wiphy, regd);
+               wiphy_apply_custom_regulatory(hw->wiphy, param->regd);
                /* give the regulatory workqueue a chance to run */
                schedule_timeout_interruptible(1);
        }
 
+       if (param->no_vif)
+               hw->flags |= IEEE80211_HW_NO_AUTO_VIF;
+
        err = ieee80211_register_hw(hw);
        if (err < 0) {
                printk(KERN_DEBUG "mac80211_hwsim: ieee80211_register_hw failed (%d)\n",
@@ -2160,8 +2371,8 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
 
        wiphy_debug(hw->wiphy, "hwaddr %pM registered\n", hw->wiphy->perm_addr);
 
-       if (reg_alpha2)
-               regulatory_hint(hw->wiphy, reg_alpha2);
+       if (param->reg_alpha2)
+               regulatory_hint(hw->wiphy, param->reg_alpha2);
 
        data->debugfs = debugfs_create_dir("hwsim", hw->wiphy->debugfsdir);
        debugfs_create_file("ps", 0666, data->debugfs, data, &hwsim_fops_ps);
@@ -2180,6 +2391,9 @@ static int mac80211_hwsim_create_radio(int channels, const char *reg_alpha2,
        list_add_tail(&data->list, &hwsim_radios);
        spin_unlock_bh(&hwsim_radio_lock);
 
+       if (idx > 0)
+               hswim_mcast_new_radio(idx, info, param);
+
        return idx;
 
 failed_hw:
@@ -2190,8 +2404,48 @@ failed:
        return err;
 }
 
-static void mac80211_hwsim_destroy_radio(struct mac80211_hwsim_data *data)
+static void hwsim_mcast_del_radio(int id, const char *hwname,
+                                 struct genl_info *info)
+{
+       struct sk_buff *skb;
+       void *data;
+       int ret;
+
+       skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb)
+               return;
+
+       data = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
+                          HWSIM_CMD_DEL_RADIO);
+       if (!data)
+               goto error;
+
+       ret = nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, id);
+       if (ret < 0)
+               goto error;
+
+       if (hwname) {
+               ret = nla_put(skb, HWSIM_ATTR_RADIO_NAME, strlen(hwname),
+                             hwname);
+               if (ret < 0)
+                       goto error;
+       }
+
+       genlmsg_end(skb, data);
+
+       hwsim_mcast_config_msg(skb, info);
+
+       return;
+
+error:
+       nlmsg_free(skb);
+}
+
+static void mac80211_hwsim_del_radio(struct mac80211_hwsim_data *data,
+                                    const char *hwname,
+                                    struct genl_info *info)
 {
+       hwsim_mcast_del_radio(data->idx, hwname, info);
        debugfs_remove_recursive(data->debugfs);
        ieee80211_unregister_hw(data->hw);
        device_release_driver(data->dev);
@@ -2209,7 +2463,7 @@ static void mac80211_hwsim_free(void)
                                                list))) {
                list_del(&data->list);
                spin_unlock_bh(&hwsim_radio_lock);
-               mac80211_hwsim_destroy_radio(data);
+               mac80211_hwsim_del_radio(data, NULL, NULL);
                spin_lock_bh(&hwsim_radio_lock);
        }
        spin_unlock_bh(&hwsim_radio_lock);
@@ -2337,7 +2591,6 @@ out:
 static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
                                          struct genl_info *info)
 {
-
        struct mac80211_hwsim_data *data2;
        struct ieee80211_rx_status rx_status;
        const u8 *dst;
@@ -2380,18 +2633,22 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
 
        /* A frame is received from user space */
        memset(&rx_status, 0, sizeof(rx_status));
+       /* TODO: Check ATTR_FREQ if it exists, and maybe throw away off-channel
+        * packets?
+        */
        rx_status.freq = data2->channel->center_freq;
        rx_status.band = data2->channel->band;
        rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
        rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
 
        memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+       data2->rx_pkts++;
+       data2->rx_bytes += skb->len;
        ieee80211_rx_irqsafe(data2->hw, skb);
 
        return 0;
 err:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
-       goto out;
 out:
        dev_kfree_skb(skb);
        return -EINVAL;
@@ -2427,54 +2684,72 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
        return 0;
 }
 
-static int hwsim_create_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
-       unsigned int chans = channels;
-       const char *alpha2 = NULL;
-       const struct ieee80211_regdomain *regd = NULL;
-       bool reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
-       bool p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
-       bool use_chanctx;
+       struct hwsim_new_radio_params param = { 0 };
+
+       param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG];
+       param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE];
+       param.channels = channels;
+       param.destroy_on_close =
+               info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE];
 
        if (info->attrs[HWSIM_ATTR_CHANNELS])
-               chans = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
+               param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]);
+
+       if (info->attrs[HWSIM_ATTR_NO_VIF])
+               param.no_vif = true;
+
+       if (info->attrs[HWSIM_ATTR_RADIO_NAME])
+               param.hwname = nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
 
        if (info->attrs[HWSIM_ATTR_USE_CHANCTX])
-               use_chanctx = true;
+               param.use_chanctx = true;
        else
-               use_chanctx = (chans > 1);
+               param.use_chanctx = (param.channels > 1);
 
        if (info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2])
-               alpha2 = nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
+               param.reg_alpha2 =
+                       nla_data(info->attrs[HWSIM_ATTR_REG_HINT_ALPHA2]);
 
        if (info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]) {
                u32 idx = nla_get_u32(info->attrs[HWSIM_ATTR_REG_CUSTOM_REG]);
 
                if (idx >= ARRAY_SIZE(hwsim_world_regdom_custom))
                        return -EINVAL;
-               regd = hwsim_world_regdom_custom[idx];
+               param.regd = hwsim_world_regdom_custom[idx];
        }
 
-       return mac80211_hwsim_create_radio(chans, alpha2, regd, reg_strict,
-                                          p2p_device, use_chanctx);
+       return mac80211_hwsim_new_radio(info, &param);
 }
 
-static int hwsim_destroy_radio_nl(struct sk_buff *msg, struct genl_info *info)
+static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
 {
        struct mac80211_hwsim_data *data;
-       int idx;
+       s64 idx = -1;
+       const char *hwname = NULL;
 
-       if (!info->attrs[HWSIM_ATTR_RADIO_ID])
+       if (info->attrs[HWSIM_ATTR_RADIO_ID])
+               idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
+       else if (info->attrs[HWSIM_ATTR_RADIO_NAME])
+               hwname = (void *)nla_data(info->attrs[HWSIM_ATTR_RADIO_NAME]);
+       else
                return -EINVAL;
-       idx = nla_get_u32(info->attrs[HWSIM_ATTR_RADIO_ID]);
 
        spin_lock_bh(&hwsim_radio_lock);
        list_for_each_entry(data, &hwsim_radios, list) {
-               if (data->idx != idx)
-                       continue;
+               if (idx >= 0) {
+                       if (data->idx != idx)
+                               continue;
+               } else {
+                       if (hwname &&
+                           strcmp(hwname, wiphy_name(data->hw->wiphy)))
+                               continue;
+               }
+
                list_del(&data->list);
                spin_unlock_bh(&hwsim_radio_lock);
-               mac80211_hwsim_destroy_radio(data);
+               mac80211_hwsim_del_radio(data, hwname, info);
                return 0;
        }
        spin_unlock_bh(&hwsim_radio_lock);
@@ -2501,19 +2776,42 @@ static const struct genl_ops hwsim_ops[] = {
                .doit = hwsim_tx_info_frame_received_nl,
        },
        {
-               .cmd = HWSIM_CMD_CREATE_RADIO,
+               .cmd = HWSIM_CMD_NEW_RADIO,
                .policy = hwsim_genl_policy,
-               .doit = hwsim_create_radio_nl,
+               .doit = hwsim_new_radio_nl,
                .flags = GENL_ADMIN_PERM,
        },
        {
-               .cmd = HWSIM_CMD_DESTROY_RADIO,
+               .cmd = HWSIM_CMD_DEL_RADIO,
                .policy = hwsim_genl_policy,
-               .doit = hwsim_destroy_radio_nl,
+               .doit = hwsim_del_radio_nl,
                .flags = GENL_ADMIN_PERM,
        },
 };
 
+static void destroy_radio(struct work_struct *work)
+{
+       struct mac80211_hwsim_data *data =
+               container_of(work, struct mac80211_hwsim_data, destroy_work);
+
+       mac80211_hwsim_del_radio(data, NULL, NULL);
+}
+
+static void remove_user_radios(u32 portid)
+{
+       struct mac80211_hwsim_data *entry, *tmp;
+
+       spin_lock_bh(&hwsim_radio_lock);
+       list_for_each_entry_safe(entry, tmp, &hwsim_radios, list) {
+               if (entry->destroy_on_close && entry->portid == portid) {
+                       list_del(&entry->list);
+                       INIT_WORK(&entry->destroy_work, destroy_radio);
+                       schedule_work(&entry->destroy_work);
+               }
+       }
+       spin_unlock_bh(&hwsim_radio_lock);
+}
+
 static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
                                         unsigned long state,
                                         void *_notify)
@@ -2523,6 +2821,8 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
        if (state != NETLINK_URELEASE)
                return NOTIFY_DONE;
 
+       remove_user_radios(notify->portid);
+
        if (notify->portid == wmediumd_portid) {
                printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
                       " socket, switching to perfect channel medium\n");
@@ -2542,7 +2842,9 @@ static int hwsim_init_netlink(void)
 
        printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
 
-       rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops);
+       rc = genl_register_family_with_ops_groups(&hwsim_genl_family,
+                                                 hwsim_ops,
+                                                 hwsim_mcgrps);
        if (rc)
                goto failure;
 
@@ -2603,69 +2905,73 @@ static int __init init_mac80211_hwsim(void)
                goto out_unregister_driver;
        }
 
+       err = hwsim_init_netlink();
+       if (err < 0)
+               goto out_unregister_driver;
+
        for (i = 0; i < radios; i++) {
-               const char *reg_alpha2 = NULL;
-               const struct ieee80211_regdomain *regd = NULL;
-               bool reg_strict = false;
+               struct hwsim_new_radio_params param = { 0 };
+
+               param.channels = channels;
 
                switch (regtest) {
                case HWSIM_REGTEST_DIFF_COUNTRY:
                        if (i < ARRAY_SIZE(hwsim_alpha2s))
-                               reg_alpha2 = hwsim_alpha2s[i];
+                               param.reg_alpha2 = hwsim_alpha2s[i];
                        break;
                case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
                        if (!i)
-                               reg_alpha2 = hwsim_alpha2s[0];
+                               param.reg_alpha2 = hwsim_alpha2s[0];
                        break;
                case HWSIM_REGTEST_STRICT_ALL:
-                       reg_strict = true;
+                       param.reg_strict = true;
                case HWSIM_REGTEST_DRIVER_REG_ALL:
-                       reg_alpha2 = hwsim_alpha2s[0];
+                       param.reg_alpha2 = hwsim_alpha2s[0];
                        break;
                case HWSIM_REGTEST_WORLD_ROAM:
                        if (i == 0)
-                               regd = &hwsim_world_regdom_custom_01;
+                               param.regd = &hwsim_world_regdom_custom_01;
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD:
-                       regd = &hwsim_world_regdom_custom_01;
+                       param.regd = &hwsim_world_regdom_custom_01;
                        break;
                case HWSIM_REGTEST_CUSTOM_WORLD_2:
                        if (i == 0)
-                               regd = &hwsim_world_regdom_custom_01;
+                               param.regd = &hwsim_world_regdom_custom_01;
                        else if (i == 1)
-                               regd = &hwsim_world_regdom_custom_02;
+                               param.regd = &hwsim_world_regdom_custom_02;
                        break;
                case HWSIM_REGTEST_STRICT_FOLLOW:
                        if (i == 0) {
-                               reg_strict = true;
-                               reg_alpha2 = hwsim_alpha2s[0];
+                               param.reg_strict = true;
+                               param.reg_alpha2 = hwsim_alpha2s[0];
                        }
                        break;
                case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
                        if (i == 0) {
-                               reg_strict = true;
-                               reg_alpha2 = hwsim_alpha2s[0];
+                               param.reg_strict = true;
+                               param.reg_alpha2 = hwsim_alpha2s[0];
                        } else if (i == 1) {
-                               reg_alpha2 = hwsim_alpha2s[1];
+                               param.reg_alpha2 = hwsim_alpha2s[1];
                        }
                        break;
                case HWSIM_REGTEST_ALL:
                        switch (i) {
                        case 0:
-                               regd = &hwsim_world_regdom_custom_01;
+                               param.regd = &hwsim_world_regdom_custom_01;
                                break;
                        case 1:
-                               regd = &hwsim_world_regdom_custom_02;
+                               param.regd = &hwsim_world_regdom_custom_02;
                                break;
                        case 2:
-                               reg_alpha2 = hwsim_alpha2s[0];
+                               param.reg_alpha2 = hwsim_alpha2s[0];
                                break;
                        case 3:
-                               reg_alpha2 = hwsim_alpha2s[1];
+                               param.reg_alpha2 = hwsim_alpha2s[1];
                                break;
                        case 4:
-                               reg_strict = true;
-                               reg_alpha2 = hwsim_alpha2s[2];
+                               param.reg_strict = true;
+                               param.reg_alpha2 = hwsim_alpha2s[2];
                                break;
                        }
                        break;
@@ -2673,10 +2979,10 @@ static int __init init_mac80211_hwsim(void)
                        break;
                }
 
-               err = mac80211_hwsim_create_radio(channels, reg_alpha2,
-                                                 regd, reg_strict,
-                                                 support_p2p_device,
-                                                 channels > 1);
+               param.p2p_device = support_p2p_device;
+               param.use_chanctx = channels > 1;
+
+               err = mac80211_hwsim_new_radio(NULL, &param);
                if (err < 0)
                        goto out_free_radios;
        }
@@ -2702,10 +3008,6 @@ static int __init init_mac80211_hwsim(void)
        }
        rtnl_unlock();
 
-       err = hwsim_init_netlink();
-       if (err < 0)
-               goto out_free_mon;
-
        return 0;
 
 out_free_mon:
index c9d0315575bab27035378378d396a46db828bf4c..f08debdd639b5aeeb35a819fe99fd5811301f13c 100644 (file)
@@ -60,14 +60,15 @@ enum hwsim_tx_control_flags {
  * space, uses:
  *     %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER,
  *     %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE,
- *     %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
+ *     %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE, %HWSIM_ATTR_FREQ (optional)
  * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to
  * kernel, uses:
  *     %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
  *     %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
- * @HWSIM_CMD_CREATE_RADIO: create a new radio with the given parameters,
- *     returns the radio ID (>= 0) or negative on errors
- * @HWSIM_CMD_DESTROY_RADIO: destroy a radio
+ * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters,
+ *     returns the radio ID (>= 0) or negative on errors, if successful
+ *     then multicast the result
+ * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @__HWSIM_CMD_MAX: enum limit
  */
 enum {
@@ -75,12 +76,15 @@ enum {
        HWSIM_CMD_REGISTER,
        HWSIM_CMD_FRAME,
        HWSIM_CMD_TX_INFO_FRAME,
-       HWSIM_CMD_CREATE_RADIO,
-       HWSIM_CMD_DESTROY_RADIO,
+       HWSIM_CMD_NEW_RADIO,
+       HWSIM_CMD_DEL_RADIO,
        __HWSIM_CMD_MAX,
 };
 #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
 
+#define HWSIM_CMD_CREATE_RADIO   HWSIM_CMD_NEW_RADIO
+#define HWSIM_CMD_DESTROY_RADIO  HWSIM_CMD_DEL_RADIO
+
 /**
  * enum hwsim_attrs - hwsim netlink attributes
  *
@@ -111,6 +115,11 @@ enum {
  * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO
  *     command to force use of channel contexts even when only a
  *     single channel is supported
+ * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO
+ *     command to force radio removal when process that created the radio dies
+ * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666
+ * @HWSIM_ATTR_NO_VIF:  Do not create vif (wlanX) when creating radio.
+ * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -132,6 +141,10 @@ enum {
        HWSIM_ATTR_REG_STRICT_REG,
        HWSIM_ATTR_SUPPORT_P2P_DEVICE,
        HWSIM_ATTR_USE_CHANCTX,
+       HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE,
+       HWSIM_ATTR_RADIO_NAME,
+       HWSIM_ATTR_NO_VIF,
+       HWSIM_ATTR_FREQ,
        __HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
index 0dd672954ad10316bec599a0f2eeb56b70e66c75..f63abfd8acd71433bc65fc7bf0eef75ece5d8653 100644 (file)
@@ -992,6 +992,52 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
        return mwifiex_dump_station_info(priv, sinfo);
 }
 
+static int
+mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+                            int idx, struct survey_info *survey)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       struct mwifiex_chan_stats *pchan_stats = priv->adapter->chan_stats;
+       enum ieee80211_band band;
+
+       dev_dbg(priv->adapter->dev, "dump_survey idx=%d\n", idx);
+
+       memset(survey, 0, sizeof(struct survey_info));
+
+       if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+           priv->media_connected && idx == 0) {
+                       u8 curr_bss_band = priv->curr_bss_params.band;
+                       u32 chan = priv->curr_bss_params.bss_descriptor.channel;
+
+                       band = mwifiex_band_to_radio_type(curr_bss_band);
+                       survey->channel = ieee80211_get_channel(wiphy,
+                               ieee80211_channel_to_frequency(chan, band));
+
+                       if (priv->bcn_nf_last) {
+                               survey->filled = SURVEY_INFO_NOISE_DBM;
+                               survey->noise = priv->bcn_nf_last;
+                       }
+                       return 0;
+       }
+
+       if (idx >= priv->adapter->num_in_chan_stats)
+               return -ENOENT;
+
+       if (!pchan_stats[idx].cca_scan_dur)
+               return 0;
+
+       band = pchan_stats[idx].bandcfg;
+       survey->channel = ieee80211_get_channel(wiphy,
+           ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band));
+       survey->filled = SURVEY_INFO_NOISE_DBM |
+               SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
+       survey->noise = pchan_stats[idx].noise;
+       survey->channel_time = pchan_stats[idx].cca_scan_dur;
+       survey->channel_time_busy = pchan_stats[idx].cca_busy_dur;
+
+       return 0;
+}
+
 /* Supported rates to be advertised to the cfg80211 */
 static struct ieee80211_rate mwifiex_rates[] = {
        {.bitrate = 10, .hw_value = 2, },
@@ -1239,7 +1285,7 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
  */
 static int
 mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                            const u8 *mac)
+                            struct station_del_parameters *params)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        struct mwifiex_sta_node *sta_node;
@@ -1248,7 +1294,7 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
        if (list_empty(&priv->sta_list) || !priv->bss_started)
                return 0;
 
-       if (!mac || is_broadcast_ether_addr(mac)) {
+       if (!params->mac || is_broadcast_ether_addr(params->mac)) {
                wiphy_dbg(wiphy, "%s: NULL/broadcast mac address\n", __func__);
                list_for_each_entry(sta_node, &priv->sta_list, list) {
                        if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
@@ -1258,9 +1304,10 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev,
                        mwifiex_uap_del_sta_data(priv, sta_node);
                }
        } else {
-               wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, mac);
+               wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__,
+                         params->mac);
                spin_lock_irqsave(&priv->sta_list_spinlock, flags);
-               sta_node = mwifiex_get_sta_entry(priv, mac);
+               sta_node = mwifiex_get_sta_entry(priv, params->mac);
                spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
                if (sta_node) {
                        if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_STA_DEAUTH,
@@ -2779,6 +2826,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .disconnect = mwifiex_cfg80211_disconnect,
        .get_station = mwifiex_cfg80211_get_station,
        .dump_station = mwifiex_cfg80211_dump_station,
+       .dump_survey = mwifiex_cfg80211_dump_survey,
        .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
        .join_ibss = mwifiex_cfg80211_join_ibss,
        .leave_ibss = mwifiex_cfg80211_leave_ibss,
@@ -2840,6 +2888,25 @@ static const struct wiphy_coalesce_support mwifiex_coalesce_support = {
        .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
 };
 
+int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter)
+{
+       u32 n_channels_bg, n_channels_a = 0;
+
+       n_channels_bg = mwifiex_band_2ghz.n_channels;
+
+       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->chan_stats = vmalloc(sizeof(*adapter->chan_stats) *
+                                     adapter->num_in_chan_stats);
+
+       if (!adapter->chan_stats)
+               return -ENOMEM;
+
+       return 0;
+}
+
 /*
  * This function registers the device with CFG802.11 subsystem.
  *
index e0d00a7f0ec314f9dd03e288af38cbd5c6aa1731..f53e5b50d3d83c141bbe41ce91af8145b96902c1 100644 (file)
@@ -185,4 +185,14 @@ struct mwifiex_arp_eth_header {
        u8 ar_tha[ETH_ALEN];
        u8 ar_tip[4];
 } __packed;
+
+struct mwifiex_chan_stats {
+       u8 chan_num;
+       u8 bandcfg;
+       u8 flags;
+       s8 noise;
+       u16 total_bss;
+       u16 cca_scan_dur;
+       u16 cca_busy_dur;
+} __packed;
 #endif /* !_MWIFIEX_DECL_H_ */
index 1eb61739071fd828bac55865a9df41709e1ccc08..7f922a882c13a4dcfa7481f0a854330955b32f09 100644 (file)
@@ -172,6 +172,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
 #define TLV_TYPE_SCAN_CHANNEL_GAP   (PROPRIETARY_TLV_BASE_ID + 197)
 #define TLV_TYPE_API_REV            (PROPRIETARY_TLV_BASE_ID + 199)
+#define TLV_TYPE_CHANNEL_STATS      (PROPRIETARY_TLV_BASE_ID + 198)
 
 #define MWIFIEX_TX_DATA_BUF_SIZE_2K        2048
 
@@ -611,6 +612,16 @@ struct uap_rxpd {
        u8 reserved1;
 };
 
+struct mwifiex_fw_chan_stats {
+       u8 chan_num;
+       u8 bandcfg;
+       u8 flags;
+       s8 noise;
+       __le16 total_bss;
+       __le16 cca_scan_dur;
+       __le16 cca_busy_dur;
+} __packed;
+
 enum mwifiex_chan_scan_mode_bitmasks {
        MWIFIEX_PASSIVE_SCAN = BIT(0),
        MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
@@ -660,6 +671,11 @@ struct mwifiex_ie_types_scan_chan_gap {
        __le16 chan_gap;
 } __packed;
 
+struct mwifiex_ietypes_chanstats {
+       struct mwifiex_ie_types_header header;
+       struct mwifiex_fw_chan_stats chanstats[0];
+} __packed;
+
 struct mwifiex_ie_types_wildcard_ssid_params {
        struct mwifiex_ie_types_header header;
        u8 max_ssid_length;
index d5070c444fe1fcb53ff95a67024b12013ed547dc..f26420dbab6fa8f833edad4968e03662d50b7d92 100644 (file)
@@ -122,6 +122,7 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
                }
        }
 
+       vfree(adapter->chan_stats);
        kfree(adapter);
        return 0;
 }
@@ -447,6 +448,11 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
                goto err_init_fw;
        }
 
+       if (mwifiex_init_channel_scan_gap(adapter)) {
+               dev_err(adapter->dev, "could not init channel stats table\n");
+               goto err_init_fw;
+       }
+
        rtnl_lock();
        /* Create station interface by default */
        wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
index f55658d15c60710d44603d12b9fbab58414050fc..cb393195eee1730e007929fcee8956363092f8af 100644 (file)
@@ -845,6 +845,9 @@ struct mwifiex_adapter {
        u8 curr_mem_idx;
        bool scan_chan_gap_enabled;
        struct sk_buff_head rx_data_q;
+       struct mwifiex_chan_stats *chan_stats;
+       u32 num_in_chan_stats;
+       int survey_idx;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -1031,7 +1034,8 @@ void mwifiex_set_11ac_ba_params(struct mwifiex_private *priv);
 int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
                                struct host_cmd_ds_command *cmd,
                                void *data_buf);
-int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv);
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+                               struct host_cmd_ds_command *resp);
 int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
                                         void *buf);
 
index ca64d4c941127511bde59dd76d8b2c47299db47b..3a17821157d77c1503ab636fafc8d244ae538def 100644 (file)
@@ -1755,6 +1755,7 @@ static void mwifiex_complete_scan(struct mwifiex_private *priv)
 {
        struct mwifiex_adapter *adapter = priv->adapter;
 
+       adapter->survey_idx = 0;
        if (adapter->curr_cmd->wait_q_enabled) {
                adapter->cmd_wait_q.status = 0;
                if (!priv->scan_request) {
@@ -1976,10 +1977,53 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
        return 0;
 }
 
+static void
+mwifiex_update_chan_statistics(struct mwifiex_private *priv,
+                              struct mwifiex_ietypes_chanstats *tlv_stat)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       u8 i, num_chan;
+       struct mwifiex_fw_chan_stats *fw_chan_stats;
+       struct mwifiex_chan_stats chan_stats;
+
+       fw_chan_stats = (void *)((u8 *)tlv_stat +
+                             sizeof(struct mwifiex_ie_types_header));
+       num_chan = le16_to_cpu(tlv_stat->header.len) /
+                                             sizeof(struct mwifiex_chan_stats);
+
+       for (i = 0 ; i < num_chan; i++) {
+               chan_stats.chan_num = fw_chan_stats->chan_num;
+               chan_stats.bandcfg = fw_chan_stats->bandcfg;
+               chan_stats.flags = fw_chan_stats->flags;
+               chan_stats.noise = fw_chan_stats->noise;
+               chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss);
+               chan_stats.cca_scan_dur =
+                                      le16_to_cpu(fw_chan_stats->cca_scan_dur);
+               chan_stats.cca_busy_dur =
+                                      le16_to_cpu(fw_chan_stats->cca_busy_dur);
+               dev_dbg(adapter->dev,
+                       "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
+                       chan_stats.chan_num,
+                       chan_stats.noise,
+                       chan_stats.total_bss,
+                       chan_stats.cca_scan_dur,
+                       chan_stats.cca_busy_dur);
+               memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
+                      sizeof(struct mwifiex_chan_stats));
+               fw_chan_stats++;
+       }
+}
+
 /* This function handles the command response of extended scan */
-int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
+int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
+                               struct host_cmd_ds_command *resp)
 {
        struct mwifiex_adapter *adapter = priv->adapter;
+       struct host_cmd_ds_802_11_scan_ext *ext_scan_resp;
+       struct mwifiex_ie_types_header *tlv;
+       struct mwifiex_ietypes_chanstats *tlv_stat;
+       u16 buf_left, type, len;
+
        struct host_cmd_ds_command *cmd_ptr;
        struct cmd_ctrl_node *cmd_node;
        unsigned long cmd_flags, scan_flags;
@@ -1987,6 +2031,36 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv)
 
        dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n");
 
+       ext_scan_resp = &resp->params.ext_scan;
+
+       tlv = (void *)ext_scan_resp->tlv_buffer;
+       buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
+                                             - 1);
+
+       while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+               type = le16_to_cpu(tlv->type);
+               len = le16_to_cpu(tlv->len);
+
+               if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
+                       dev_err(adapter->dev,
+                               "error processing scan response TLVs");
+                       break;
+               }
+
+               switch (type) {
+               case TLV_TYPE_CHANNEL_STATS:
+                       tlv_stat = (void *)tlv;
+                       mwifiex_update_chan_statistics(priv, tlv_stat);
+                       break;
+               default:
+                       break;
+               }
+
+               buf_left -= len + sizeof(struct mwifiex_ie_types_header);
+               tlv = (void *)((u8 *)tlv + len +
+                              sizeof(struct mwifiex_ie_types_header));
+       }
+
        spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_flags);
        spin_lock_irqsave(&adapter->scan_pending_q_lock, scan_flags);
        if (list_empty(&adapter->scan_pending_q)) {
index 4aad44685f8dff43f80e5ed79a729bf99dbe8d5c..b65e1014b0fccc1c2124b323416f062de3ba7db4 100644 (file)
@@ -983,7 +983,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                adapter->curr_cmd->wait_q_enabled = false;
                break;
        case HostCmd_CMD_802_11_SCAN_EXT:
-               ret = mwifiex_ret_802_11_scan_ext(priv);
+               ret = mwifiex_ret_802_11_scan_ext(priv, resp);
                adapter->curr_cmd->wait_q_enabled = false;
                break;
        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
index d849d590de250b915ddda53ce64c703beef3215e..c878e3f3993c3ecb7692b980aec723e9723f656e 100644 (file)
@@ -62,7 +62,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev,
        __le16 reg;
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
                                      USB_VENDOR_REQUEST_IN, offset,
-                                     &reg, sizeof(reg), REGISTER_TIMEOUT);
+                                     &reg, sizeof(reg));
        *value = le16_to_cpu(reg);
 }
 
@@ -83,8 +83,7 @@ static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev,
 {
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
                                      USB_VENDOR_REQUEST_IN, offset,
-                                     value, length,
-                                     REGISTER_TIMEOUT16(length));
+                                     value, length);
 }
 
 static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
@@ -94,7 +93,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev,
        __le16 reg = cpu_to_le16(value);
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
                                      USB_VENDOR_REQUEST_OUT, offset,
-                                     &reg, sizeof(reg), REGISTER_TIMEOUT);
+                                     &reg, sizeof(reg));
 }
 
 static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev,
@@ -113,8 +112,7 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 {
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
                                      USB_VENDOR_REQUEST_OUT, offset,
-                                     value, length,
-                                     REGISTER_TIMEOUT16(length));
+                                     value, length);
 }
 
 static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
index 86c43d112a4b7d4f25bfbf123b7cbbfb98bd75b9..dc85d3e0ffe58ecf23faaa1fc75fd92c974b24be 100644 (file)
@@ -116,7 +116,7 @@ EXPORT_SYMBOL_GPL(rt2x00usb_vendor_req_buff_lock);
 int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
                                  const u8 request, const u8 requesttype,
                                  const u16 offset, void *buffer,
-                                 const u16 buffer_length, const int timeout)
+                                 const u16 buffer_length)
 {
        int status = 0;
        unsigned char *tb;
@@ -131,7 +131,7 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
                bsize = min_t(u16, CSR_CACHE_SIZE, len);
                status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
                                                        requesttype, off, tb,
-                                                       bsize, timeout);
+                                                       bsize, REGISTER_TIMEOUT);
 
                tb  += bsize;
                len -= bsize;
index 831b65f93feb27206f816d76c115eba6dc9d8c45..819690e978c07dc27e50b2cff1fa3e64f37e3486 100644 (file)
 })
 
 /*
- * For USB vendor requests we need to pass a timeout
- * time in ms, for this we use the REGISTER_TIMEOUT,
- * however when loading firmware a higher value is
- * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE.
+ * For USB vendor requests we need to pass a timeout time in ms, for this we
+ * use the REGISTER_TIMEOUT, however when loading firmware or read EEPROM
+ * a higher value is required. In that case we use the REGISTER_TIMEOUT_FIRMWARE
+ * and EEPROM_TIMEOUT.
  */
 #define REGISTER_TIMEOUT               500
 #define REGISTER_TIMEOUT_FIRMWARE      1000
-
-/**
- * REGISTER_TIMEOUT16 - Determine the timeout for 16bit register access
- * @__datalen: Data length
- */
-#define REGISTER_TIMEOUT16(__datalen)  \
-       ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u16)) )
-
-/**
- * REGISTER_TIMEOUT32 - Determine the timeout for 32bit register access
- * @__datalen: Data length
- */
-#define REGISTER_TIMEOUT32(__datalen)  \
-       ( REGISTER_TIMEOUT * ((__datalen) / sizeof(u32)) )
+#define EEPROM_TIMEOUT                 2000
 
 /*
  * Cache size
@@ -126,7 +113,6 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
  * @offset: Register offset to perform action on
  * @buffer: Buffer where information will be read/written to by device
  * @buffer_length: Size of &buffer
- * @timeout: Operation timeout
  *
  * This function will use a previously with kmalloc allocated cache
  * to communicate with the device. The contents of the buffer pointer
@@ -139,7 +125,7 @@ int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev,
 int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
                                  const u8 request, const u8 requesttype,
                                  const u16 offset, void *buffer,
-                                 const u16 buffer_length, const int timeout);
+                                 const u16 buffer_length);
 
 /**
  * rt2x00usb_vendor_request_buff - Send register command to device (buffered)
@@ -197,8 +183,7 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev,
 {
        return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
                                        USB_VENDOR_REQUEST_IN, 0, 0,
-                                       eeprom, length,
-                                       REGISTER_TIMEOUT16(length));
+                                       eeprom, length, EEPROM_TIMEOUT);
 }
 
 /**
@@ -217,7 +202,7 @@ static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev,
        __le32 reg;
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
                                      USB_VENDOR_REQUEST_IN, offset,
-                                     &reg, sizeof(reg), REGISTER_TIMEOUT);
+                                     &reg, sizeof(reg));
        *value = le32_to_cpu(reg);
 }
 
@@ -257,8 +242,7 @@ static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev,
 {
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
                                      USB_VENDOR_REQUEST_IN, offset,
-                                     value, length,
-                                     REGISTER_TIMEOUT32(length));
+                                     value, length);
 }
 
 /**
@@ -277,7 +261,7 @@ static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev,
        __le32 reg = cpu_to_le32(value);
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
                                      USB_VENDOR_REQUEST_OUT, offset,
-                                     &reg, sizeof(reg), REGISTER_TIMEOUT);
+                                     &reg, sizeof(reg));
 }
 
 /**
@@ -316,8 +300,7 @@ static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev,
 {
        rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
                                      USB_VENDOR_REQUEST_OUT, offset,
-                                     (void *)value, length,
-                                     REGISTER_TIMEOUT32(length));
+                                     (void *)value, length);
 }
 
 /**
index 1e9570fa874fe6309962d2de2251fc923da424cb..9b4d8a63791511ae54b143dae0209f65cd2cb387 100644 (file)
@@ -800,7 +800,7 @@ static void _rtl8821ae_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw,
                                 "Invalid RateSection %d in Band 2.4G,Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
                                 rate_section, path, txnum);
                        break;
-               };
+               }
        } else if (band == BAND_ON_5G) {
                switch (rate_section) {
                case OFDM:
@@ -823,7 +823,7 @@ static void _rtl8821ae_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw,
                                "Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_SetTxPowerByRateBase()\n",
                                rate_section, path, txnum);
                        break;
-               };
+               }
        } else {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
                        "Invalid Band %d in PHY_SetTxPowerByRateBase()\n", band);
@@ -870,7 +870,7 @@ static u8 _rtl8821ae_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw,
                                 "Invalid RateSection %d in Band 2.4G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
                                 rate_section, path, txnum);
                        break;
-               };
+               }
        } else if (band == BAND_ON_5G) {
                switch (rate_section) {
                case OFDM:
@@ -893,7 +893,7 @@ static u8 _rtl8821ae_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw,
                                 "Invalid RateSection %d in Band 5G, Rf Path %d, %dTx in PHY_GetTxPowerByRateBase()\n",
                                 rate_section, path, txnum);
                        break;
-               };
+               }
        } else {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
                         "Invalid Band %d in PHY_GetTxPowerByRateBase()\n", band);
@@ -3746,7 +3746,7 @@ static void _rtl8821ae_iqk_tx_fill_iqc(struct ieee80211_hw *hw,
                break;
        default:
                break;
-       };
+       }
 }
 
 static void _rtl8821ae_iqk_rx_fill_iqc(struct ieee80211_hw *hw,
@@ -3767,7 +3767,7 @@ static void _rtl8821ae_iqk_rx_fill_iqc(struct ieee80211_hw *hw,
                break;
        default:
                break;
-       };
+       }
 }
 
 #define cal_num 10
index 575c8f6d4009477dc6430b7eff91ab6d8a60e080..6ad3fcedab9b29fa92c9fb37eb65037a5b6d6f0f 100644 (file)
@@ -5177,10 +5177,11 @@ out:
 }
 
 static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_channel_switch *ch_switch)
 {
        struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
@@ -5190,14 +5191,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
        mutex_lock(&wl->mutex);
 
        if (unlikely(wl->state == WLCORE_STATE_OFF)) {
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
-                       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                               continue;
-
+               if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
                        ieee80211_chswitch_done(vif, false);
-               }
                goto out;
        } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
                goto out;
@@ -5208,11 +5203,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
                goto out;
 
        /* TODO: change mac80211 to pass vif as param */
-       wl12xx_for_each_wlvif_sta(wl, wlvif) {
-               unsigned long delay_usec;
 
-               if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                       continue;
+       if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
+               unsigned long delay_usec;
 
                ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
                if (ret)
@@ -5222,10 +5215,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
                /* indicate failure 5 seconds after channel switch time */
                delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
-                            ch_switch->count;
+                       ch_switch->count;
                ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
-                               usecs_to_jiffies(delay_usec) +
-                               msecs_to_jiffies(5000));
+                                            usecs_to_jiffies(delay_usec) +
+                                            msecs_to_jiffies(5000));
        }
 
 out_sleep:
index 065a87ace623b458a87bf177532a0dfafda67dbe..2d1c4ebd40f91d7b0f7e58a57d4d89f871456910 100644 (file)
@@ -451,9 +451,9 @@ csio_fcoe_alloc_vnp(struct csio_hw *hw, struct csio_lnode *ln)
 
        /* Process Mbox response of VNP command */
        rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
-       if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
+       if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
                csio_ln_err(ln, "FCOE VNP ALLOC cmd returned 0x%x!\n",
-                           FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
+                           FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)));
                ret = -EINVAL;
                goto out_free;
        }
@@ -526,9 +526,9 @@ csio_fcoe_free_vnp(struct csio_hw *hw, struct csio_lnode *ln)
 
        /* Process Mbox response of VNP command */
        rsp = (struct fw_fcoe_vnp_cmd *)(mbp->mb);
-       if (FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
+       if (FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)) != FW_SUCCESS) {
                csio_ln_err(ln, "FCOE VNP FREE cmd returned 0x%x!\n",
-                           FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16)));
+                           FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16)));
                ret = -EINVAL;
        }
 
index 0eaec474895788a6437e12c9907e053c9f74b048..5f06877aa7c42b94df01bea105657318c87fd179 100644 (file)
@@ -1370,9 +1370,9 @@ csio_hw_fw_config_file(struct csio_hw *hw,
        caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb);
        CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1);
        caps_cmd->op_to_write =
-               htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                     FW_CMD_REQUEST |
-                     FW_CMD_READ);
+               htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                     FW_CMD_REQUEST_F |
+                     FW_CMD_READ_F);
        caps_cmd->cfvalid_to_len16 =
                htonl(FW_CAPS_CONFIG_CMD_CFVALID |
                      FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
@@ -1407,9 +1407,9 @@ csio_hw_fw_config_file(struct csio_hw *hw,
         * And now tell the firmware to use the configuration we just loaded.
         */
        caps_cmd->op_to_write =
-               htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                     FW_CMD_REQUEST |
-                     FW_CMD_WRITE);
+               htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                     FW_CMD_REQUEST_F |
+                     FW_CMD_WRITE_F);
        caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd));
 
        if (csio_mb_issue(hw, mbp)) {
@@ -1678,7 +1678,7 @@ csio_get_fcoe_resinfo(struct csio_hw *hw)
        }
 
        rsp = (struct fw_fcoe_res_info_cmd *)(mbp->mb);
-       retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+       retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
        if (retval != FW_SUCCESS) {
                csio_err(hw, "FW_FCOE_RES_INFO_CMD failed with ret x%x\n",
                         retval);
index 89ecbac5478f6a14cfe60e77517f172062a0f9a8..95d831857640eecb28cab0dd2e67d7d94a028999 100644 (file)
@@ -307,12 +307,12 @@ csio_t4_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
         * MEM_EDC1 = 1
         * MEM_MC   = 2 -- T4
         */
-       edc_size  = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+       edc_size  = EDRAM0_SIZE_G(csio_rd_reg32(hw, MA_EDRAM0_BAR_A));
        if (mtype != MEM_MC1)
                memoffset = (mtype * (edc_size * 1024 * 1024));
        else {
-               mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
-                                                        MA_EXT_MEMORY_BAR));
+               mc_size = EXT_MEM_SIZE_G(csio_rd_reg32(hw,
+                                                      MA_EXT_MEMORY_BAR_A));
                memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
        }
 
@@ -383,11 +383,12 @@ static void
 csio_t4_dfs_create_ext_mem(struct csio_hw *hw)
 {
        u32 size;
-       int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
-       if (i & EXT_MEM_ENABLE) {
-               size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+       int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
+
+       if (i & EXT_MEM_ENABLE_F) {
+               size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR_A);
                csio_add_debugfs_mem(hw, "mc", MEM_MC,
-                                    EXT_MEM_SIZE_GET(size));
+                                    EXT_MEM_SIZE_G(size));
        }
 }
 
index 27745c170c24770360052457556047f2e261e2c0..66e180a58718b1c7e7b8c76f806aa0f38582c498 100644 (file)
@@ -298,12 +298,12 @@ csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
         * MEM_MC0  = 2 -- For T5
         * MEM_MC1  = 3 -- For T5
         */
-       edc_size  = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR));
+       edc_size  = EDRAM0_SIZE_G(csio_rd_reg32(hw, MA_EDRAM0_BAR_A));
        if (mtype != MEM_MC1)
                memoffset = (mtype * (edc_size * 1024 * 1024));
        else {
-               mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw,
-                                                        MA_EXT_MEMORY_BAR));
+               mc_size = EXT_MEM_SIZE_G(csio_rd_reg32(hw,
+                                                      MA_EXT_MEMORY_BAR_A));
                memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
        }
 
@@ -372,16 +372,17 @@ static void
 csio_t5_dfs_create_ext_mem(struct csio_hw *hw)
 {
        u32 size;
-       int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
-       if (i & EXT_MEM_ENABLE) {
-               size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR);
+       int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
+
+       if (i & EXT_MEM_ENABLE_F) {
+               size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR_A);
                csio_add_debugfs_mem(hw, "mc0", MEM_MC0,
-                                    EXT_MEM_SIZE_GET(size));
+                                    EXT_MEM_SIZE_G(size));
        }
-       if (i & EXT_MEM1_ENABLE) {
-               size = csio_rd_reg32(hw, MA_EXT_MEMORY1_BAR);
+       if (i & EXT_MEM1_ENABLE_F) {
+               size = csio_rd_reg32(hw, MA_EXT_MEMORY1_BAR_A);
                csio_add_debugfs_mem(hw, "mc1", MEM_MC1,
-                                    EXT_MEM_SIZE_GET(size));
+                                    EXT_MEM_SIZE_G(size));
        }
 }
 
index 17794add855c4c5097e7db2a7eaa561699a9ecb9..70e1eb6d964098f0245e1e21bf03e208fb55fc0b 100644 (file)
@@ -128,10 +128,10 @@ static int csio_setup_debugfs(struct csio_hw *hw)
        if (IS_ERR_OR_NULL(hw->debugfs_root))
                return -1;
 
-       i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE);
-       if (i & EDRAM0_ENABLE)
+       i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
+       if (i & EDRAM0_ENABLE_F)
                csio_add_debugfs_mem(hw, "edc0", MEM_EDC0, 5);
-       if (i & EDRAM1_ENABLE)
+       if (i & EDRAM1_ENABLE_F)
                csio_add_debugfs_mem(hw, "edc1", MEM_EDC1, 5);
 
        hw->chip_ops->chip_dfs_create_ext_mem(hw);
index ffe9be04dc39ab5a6133715ea66ab644d2fd8be0..48e45b1ea4e5875163aef320729f097f16d7e768 100644 (file)
@@ -603,7 +603,7 @@ csio_ln_vnp_read_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
        enum fw_retval retval;
        __be32 nport_id;
 
-       retval = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+       retval = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
        if (retval != FW_SUCCESS) {
                csio_err(hw, "FCOE VNP read cmd returned error:0x%x\n", retval);
                mempool_free(mbp, hw->mb_mempool);
@@ -770,7 +770,7 @@ csio_ln_read_fcf_cbfn(struct csio_hw *hw, struct csio_mb *mbp)
                                (struct fw_fcoe_fcf_cmd *)(mbp->mb);
        enum fw_retval retval;
 
-       retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+       retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
        if (retval != FW_SUCCESS) {
                csio_ln_err(ln, "FCOE FCF cmd failed with ret x%x\n",
                                retval);
@@ -1506,7 +1506,7 @@ csio_fcoe_fwevt_handler(struct csio_hw *hw, __u8 cpl_op, __be64 *cmd)
                }
        } else if (cpl_op == CPL_FW6_PLD) {
                wr = (struct fw_wr_hdr *) (cmd + 4);
-               if (FW_WR_OP_GET(be32_to_cpu(wr->hi))
+               if (FW_WR_OP_G(be32_to_cpu(wr->hi))
                        == FW_RDEV_WR) {
 
                        rdev_wr = (struct fw_rdev_wr *) (cmd + 4);
@@ -1574,17 +1574,17 @@ out_pld:
                        return;
                } else {
                        csio_warn(hw, "unexpected WR op(0x%x) recv\n",
-                               FW_WR_OP_GET(be32_to_cpu((wr->hi))));
+                                 FW_WR_OP_G(be32_to_cpu((wr->hi))));
                        CSIO_INC_STATS(hw, n_cpl_unexp);
                }
        } else if (cpl_op == CPL_FW6_MSG) {
                wr = (struct fw_wr_hdr *) (cmd);
-               if (FW_WR_OP_GET(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) {
+               if (FW_WR_OP_G(be32_to_cpu(wr->hi)) == FW_FCOE_ELS_CT_WR) {
                        csio_ln_mgmt_wr_handler(hw, wr,
                                        sizeof(struct fw_fcoe_els_ct_wr));
                } else {
                        csio_warn(hw, "unexpected WR op(0x%x) recv\n",
-                               FW_WR_OP_GET(be32_to_cpu((wr->hi))));
+                                 FW_WR_OP_G(be32_to_cpu((wr->hi))));
                        CSIO_INC_STATS(hw, n_cpl_unexp);
                }
        } else {
@@ -1668,12 +1668,12 @@ csio_ln_prep_ecwr(struct csio_ioreq *io_req, uint32_t wr_len,
        __be32 port_id;
 
        wr  = (struct fw_fcoe_els_ct_wr *)fw_wr;
-       wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_FCOE_ELS_CT_WR) |
+       wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_FCOE_ELS_CT_WR) |
                                     FW_FCOE_ELS_CT_WR_IMMDLEN(immd_len));
 
        wr_len =  DIV_ROUND_UP(wr_len, 16);
-       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(flow_id) |
-                                         FW_WR_LEN16(wr_len));
+       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(flow_id) |
+                                      FW_WR_LEN16_V(wr_len));
        wr->els_ct_type = sub_op;
        wr->ctl_pri = 0;
        wr->cp_en_class = 0;
index 15b6351425469db7b7fed1c9c0565641da462558..ffa84898760818713263c027aafd57b313103a5c 100644 (file)
@@ -59,7 +59,7 @@ csio_mb_fw_retval(struct csio_mb *mbp)
 
        hdr = (struct fw_cmd_hdr *)(mbp->mb);
 
-       return FW_CMD_RETVAL_GET(ntohl(hdr->lo));
+       return FW_CMD_RETVAL_G(ntohl(hdr->lo));
 }
 
 /*
@@ -81,9 +81,9 @@ csio_mb_hello(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
 
-       cmdp->op_to_write = htonl(FW_CMD_OP(FW_HELLO_CMD) |
-                                      FW_CMD_REQUEST | FW_CMD_WRITE);
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_HELLO_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->err_to_clearinit = htonl(
                FW_HELLO_CMD_MASTERDIS(master == CSIO_MASTER_CANT)      |
                FW_HELLO_CMD_MASTERFORCE(master == CSIO_MASTER_MUST)    |
@@ -112,7 +112,7 @@ csio_mb_process_hello_rsp(struct csio_hw *hw, struct csio_mb *mbp,
        struct fw_hello_cmd *rsp = (struct fw_hello_cmd *)(mbp->mb);
        uint32_t value;
 
-       *retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+       *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
 
        if (*retval == FW_SUCCESS) {
                hw->fwrev = ntohl(rsp->fwrev);
@@ -144,9 +144,9 @@ csio_mb_bye(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
 
-       cmdp->op_to_write = htonl(FW_CMD_OP(FW_BYE_CMD) |
-                                      FW_CMD_REQUEST | FW_CMD_WRITE);
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_BYE_CMD) |
+                                      FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 }
 
@@ -167,9 +167,9 @@ csio_mb_reset(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
 
-       cmdp->op_to_write = htonl(FW_CMD_OP(FW_RESET_CMD) |
-                                 FW_CMD_REQUEST | FW_CMD_WRITE);
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_RESET_CMD) |
+                                 FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->val = htonl(reset);
        cmdp->halt_pkd = htonl(halt);
 
@@ -202,12 +202,12 @@ csio_mb_params(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
 
-       cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD)                |
-                               FW_CMD_REQUEST                          |
-                               (wr ? FW_CMD_WRITE : FW_CMD_READ)       |
+       cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_PARAMS_CMD)              |
+                               FW_CMD_REQUEST_F                        |
+                               (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F)   |
                                FW_PARAMS_CMD_PFN(pf)                   |
                                FW_PARAMS_CMD_VFN(vf));
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
        /* Write Params */
        if (wr) {
@@ -245,7 +245,7 @@ csio_mb_process_read_params_rsp(struct csio_hw *hw, struct csio_mb *mbp,
        uint32_t i;
        __be32 *p = &rsp->param[0].val;
 
-       *retval = FW_CMD_RETVAL_GET(ntohl(rsp->retval_len16));
+       *retval = FW_CMD_RETVAL_G(ntohl(rsp->retval_len16));
 
        if (*retval == FW_SUCCESS)
                for (i = 0; i < nparams; i++, p += 2)
@@ -271,9 +271,9 @@ csio_mb_ldst(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo, int reg)
         * specified PCI-E Configuration Space register.
         */
        ldst_cmd->op_to_addrspace =
-                       htonl(FW_CMD_OP(FW_LDST_CMD)    |
-                       FW_CMD_REQUEST                  |
-                       FW_CMD_READ                     |
+                       htonl(FW_CMD_OP_V(FW_LDST_CMD)  |
+                       FW_CMD_REQUEST_F                        |
+                       FW_CMD_READ_F                   |
                        FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FUNC_PCIE));
        ldst_cmd->cycles_to_len16 = htonl(FW_LEN16(struct fw_ldst_cmd));
        ldst_cmd->u.pcie.select_naccess = FW_LDST_CMD_NACCESS(1);
@@ -306,10 +306,10 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, wr ? 0 : 1);
 
-       cmdp->op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
-                                 FW_CMD_REQUEST                |
-                                 (wr ? FW_CMD_WRITE : FW_CMD_READ));
-       cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+                                 FW_CMD_REQUEST_F              |
+                                 (wr ? FW_CMD_WRITE_F : FW_CMD_READ_F));
+       cmdp->cfvalid_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
        /* Read config */
        if (!wr)
@@ -351,21 +351,21 @@ csio_mb_port(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn,  1);
 
-       cmdp->op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD)               |
-                                  FW_CMD_REQUEST                       |
-                                  (wr ? FW_CMD_EXEC : FW_CMD_READ)     |
+       cmdp->op_to_portid = htonl(FW_CMD_OP_V(FW_PORT_CMD)             |
+                                  FW_CMD_REQUEST_F                     |
+                                  (wr ? FW_CMD_EXEC_F : FW_CMD_READ_F) |
                                   FW_PORT_CMD_PORTID(portid));
        if (!wr) {
                cmdp->action_to_len16 = htonl(
                        FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
-                       FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                       FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
                return;
        }
 
        /* Set port */
        cmdp->action_to_len16 = htonl(
                        FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
-                       FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                       FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
        if (fc & PAUSE_RX)
                lfc |= FW_PORT_CAP_FC_RX;
@@ -393,7 +393,7 @@ csio_mb_process_read_port_rsp(struct csio_hw *hw, struct csio_mb *mbp,
 {
        struct fw_port_cmd *rsp = (struct fw_port_cmd *)(mbp->mb);
 
-       *retval = FW_CMD_RETVAL_GET(ntohl(rsp->action_to_len16));
+       *retval = FW_CMD_RETVAL_G(ntohl(rsp->action_to_len16));
 
        if (*retval == FW_SUCCESS)
                *caps = ntohs(rsp->u.info.pcap);
@@ -415,9 +415,9 @@ csio_mb_initialize(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
 
        CSIO_INIT_MBP(mbp, cmdp, tmo, hw, cbfn, 1);
 
-       cmdp->op_to_write = htonl(FW_CMD_OP(FW_INITIALIZE_CMD)  |
-                                 FW_CMD_REQUEST | FW_CMD_WRITE);
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->op_to_write = htonl(FW_CMD_OP_V(FW_INITIALIZE_CMD)        |
+                                 FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 }
 
@@ -443,13 +443,13 @@ csio_mb_iq_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
 
-       cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD)            |
-                               FW_CMD_REQUEST | FW_CMD_EXEC    |
+       cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD)          |
+                               FW_CMD_REQUEST_F | FW_CMD_EXEC_F        |
                                FW_IQ_CMD_PFN(iq_params->pfn)   |
                                FW_IQ_CMD_VFN(iq_params->vfn));
 
        cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_ALLOC            |
-                               FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                               FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
        cmdp->type_to_iqandstindex = htonl(
                                FW_IQ_CMD_VIID(iq_params->viid) |
@@ -499,12 +499,12 @@ csio_mb_iq_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
        if (!cascaded_req)
                CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
 
-       cmdp->op_to_vfn |= htonl(FW_CMD_OP(FW_IQ_CMD)           |
-                               FW_CMD_REQUEST | FW_CMD_WRITE   |
+       cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_IQ_CMD)         |
+                               FW_CMD_REQUEST_F | FW_CMD_WRITE_F       |
                                FW_IQ_CMD_PFN(iq_params->pfn)   |
                                FW_IQ_CMD_VFN(iq_params->vfn));
        cmdp->alloc_to_len16 |= htonl(iq_start_stop |
-                               FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                               FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->iqid |= htons(iq_params->iqid);
        cmdp->fl0id |= htons(iq_params->fl0id);
        cmdp->fl1id |= htons(iq_params->fl1id);
@@ -588,7 +588,7 @@ csio_mb_iq_alloc_write_rsp(struct csio_hw *hw, struct csio_mb *mbp,
 {
        struct fw_iq_cmd *rsp = (struct fw_iq_cmd *)(mbp->mb);
 
-       *ret_val = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+       *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
        if (*ret_val == FW_SUCCESS) {
                iq_params->physiqid = ntohs(rsp->physiqid);
                iq_params->iqid = ntohs(rsp->iqid);
@@ -622,12 +622,12 @@ csio_mb_iq_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
 
-       cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD)            |
-                               FW_CMD_REQUEST | FW_CMD_EXEC    |
+       cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_IQ_CMD)          |
+                               FW_CMD_REQUEST_F | FW_CMD_EXEC_F        |
                                FW_IQ_CMD_PFN(iq_params->pfn)   |
                                FW_IQ_CMD_VFN(iq_params->vfn));
        cmdp->alloc_to_len16 = htonl(FW_IQ_CMD_FREE             |
-                               FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                               FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iq_params->type));
 
        cmdp->iqid = htons(iq_params->iqid);
@@ -657,12 +657,12 @@ csio_mb_eq_ofld_alloc(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
        struct fw_eq_ofld_cmd *cmdp = (struct fw_eq_ofld_cmd *)(mbp->mb);
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
-       cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD)               |
-                               FW_CMD_REQUEST | FW_CMD_EXEC            |
+       cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD)             |
+                               FW_CMD_REQUEST_F | FW_CMD_EXEC_F        |
                                FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
                                FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
        cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_ALLOC       |
-                               FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                               FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 } /* csio_mb_eq_ofld_alloc */
 
@@ -704,12 +704,12 @@ csio_mb_eq_ofld_write(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
        if (!cascaded_req)
                CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
 
-       cmdp->op_to_vfn |= htonl(FW_CMD_OP(FW_EQ_OFLD_CMD)      |
-                               FW_CMD_REQUEST | FW_CMD_WRITE   |
+       cmdp->op_to_vfn |= htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD)    |
+                               FW_CMD_REQUEST_F | FW_CMD_WRITE_F       |
                                FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
                                FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
        cmdp->alloc_to_len16 |= htonl(eq_start_stop             |
-                                     FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                                     FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
        cmdp->eqid_pkd |= htonl(FW_EQ_OFLD_CMD_EQID(eq_ofld_params->eqid));
 
@@ -773,7 +773,7 @@ csio_mb_eq_ofld_alloc_write_rsp(struct csio_hw *hw,
 {
        struct fw_eq_ofld_cmd *rsp = (struct fw_eq_ofld_cmd *)(mbp->mb);
 
-       *ret_val = FW_CMD_RETVAL_GET(ntohl(rsp->alloc_to_len16));
+       *ret_val = FW_CMD_RETVAL_G(ntohl(rsp->alloc_to_len16));
 
        if (*ret_val == FW_SUCCESS) {
                eq_ofld_params->eqid = FW_EQ_OFLD_CMD_EQID_GET(
@@ -807,12 +807,12 @@ csio_mb_eq_ofld_free(struct csio_hw *hw, struct csio_mb *mbp, void *priv,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, priv, cbfn, 1);
 
-       cmdp->op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD)       |
-                               FW_CMD_REQUEST | FW_CMD_EXEC    |
+       cmdp->op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD)     |
+                               FW_CMD_REQUEST_F | FW_CMD_EXEC_F        |
                                FW_EQ_OFLD_CMD_PFN(eq_ofld_params->pfn) |
                                FW_EQ_OFLD_CMD_VFN(eq_ofld_params->vfn));
        cmdp->alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE |
-                               FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                               FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eq_ofld_params->eqid));
 
 } /* csio_mb_eq_ofld_free */
@@ -840,15 +840,15 @@ csio_write_fcoe_link_cond_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
 
        cmdp->op_to_portid = htonl((
-                       FW_CMD_OP(FW_FCOE_LINK_CMD)             |
-                       FW_CMD_REQUEST                          |
-                       FW_CMD_WRITE                            |
+                       FW_CMD_OP_V(FW_FCOE_LINK_CMD)           |
+                       FW_CMD_REQUEST_F                                |
+                       FW_CMD_WRITE_F                          |
                        FW_FCOE_LINK_CMD_PORTID(port_id)));
        cmdp->sub_opcode_fcfi = htonl(
                        FW_FCOE_LINK_CMD_SUB_OPCODE(sub_opcode) |
                        FW_FCOE_LINK_CMD_FCFI(fcfi));
        cmdp->lstatus = link_status;
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 } /* csio_write_fcoe_link_cond_init_mb */
 
@@ -873,11 +873,11 @@ csio_fcoe_read_res_info_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
 
-       cmdp->op_to_read = htonl((FW_CMD_OP(FW_FCOE_RES_INFO_CMD)       |
-                                 FW_CMD_REQUEST                        |
-                                 FW_CMD_READ));
+       cmdp->op_to_read = htonl((FW_CMD_OP_V(FW_FCOE_RES_INFO_CMD)     |
+                                 FW_CMD_REQUEST_F                      |
+                                 FW_CMD_READ_F));
 
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 } /* csio_fcoe_read_res_info_init_mb */
 
@@ -908,13 +908,13 @@ csio_fcoe_vnp_alloc_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
 
-       cmdp->op_to_fcfi = htonl((FW_CMD_OP(FW_FCOE_VNP_CMD)            |
-                                 FW_CMD_REQUEST                        |
-                                 FW_CMD_EXEC                           |
+       cmdp->op_to_fcfi = htonl((FW_CMD_OP_V(FW_FCOE_VNP_CMD)          |
+                                 FW_CMD_REQUEST_F                      |
+                                 FW_CMD_EXEC_F                         |
                                  FW_FCOE_VNP_CMD_FCFI(fcfi)));
 
        cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_ALLOC              |
-                                    FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                                    FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
        cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
 
@@ -948,11 +948,11 @@ csio_fcoe_vnp_read_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
                        (struct fw_fcoe_vnp_cmd *)(mbp->mb);
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
-       cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_VNP_CMD)     |
-                                FW_CMD_REQUEST                 |
-                                FW_CMD_READ                    |
+       cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD)   |
+                                FW_CMD_REQUEST_F                       |
+                                FW_CMD_READ_F                  |
                                 FW_FCOE_VNP_CMD_FCFI(fcfi));
-       cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->alloc_to_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
 }
 
@@ -978,12 +978,12 @@ csio_fcoe_vnp_free_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
 
-       cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_VNP_CMD)     |
-                                FW_CMD_REQUEST                 |
-                                FW_CMD_EXEC                    |
+       cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_VNP_CMD)   |
+                                FW_CMD_REQUEST_F                       |
+                                FW_CMD_EXEC_F                  |
                                 FW_FCOE_VNP_CMD_FCFI(fcfi));
        cmdp->alloc_to_len16 = htonl(FW_FCOE_VNP_CMD_FREE       |
-                                    FW_CMD_LEN16(sizeof(*cmdp) / 16));
+                                    FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
        cmdp->gen_wwn_to_vnpi = htonl(FW_FCOE_VNP_CMD_VNPI(vnpi));
 }
 
@@ -1009,11 +1009,11 @@ csio_fcoe_read_fcf_init_mb(struct csio_lnode *ln, struct csio_mb *mbp,
 
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, ln, cbfn, 1);
 
-       cmdp->op_to_fcfi = htonl(FW_CMD_OP(FW_FCOE_FCF_CMD)     |
-                                FW_CMD_REQUEST                 |
-                                FW_CMD_READ                    |
+       cmdp->op_to_fcfi = htonl(FW_CMD_OP_V(FW_FCOE_FCF_CMD)   |
+                                FW_CMD_REQUEST_F                       |
+                                FW_CMD_READ_F                  |
                                 FW_FCOE_FCF_CMD_FCFI(fcfi));
-       cmdp->retval_len16 = htonl(FW_CMD_LEN16(sizeof(*cmdp) / 16));
+       cmdp->retval_len16 = htonl(FW_CMD_LEN16_V(sizeof(*cmdp) / 16));
 
 } /* csio_fcoe_read_fcf_init_mb */
 
@@ -1029,9 +1029,9 @@ csio_fcoe_read_portparams_init_mb(struct csio_hw *hw, struct csio_mb *mbp,
        CSIO_INIT_MBP(mbp, cmdp, mb_tmo, hw, cbfn, 1);
        mbp->mb_size = 64;
 
-       cmdp->op_to_flowid = htonl(FW_CMD_OP(FW_FCOE_STATS_CMD)         |
-                                  FW_CMD_REQUEST | FW_CMD_READ);
-       cmdp->free_to_len16 = htonl(FW_CMD_LEN16(CSIO_MAX_MB_SIZE/16));
+       cmdp->op_to_flowid = htonl(FW_CMD_OP_V(FW_FCOE_STATS_CMD)         |
+                                  FW_CMD_REQUEST_F | FW_CMD_READ_F);
+       cmdp->free_to_len16 = htonl(FW_CMD_LEN16_V(CSIO_MAX_MB_SIZE/16));
 
        cmdp->u.ctl.nstats_port = FW_FCOE_STATS_CMD_NSTATS(portparams->nstats) |
                                  FW_FCOE_STATS_CMD_PORT(portparams->portid);
@@ -1053,7 +1053,7 @@ csio_mb_process_portparams_rsp(struct csio_hw *hw,
        uint8_t *src;
        uint8_t *dst;
 
-       *retval = FW_CMD_RETVAL_GET(ntohl(rsp->free_to_len16));
+       *retval = FW_CMD_RETVAL_G(ntohl(rsp->free_to_len16));
 
        memset(&stats, 0, sizeof(struct fw_fcoe_port_stats));
 
@@ -1305,7 +1305,7 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
                        hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
                        fw_hdr = (struct fw_cmd_hdr *)&hdr;
 
-                       switch (FW_CMD_OP_GET(ntohl(fw_hdr->hi))) {
+                       switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
                        case FW_DEBUG_CMD:
                                csio_mb_debug_cmd_handler(hw);
                                continue;
@@ -1498,7 +1498,7 @@ csio_mb_isr_handler(struct csio_hw *hw)
                hdr = cpu_to_be64(csio_rd_reg64(hw, data_reg));
                fw_hdr = (struct fw_cmd_hdr *)&hdr;
 
-               switch (FW_CMD_OP_GET(ntohl(fw_hdr->hi))) {
+               switch (FW_CMD_OP_G(ntohl(fw_hdr->hi))) {
                case FW_DEBUG_CMD:
                        csio_mb_debug_cmd_handler(hw);
                        return -EINVAL;
@@ -1571,11 +1571,11 @@ csio_mb_tmo_handler(struct csio_hw *hw)
        fw_hdr = (struct fw_cmd_hdr *)(mbp->mb);
 
        csio_dbg(hw, "Mailbox num:%x op:0x%x timed out\n", hw->pfn,
-                   FW_CMD_OP_GET(ntohl(fw_hdr->hi)));
+                   FW_CMD_OP_G(ntohl(fw_hdr->hi)));
 
        mbm->mcurrent = NULL;
        CSIO_INC_STATS(mbm, n_tmo);
-       fw_hdr->lo = htonl(FW_CMD_RETVAL(FW_ETIMEDOUT));
+       fw_hdr->lo = htonl(FW_CMD_RETVAL_V(FW_ETIMEDOUT));
 
        return mbp;
 }
@@ -1624,10 +1624,10 @@ csio_mb_cancel_all(struct csio_hw *hw, struct list_head *cbfn_q)
                hdr = (struct fw_cmd_hdr *)(mbp->mb);
 
                csio_dbg(hw, "Cancelling pending mailbox num %x op:%x\n",
-                           hw->pfn, FW_CMD_OP_GET(ntohl(hdr->hi)));
+                           hw->pfn, FW_CMD_OP_G(ntohl(hdr->hi)));
 
                CSIO_INC_STATS(mbm, n_cancel);
-               hdr->lo = htonl(FW_CMD_RETVAL(FW_HOSTERROR));
+               hdr->lo = htonl(FW_CMD_RETVAL_V(FW_HOSTERROR));
        }
 }
 
index 86103c8475d8ed649b456b4e9f83b954a3b04e31..b37c69a2772a0daa0161285a097a3d8ab31174e7 100644 (file)
@@ -230,10 +230,10 @@ csio_scsi_init_cmd_wr(struct csio_ioreq *req, void *addr, uint32_t size)
        struct csio_dma_buf *dma_buf;
        uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
 
-       wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_CMD_WR) |
+       wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_CMD_WR) |
                                          FW_SCSI_CMD_WR_IMMDLEN(imm));
-       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
-                                           FW_WR_LEN16(
+       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+                                           FW_WR_LEN16_V(
                                                DIV_ROUND_UP(size, 16)));
 
        wr->cookie = (uintptr_t) req;
@@ -391,10 +391,10 @@ csio_scsi_init_read_wr(struct csio_ioreq *req, void *wrp, uint32_t size)
        uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
        struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
 
-       wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_READ_WR) |
+       wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_READ_WR) |
                                     FW_SCSI_READ_WR_IMMDLEN(imm));
-       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
-                                      FW_WR_LEN16(DIV_ROUND_UP(size, 16)));
+       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+                                      FW_WR_LEN16_V(DIV_ROUND_UP(size, 16)));
        wr->cookie = (uintptr_t)req;
        wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
        wr->tmo_val = (uint8_t)(req->tmo);
@@ -444,10 +444,10 @@ csio_scsi_init_write_wr(struct csio_ioreq *req, void *wrp, uint32_t size)
        uint8_t imm = csio_hw_to_scsim(hw)->proto_cmd_len;
        struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
 
-       wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_WRITE_WR) |
+       wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_WRITE_WR) |
                                     FW_SCSI_WRITE_WR_IMMDLEN(imm));
-       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
-                                      FW_WR_LEN16(DIV_ROUND_UP(size, 16)));
+       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+                                      FW_WR_LEN16_V(DIV_ROUND_UP(size, 16)));
        wr->cookie = (uintptr_t)req;
        wr->iqid = cpu_to_be16(csio_q_physiqid(hw, req->iq_idx));
        wr->tmo_val = (uint8_t)(req->tmo);
@@ -674,9 +674,9 @@ csio_scsi_init_abrt_cls_wr(struct csio_ioreq *req, void *addr, uint32_t size,
        struct csio_rnode *rn = req->rnode;
        struct fw_scsi_abrt_cls_wr *wr = (struct fw_scsi_abrt_cls_wr *)addr;
 
-       wr->op_immdlen = cpu_to_be32(FW_WR_OP(FW_SCSI_ABRT_CLS_WR));
-       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID(rn->flowid) |
-                                           FW_WR_LEN16(
+       wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_SCSI_ABRT_CLS_WR));
+       wr->flowid_len16 = cpu_to_be32(FW_WR_FLOWID_V(rn->flowid) |
+                                           FW_WR_LEN16_V(
                                                DIV_ROUND_UP(size, 16)));
 
        wr->cookie = (uintptr_t) req;
index 8d30e7ac1f5efb49941d27fbf36a7c7930200ed6..0c0dd9a658cc254d007560c2fe861860727c8743 100644 (file)
 
 /* WR status is at the same position as retval in a CMD header */
 #define csio_wr_status(_wr)            \
-               (FW_CMD_RETVAL_GET(ntohl(((struct fw_cmd_hdr *)(_wr))->lo)))
+               (FW_CMD_RETVAL_G(ntohl(((struct fw_cmd_hdr *)(_wr))->lo)))
 
 struct csio_hw;
 
index 3e0a0d315f72acc6b7088ded6d27465ff14b2840..ccacf09c2c16cefbe87b91eeeaca253ba155f092 100644 (file)
@@ -499,10 +499,10 @@ static inline void send_tx_flowc_wr(struct cxgbi_sock *csk)
        skb = alloc_wr(flowclen, 0, GFP_ATOMIC);
        flowc = (struct fw_flowc_wr *)skb->head;
        flowc->op_to_nparams =
-               htonl(FW_WR_OP(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS(8));
+               htonl(FW_WR_OP_V(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS_V(8));
        flowc->flowid_len16 =
-               htonl(FW_WR_LEN16(DIV_ROUND_UP(72, 16)) |
-                               FW_WR_FLOWID(csk->tid));
+               htonl(FW_WR_LEN16_V(DIV_ROUND_UP(72, 16)) |
+                               FW_WR_FLOWID_V(csk->tid));
        flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN;
        flowc->mnemval[0].val = htonl(csk->cdev->pfvf);
        flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH;
@@ -542,30 +542,31 @@ static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb,
 {
        struct fw_ofld_tx_data_wr *req;
        unsigned int submode = cxgbi_skcb_ulp_mode(skb) & 3;
-       unsigned int wr_ulp_mode = 0;
+       unsigned int wr_ulp_mode = 0, val;
 
        req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, sizeof(*req));
 
        if (is_ofld_imm(skb)) {
-               req->op_to_immdlen = htonl(FW_WR_OP(FW_OFLD_TX_DATA_WR) |
-                                       FW_WR_COMPL(1) |
-                                       FW_WR_IMMDLEN(dlen));
-               req->flowid_len16 = htonl(FW_WR_FLOWID(csk->tid) |
-                                               FW_WR_LEN16(credits));
+               req->op_to_immdlen = htonl(FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+                                       FW_WR_COMPL_F |
+                                       FW_WR_IMMDLEN_V(dlen));
+               req->flowid_len16 = htonl(FW_WR_FLOWID_V(csk->tid) |
+                                               FW_WR_LEN16_V(credits));
        } else {
                req->op_to_immdlen =
-                       cpu_to_be32(FW_WR_OP(FW_OFLD_TX_DATA_WR) |
-                                       FW_WR_COMPL(1) |
-                                       FW_WR_IMMDLEN(0));
+                       cpu_to_be32(FW_WR_OP_V(FW_OFLD_TX_DATA_WR) |
+                                       FW_WR_COMPL_F |
+                                       FW_WR_IMMDLEN_V(0));
                req->flowid_len16 =
-                       cpu_to_be32(FW_WR_FLOWID(csk->tid) |
-                                       FW_WR_LEN16(credits));
+                       cpu_to_be32(FW_WR_FLOWID_V(csk->tid) |
+                                       FW_WR_LEN16_V(credits));
        }
        if (submode)
-               wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE(ULP2_MODE_ISCSI) |
-                               FW_OFLD_TX_DATA_WR_ULPSUBMODE(submode);
+               wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE_V(ULP2_MODE_ISCSI) |
+                               FW_OFLD_TX_DATA_WR_ULPSUBMODE_V(submode);
+       val = skb_peek(&csk->write_queue) ? 0 : 1;
        req->tunnel_to_proxy = htonl(wr_ulp_mode |
-                FW_OFLD_TX_DATA_WR_SHOVE(skb_peek(&csk->write_queue) ? 0 : 1));
+                                    FW_OFLD_TX_DATA_WR_SHOVE_V(val));
        req->plen = htonl(len);
        if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT))
                cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT);
index bd6953af0a0396f715cb2622e5a4e6ca904b5228..3d26955da724bcab0ea5e872076752607a51f79b 100644 (file)
@@ -2856,8 +2856,10 @@ static int cfg80211_rtw_add_station(struct wiphy *wiphy,
 }
 
 static int cfg80211_rtw_del_station(struct wiphy *wiphy,
-                                   struct net_device *ndev, const u8 *mac)
+                                   struct net_device *ndev,
+                                   struct station_del_parameters *params)
 {
+       const u8 *mac = params->mac;
        int ret = 0;
        struct list_head *phead, *plist, *ptmp;
        u8 updated = 0;
index a495a959e8a754939b9c8c9d9bd748a73f54f587..33eb274cd0e6b61be2b000e3e30c82f2ea6c7f1e 100644 (file)
@@ -31,8 +31,11 @@ struct ath9k_platform_data {
        u32 gpio_mask;
        u32 gpio_val;
 
+       bool endian_check;
        bool is_clk_25mhz;
        bool tx_gain_buffalo;
+       bool disable_2ghz;
+       bool disable_5ghz;
 
        int (*get_mac_revision)(void);
        int (*external_reset)(void);
index b1be39c76931b5084ee4bebab2c237021d31e109..f65b5446d983d6097ebe7805f7c3d8d6122fe6b8 100644 (file)
@@ -1274,7 +1274,7 @@ struct ieee80211_ht_cap {
 #define                IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT   2
 
 /*
- * Maximum length of AMPDU that the STA can receive.
+ * Maximum length of AMPDU that the STA can receive in high-throughput (HT).
  * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
  */
 enum ieee80211_max_ampdu_length_exp {
@@ -1284,6 +1284,21 @@ enum ieee80211_max_ampdu_length_exp {
        IEEE80211_HT_MAX_AMPDU_64K = 3
 };
 
+/*
+ * Maximum length of AMPDU that the STA can receive in VHT.
+ * Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+ */
+enum ieee80211_vht_max_ampdu_length_exp {
+       IEEE80211_VHT_MAX_AMPDU_8K = 0,
+       IEEE80211_VHT_MAX_AMPDU_16K = 1,
+       IEEE80211_VHT_MAX_AMPDU_32K = 2,
+       IEEE80211_VHT_MAX_AMPDU_64K = 3,
+       IEEE80211_VHT_MAX_AMPDU_128K = 4,
+       IEEE80211_VHT_MAX_AMPDU_256K = 5,
+       IEEE80211_VHT_MAX_AMPDU_512K = 6,
+       IEEE80211_VHT_MAX_AMPDU_1024K = 7
+};
+
 #define IEEE80211_HT_MAX_AMPDU_FACTOR 13
 
 /* Minimum MPDU start spacing */
@@ -1998,6 +2013,11 @@ enum ieee80211_tdls_actioncode {
        WLAN_TDLS_DISCOVERY_REQUEST = 10,
 };
 
+/* Extended Channel Switching capability to be set in the 1st byte of
+ * the @WLAN_EID_EXT_CAPABILITY information element
+ */
+#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING   BIT(2)
+
 /* Interworking capabilities are set in 7th bit of 4th byte of the
  * @WLAN_EID_EXT_CAPABILITY information element
  */
similarity index 94%
rename from include/net/ieee802154.h
rename to include/linux/ieee802154.h
index 0aa7122e8f15390b4b6158429a245057fdd23e5d..6e50a2a1d4851f77163b0dacf4623b17909363bd 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  */
 
-#ifndef NET_IEEE802154_H
-#define NET_IEEE802154_H
+#ifndef LINUX_IEEE802154_H
+#define LINUX_IEEE802154_H
+
+#include <linux/types.h>
 
 #define IEEE802154_MTU                 127
+#define IEEE802154_MIN_PSDU_LEN                5
 
 #define IEEE802154_FC_TYPE_BEACON      0x0     /* Frame is beacon */
 #define        IEEE802154_FC_TYPE_DATA         0x1     /* Frame is data */
@@ -189,7 +188,13 @@ enum {
        IEEE802154_SCAN_IN_PROGRESS = 0xfc,
 };
 
+/**
+ * ieee802154_is_valid_psdu_len - check if psdu len is valid
+ * @len: psdu len with (MHR + payload + MFR)
+ */
+static inline bool ieee802154_is_valid_psdu_len(const u8 len)
+{
+       return (len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU);
+}
 
-#endif
-
-
+#endif /* LINUX_IEEE802154_H */
index 5cc5eac47d1b815b0ce9c8e4db62e915b4839d58..3d9bff00f24a3f1decdca003210c3ab294173b43 100644 (file)
@@ -497,6 +497,7 @@ struct mlx4_caps {
        u16                     hca_core_clock;
        u64                     phys_port_id[MLX4_MAX_PORTS + 1];
        int                     tunnel_offload_mode;
+       u8                      rx_checksum_flags_port[MLX4_MAX_PORTS + 1];
 };
 
 struct mlx4_buf_list {
index 90ac95900a11c65222950105b76384c050afcf48..888d5513fa4ac8a46b5247103982bf1d34e4633d 100644 (file)
@@ -314,6 +314,7 @@ struct napi_struct {
        struct net_device       *dev;
        struct sk_buff          *gro_list;
        struct sk_buff          *skb;
+       struct hrtimer          timer;
        struct list_head        dev_list;
        struct hlist_node       napi_hash_node;
        unsigned int            napi_id;
@@ -443,14 +444,19 @@ static inline bool napi_reschedule(struct napi_struct *napi)
        return false;
 }
 
+void __napi_complete(struct napi_struct *n);
+void napi_complete_done(struct napi_struct *n, int work_done);
 /**
  *     napi_complete - NAPI processing complete
  *     @n: napi context
  *
  * Mark NAPI processing as complete.
+ * Consider using napi_complete_done() instead.
  */
-void __napi_complete(struct napi_struct *n);
-void napi_complete(struct napi_struct *n);
+static inline void napi_complete(struct napi_struct *n)
+{
+       return napi_complete_done(n, 0);
+}
 
 /**
  *     napi_by_id - lookup a NAPI by napi_id
@@ -485,14 +491,7 @@ void napi_hash_del(struct napi_struct *napi);
  * Stop NAPI from being scheduled on this context.
  * Waits till any outstanding processing completes.
  */
-static inline void napi_disable(struct napi_struct *n)
-{
-       might_sleep();
-       set_bit(NAPI_STATE_DISABLE, &n->state);
-       while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
-               msleep(1);
-       clear_bit(NAPI_STATE_DISABLE, &n->state);
-}
+void napi_disable(struct napi_struct *n);
 
 /**
  *     napi_enable - enable NAPI scheduling
@@ -1603,6 +1602,7 @@ struct net_device {
 
 #endif
 
+       unsigned long           gro_flush_timeout;
        rx_handler_func_t __rcu *rx_handler;
        void __rcu              *rx_handler_data;
 
index 20163b9a0eae70cfdfba688bab5dc08eed5fcfdb..167342c2ce6b05d29d05dcc529023eac5cadb9ec 100644 (file)
  * 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-1301 USA.
- *
  */
 
 #ifndef NL802154_H
index d184df1d0d412360a6de44024b9559afc9d13a07..dc03d77ad23bb2588869251a67c5a7143c874b21 100644 (file)
@@ -372,12 +372,12 @@ lowpan_uncompress_size(const struct sk_buff *skb, u16 *dgram_offset)
        return skb->len + uncomp_header - ret;
 }
 
-typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
-
-int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
-               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
-               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
-               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
+int
+lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
+                        const u8 *saddr, const u8 saddr_type,
+                        const u8 saddr_len, const u8 *daddr,
+                        const u8 daddr_type, const u8 daddr_len,
+                        u8 iphc0, u8 iphc1);
 int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
                        unsigned short type, const void *_daddr,
                        const void *_saddr, unsigned int len);
index 085940f7eeec0e56d5f95226034b32b906bc3380..7d38e2ffd2566b3077b1e6450a00ef4b771d9839 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
index 37ff1aef0845e9c2ef0335b95c87b93b65e9c025..b8685a77a15e0efc1dc55cd460bd06fd94dcc149 100644 (file)
@@ -398,6 +398,8 @@ struct hci_conn {
        __u16           le_conn_interval;
        __u16           le_conn_latency;
        __u16           le_supv_timeout;
+       __u8            le_adv_data[HCI_MAX_AD_LENGTH];
+       __u8            le_adv_data_len;
        __s8            rssi;
        __s8            tx_power;
        __s8            max_tx_power;
@@ -553,6 +555,7 @@ enum {
        HCI_CONN_STK_ENCRYPT,
        HCI_CONN_AUTH_INITIATOR,
        HCI_CONN_DROP,
+       HCI_CONN_PARAM_REMOVAL_PEND,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -1310,9 +1313,8 @@ int mgmt_update_adv_data(struct hci_dev *hdev);
 void mgmt_discoverable_timeout(struct hci_dev *hdev);
 void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
                       bool persistent);
-void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                          u8 addr_type, u32 flags, u8 *name, u8 name_len,
-                          u8 *dev_class);
+void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
+                          u32 flags, u8 *name, u8 name_len);
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
                              u8 link_type, u8 addr_type, u8 reason,
                              bool mgmt_connected);
similarity index 99%
rename from drivers/net/bonding/bond_3ad.h
rename to include/net/bond_3ad.h
index c5f14ac63f3ee7b2b8b41b60939c6002ad9e7c1f..e01d903633eff269866dda0f23e65f60614adf11 100644 (file)
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef __BOND_3AD_H__
-#define __BOND_3AD_H__
+#ifndef _NET_BOND_3AD_H
+#define _NET_BOND_3AD_H
 
 #include <asm/byteorder.h>
 #include <linux/skbuff.h>
@@ -279,5 +279,5 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
                         struct slave *slave);
 int bond_3ad_set_carrier(struct bonding *bond);
 void bond_3ad_update_lacp_rate(struct bonding *bond);
-#endif /* __BOND_3AD_H__ */
+#endif /* _NET_BOND_3AD_H */
 
similarity index 98%
rename from drivers/net/bonding/bond_alb.h
rename to include/net/bond_alb.h
index 1ad473b4ade5b50f7a0dc734f55c60627f65a5cd..313a8d3b306963dd0a2c40fead61391d7ff5954c 100644 (file)
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef __BOND_ALB_H__
-#define __BOND_ALB_H__
+#ifndef _NET_BOND_ALB_H
+#define _NET_BOND_ALB_H
 
 #include <linux/if_ether.h>
 
@@ -177,5 +177,5 @@ int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
 void bond_alb_monitor(struct work_struct *);
 int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
 void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
-#endif /* __BOND_ALB_H__ */
+#endif /* _NET_BOND_ALB_H */
 
similarity index 97%
rename from drivers/net/bonding/bond_options.h
rename to include/net/bond_options.h
index 17ded5b291761ca9e85e2fa6c82514a4613815b5..ea6546d2c946aa1caeabcb071a368e07cf89c3a3 100644 (file)
@@ -8,8 +8,8 @@
  * (at your option) any later version.
  */
 
-#ifndef _BOND_OPTIONS_H
-#define _BOND_OPTIONS_H
+#ifndef _NET_BOND_OPTIONS_H
+#define _NET_BOND_OPTIONS_H
 
 #define BOND_OPT_MAX_NAMELEN 32
 #define BOND_OPT_VALID(opt) ((opt) < BOND_OPT_LAST)
@@ -127,4 +127,4 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
 
 void bond_option_arp_ip_targets_clear(struct bonding *bond);
 
-#endif /* _BOND_OPTIONS_H */
+#endif /* _NET_BOND_OPTIONS_H */
similarity index 99%
rename from drivers/net/bonding/bonding.h
rename to include/net/bonding.h
index bfb0b51c081a27fbbbe64deda058f70860aac49d..983a94b86b954c90548df20fe6f574efb6359c70 100644 (file)
@@ -12,8 +12,8 @@
  *
  */
 
-#ifndef _LINUX_BONDING_H
-#define _LINUX_BONDING_H
+#ifndef _NET_BONDING_H
+#define _NET_BONDING_H
 
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
@@ -26,9 +26,9 @@
 #include <linux/reciprocal_div.h>
 #include <linux/if_link.h>
 
-#include "bond_3ad.h"
-#include "bond_alb.h"
-#include "bond_options.h"
+#include <net/bond_3ad.h>
+#include <net/bond_alb.h>
+#include <net/bond_options.h>
 
 #define DRV_VERSION    "3.7.1"
 #define DRV_RELDATE    "April 27, 2011"
@@ -651,4 +651,4 @@ static inline void bond_tx_drop(struct net_device *dev, struct sk_buff *skb)
        dev_kfree_skb_any(skb);
 }
 
-#endif /* _LINUX_BONDING_H */
+#endif /* _NET_BONDING_H */
index a2ddcf2398fdadf43bcb5ccc12891aba20f0c946..5c3acd07acd982be8b38097d91e1908003aea66c 100644 (file)
@@ -319,9 +319,12 @@ struct ieee80211_supported_band {
 /**
  * struct vif_params - describes virtual interface parameters
  * @use_4addr: use 4-address frames
- * @macaddr: address to use for this virtual interface. This will only
- *     be used for non-netdevice interfaces. If this parameter is set
- *     to zero address the driver may determine the address as needed.
+ * @macaddr: address to use for this virtual interface.
+ *     If this parameter is set to zero address the driver may
+ *     determine the address as needed.
+ *     This feature is only fully supported by drivers that enable the
+ *     %NL80211_FEATURE_MAC_ON_CREATE flag.  Others may support creating
+ **    only p2p devices with specified MAC.
  */
 struct vif_params {
        int use_4addr;
@@ -798,6 +801,22 @@ struct station_parameters {
        bool opmode_notif_used;
 };
 
+/**
+ * struct station_del_parameters - station deletion parameters
+ *
+ * Used to delete a station entry (or all stations).
+ *
+ * @mac: MAC address of the station to remove or NULL to remove all stations
+ * @subtype: Management frame subtype to use for indicating removal
+ *     (10 = Disassociation, 12 = Deauthentication)
+ * @reason_code: Reason code for the Disassociation/Deauthentication frame
+ */
+struct station_del_parameters {
+       const u8 *mac;
+       u8 subtype;
+       u16 reason_code;
+};
+
 /**
  * enum cfg80211_station_type - the type of station being modified
  * @CFG80211_STA_AP_CLIENT: client of an AP interface
@@ -1339,6 +1358,16 @@ struct mesh_setup {
        u32 basic_rates;
 };
 
+/**
+ * struct ocb_setup - 802.11p OCB mode setup configuration
+ * @chandef: defines the channel to use
+ *
+ * These parameters are fixed when connecting to the network
+ */
+struct ocb_setup {
+       struct cfg80211_chan_def chandef;
+};
+
 /**
  * struct ieee80211_txq_params - TX queue parameters
  * @ac: AC identifier
@@ -2132,7 +2161,7 @@ struct cfg80211_qos_map {
  * @stop_ap: Stop being an AP, including stopping beaconing.
  *
  * @add_station: Add a new station.
- * @del_station: Remove a station; @mac may be NULL to remove all stations.
+ * @del_station: Remove a station
  * @change_station: Modify a given station. Note that flags changes are not much
  *     validated in cfg80211, in particular the auth/assoc/authorized flags
  *     might come to the driver in invalid combinations -- make sure to check
@@ -2146,6 +2175,8 @@ struct cfg80211_qos_map {
  * @change_mpath: change a given mesh path
  * @get_mpath: get a mesh path for the given parameters
  * @dump_mpath: dump mesh path callback -- resume dump at index @idx
+ * @get_mpp: get a mesh proxy path for the given parameters
+ * @dump_mpp: dump mesh proxy path callback -- resume dump at index @idx
  * @join_mesh: join the mesh network with the specified parameters
  *     (invoked with the wireless_dev mutex held)
  * @leave_mesh: leave the current mesh network
@@ -2331,6 +2362,11 @@ struct cfg80211_qos_map {
  *     with the peer followed by immediate teardown when the addition is later
  *     rejected)
  * @del_tx_ts: remove an existing TX TS
+ *
+ * @join_ocb: join the OCB network with the specified parameters
+ *     (invoked with the wireless_dev mutex held)
+ * @leave_ocb: leave the current OCB network
+ *     (invoked with the wireless_dev mutex held)
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2376,7 +2412,7 @@ struct cfg80211_ops {
                               const u8 *mac,
                               struct station_parameters *params);
        int     (*del_station)(struct wiphy *wiphy, struct net_device *dev,
-                              const u8 *mac);
+                              struct station_del_parameters *params);
        int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
                                  const u8 *mac,
                                  struct station_parameters *params);
@@ -2396,6 +2432,11 @@ struct cfg80211_ops {
        int     (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
                              int idx, u8 *dst, u8 *next_hop,
                              struct mpath_info *pinfo);
+       int     (*get_mpp)(struct wiphy *wiphy, struct net_device *dev,
+                          u8 *dst, u8 *mpp, struct mpath_info *pinfo);
+       int     (*dump_mpp)(struct wiphy *wiphy, struct net_device *dev,
+                           int idx, u8 *dst, u8 *mpp,
+                           struct mpath_info *pinfo);
        int     (*get_mesh_config)(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct mesh_config *conf);
@@ -2407,6 +2448,10 @@ struct cfg80211_ops {
                             const struct mesh_setup *setup);
        int     (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);
 
+       int     (*join_ocb)(struct wiphy *wiphy, struct net_device *dev,
+                           struct ocb_setup *setup);
+       int     (*leave_ocb)(struct wiphy *wiphy, struct net_device *dev);
+
        int     (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
                              struct bss_parameters *params);
 
@@ -2623,13 +2668,9 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_SUPPORTS_5_10_MHZ: Device supports 5 MHz and 10 MHz channels.
  * @WIPHY_FLAG_HAS_CHANNEL_SWITCH: Device supports channel switch in
  *     beaconing mode (AP, IBSS, Mesh, ...).
- * @WIPHY_FLAG_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
- *     TSPEC sessions (TID aka TSID 0-7) with the NL80211_CMD_ADD_TX_TS
- *     command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
- *     needs to be able to handle Block-Ack agreements and other things.
  */
 enum wiphy_flags {
-       WIPHY_FLAG_SUPPORTS_WMM_ADMISSION       = BIT(0),
+       /* use hole at 0 */
        /* use hole at 1 */
        /* use hole at 2 */
        WIPHY_FLAG_NETNS_OK                     = BIT(3),
@@ -3165,6 +3206,23 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
        return dev_name(&wiphy->dev);
 }
 
+/**
+ * wiphy_new_nm - create a new wiphy for use with cfg80211
+ *
+ * @ops: The configuration operations for this device
+ * @sizeof_priv: The size of the private area to allocate
+ * @requested_name: Request a particular name.
+ *     NULL is valid value, and means use the default phy%d naming.
+ *
+ * Create a new wiphy and associate the given operations with it.
+ * @sizeof_priv bytes are allocated for private use.
+ *
+ * Return: A pointer to the new wiphy. This pointer must be
+ * assigned to each netdev's ieee80211_ptr for proper operation.
+ */
+struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+                          const char *requested_name);
+
 /**
  * wiphy_new - create a new wiphy for use with cfg80211
  *
@@ -3177,7 +3235,11 @@ static inline const char *wiphy_name(const struct wiphy *wiphy)
  * Return: A pointer to the new wiphy. This pointer must be
  * assigned to each netdev's ieee80211_ptr for proper operation.
  */
-struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv);
+static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
+                                     int sizeof_priv)
+{
+       return wiphy_new_nm(ops, sizeof_priv, NULL);
+}
 
 /**
  * wiphy_register - register a wiphy with cfg80211
similarity index 77%
rename from include/net/wpan-phy.h
rename to include/net/cfg802154.h
index 10ab0fc6d4f79a8a608d0ce642aae294636dcecc..440b9bece9c64926307071c441eaef15a96843c6 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  */
 
-#ifndef WPAN_PHY_H
-#define WPAN_PHY_H
+#ifndef __NET_CFG802154_H
+#define __NET_CFG802154_H
 
 #include <linux/netdevice.h>
 #include <linux/mutex.h>
@@ -61,15 +57,7 @@ struct wpan_phy {
                                        const char *name, int type);
        void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
 
-       int (*set_txpower)(struct wpan_phy *phy, int db);
-       int (*set_lbt)(struct wpan_phy *phy, bool on);
-       int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode);
-       int (*set_cca_ed_level)(struct wpan_phy *phy, int level);
-       int (*set_csma_params)(struct wpan_phy *phy, u8 min_be, u8 max_be,
-                              u8 retries);
-       int (*set_frame_retries)(struct wpan_phy *phy, s8 retries);
-
-       char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
+       char priv[0] __aligned(NETDEV_ALIGN);
 };
 
 #define to_phy(_dev)   container_of(_dev, struct wpan_phy, dev)
@@ -79,6 +67,7 @@ static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev)
 {
        phy->dev.parent = dev;
 }
+
 int wpan_phy_register(struct wpan_phy *phy);
 void wpan_phy_unregister(struct wpan_phy *phy);
 void wpan_phy_free(struct wpan_phy *phy);
@@ -102,4 +91,5 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy)
 {
        return dev_name(&phy->dev);
 }
-#endif
+
+#endif /* __NET_CFG802154_H */
index 3b53c8e405e48143f667c20850db1666c402d8fa..5e62d758eea538a2f47abadad3259133a6d21e88 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
 #ifndef IEEE802154_NETDEVICE_H
 #define IEEE802154_NETDEVICE_H
 
-#include <net/ieee802154.h>
 #include <net/af_ieee802154.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <linux/ieee802154.h>
 
 struct ieee802154_sechdr {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
index 0ad1f47d2dc77ee472656fbbfce1afb08d1e3a6f..5f203a6a5e7eb8bbab27627143b1430f3eb37d9c 100644 (file)
@@ -263,6 +263,7 @@ struct ieee80211_vif_chanctx_switch {
  * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed,
  *     note that this is only called when it changes after the channel
  *     context had been assigned.
+ * @BSS_CHANGED_OCB: OCB join status changed
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -287,6 +288,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_P2P_PS              = 1<<19,
        BSS_CHANGED_BEACON_INFO         = 1<<20,
        BSS_CHANGED_BANDWIDTH           = 1<<21,
+       BSS_CHANGED_OCB                 = 1<<22,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -739,7 +741,8 @@ struct ieee80211_tx_info {
                        u8 ampdu_ack_len;
                        u8 ampdu_len;
                        u8 antenna;
-                       void *status_driver_data[21 / sizeof(void *)];
+                       u16 tx_time;
+                       void *status_driver_data[19 / sizeof(void *)];
                } status;
                struct {
                        struct ieee80211_tx_rate driver_rates[
@@ -1117,6 +1120,8 @@ struct ieee80211_conf {
  *     Function (TSF) timer when the frame containing the channel switch
  *     announcement was received. This is simply the rx.mactime parameter
  *     the driver passed into mac80211.
+ * @device_timestamp: arbitrary timestamp for the device, this is the
+ *     rx.device_timestamp parameter the driver passed to mac80211.
  * @block_tx: Indicates whether transmission must be blocked before the
  *     scheduled channel switch, as indicated by the AP.
  * @chandef: the new channel to switch to
@@ -1124,6 +1129,7 @@ struct ieee80211_conf {
  */
 struct ieee80211_channel_switch {
        u64 timestamp;
+       u32 device_timestamp;
        bool block_tx;
        struct cfg80211_chan_def chandef;
        u8 count;
@@ -1423,6 +1429,8 @@ struct ieee80211_sta_rates {
  * @smps_mode: current SMPS mode (off, static or dynamic)
  * @rates: rate control selection table
  * @tdls: indicates whether the STA is a TDLS peer
+ * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
+ *     valid if the STA is a TDLS peer in the first place.
  */
 struct ieee80211_sta {
        u32 supp_rates[IEEE80211_NUM_BANDS];
@@ -1438,6 +1446,7 @@ struct ieee80211_sta {
        enum ieee80211_smps_mode smps_mode;
        struct ieee80211_sta_rates __rcu *rates;
        bool tdls;
+       bool tdls_initiator;
 
        /* must be last */
        u8 drv_priv[0] __aligned(sizeof(void *));
@@ -1576,6 +1585,10 @@ struct ieee80211_tx_control {
  *     a virtual monitor interface when monitor interfaces are the only
  *     active interfaces.
  *
+ * @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
+ *     be created.  It is expected user-space will create vifs as
+ *     desired (and thus have them named as desired).
+ *
  * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
  *     queue mapping in order to use different queues (not just one per AC)
  *     for different virtual interfaces. See the doc section on HW queue
@@ -1622,7 +1635,8 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_DYNAMIC_PS                = 1<<12,
        IEEE80211_HW_MFP_CAPABLE                        = 1<<13,
        IEEE80211_HW_WANT_MONITOR_VIF                   = 1<<14,
-       /* free slots */
+       IEEE80211_HW_NO_AUTO_VIF                        = 1<<15,
+       /* free slot */
        IEEE80211_HW_SUPPORTS_UAPSD                     = 1<<17,
        IEEE80211_HW_REPORTS_TX_ACK_STATUS              = 1<<18,
        IEEE80211_HW_CONNECTION_MONITOR                 = 1<<19,
@@ -2374,6 +2388,22 @@ enum ieee80211_roc_type {
        IEEE80211_ROC_TYPE_MGMT_TX,
 };
 
+/**
+ * enum ieee80211_reconfig_complete_type - reconfig type
+ *
+ * This enum is used by the reconfig_complete() callback to indicate what
+ * reconfiguration type was completed.
+ *
+ * @IEEE80211_RECONFIG_TYPE_RESTART: hw restart type
+ *     (also due to resume() callback returning 1)
+ * @IEEE80211_RECONFIG_TYPE_SUSPEND: suspend type (regardless
+ *     of wowlan configuration)
+ */
+enum ieee80211_reconfig_type {
+       IEEE80211_RECONFIG_TYPE_RESTART,
+       IEEE80211_RECONFIG_TYPE_SUSPEND,
+};
+
 /**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
@@ -2809,11 +2839,11 @@ enum ieee80211_roc_type {
  *     disabled/enabled via @bss_info_changed.
  * @stop_ap: Stop operation on the AP interface.
  *
- * @restart_complete: Called after a call to ieee80211_restart_hw(), when the
- *     reconfiguration has completed. This can help the driver implement the
- *     reconfiguration step. Also called when reconfiguring because the
- *     driver's resume function returned 1, as this is just like an "inline"
- *     hardware restart. This callback may sleep.
+ * @reconfig_complete: Called after a call to ieee80211_restart_hw() and
+ *     during resume, when the reconfiguration has completed.
+ *     This can help the driver implement the reconfiguration step (and
+ *     indicate mac80211 is ready to receive frames).
+ *     This callback may sleep.
  *
  * @ipv6_addr_change: IPv6 address assignment on the given interface changed.
  *     Currently, this is only called for managed or P2P client interfaces.
@@ -2829,6 +2859,13 @@ enum ieee80211_roc_type {
  *     transmitted and then call ieee80211_csa_finish().
  *     If the CSA count starts as zero or 1, this function will not be called,
  *     since there won't be any time to beacon before the switch anyway.
+ * @pre_channel_switch: This is an optional callback that is called
+ *     before a channel switch procedure is started (ie. when a STA
+ *     gets a CSA or an userspace initiated channel-switch), allowing
+ *     the driver to prepare for the channel switch.
+ * @post_channel_switch: This is an optional callback that is called
+ *     after a channel switch procedure is completed, allowing the
+ *     driver to go back to a normal configuration.
  *
  * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
  *     information in bss_conf is set up and the beacon can be retrieved. A
@@ -2838,6 +2875,9 @@ enum ieee80211_roc_type {
  * @get_expected_throughput: extract the expected throughput towards the
  *     specified station. The returned value is expressed in Kbps. It returns 0
  *     if the RC algorithm does not have proper data to provide.
+ *
+ * @get_txpower: get current maximum tx power (in dBm) based on configuration
+ *     and hardware limits.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -2959,6 +2999,7 @@ struct ieee80211_ops {
        void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                      u32 queues, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
                               struct ieee80211_channel_switch *ch_switch);
        int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
        int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
@@ -3025,7 +3066,8 @@ struct ieee80211_ops {
                                  int n_vifs,
                                  enum ieee80211_chanctx_switch_mode mode);
 
-       void (*restart_complete)(struct ieee80211_hw *hw);
+       void (*reconfig_complete)(struct ieee80211_hw *hw,
+                                 enum ieee80211_reconfig_type reconfig_type);
 
 #if IS_ENABLED(CONFIG_IPV6)
        void (*ipv6_addr_change)(struct ieee80211_hw *hw,
@@ -3035,14 +3077,42 @@ struct ieee80211_ops {
        void (*channel_switch_beacon)(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      struct cfg80211_chan_def *chandef);
+       int (*pre_channel_switch)(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_channel_switch *ch_switch);
+
+       int (*post_channel_switch)(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif);
 
        int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        u32 (*get_expected_throughput)(struct ieee80211_sta *sta);
+       int (*get_txpower)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          int *dbm);
 };
 
 /**
- * ieee80211_alloc_hw -  Allocate a new hardware device
+ * ieee80211_alloc_hw_nm - Allocate a new hardware device
+ *
+ * This must be called once for each hardware device. The returned pointer
+ * must be used to refer to this device when calling other functions.
+ * mac80211 allocates a private data area for the driver pointed to by
+ * @priv in &struct ieee80211_hw, the size of this area is given as
+ * @priv_data_len.
+ *
+ * @priv_data_len: length of private data
+ * @ops: callbacks for this device
+ * @requested_name: Requested name for this device.
+ *     NULL is valid value, and means use the default naming (phy%d)
+ *
+ * Return: A pointer to the new hardware device, or %NULL on error.
+ */
+struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
+                                          const struct ieee80211_ops *ops,
+                                          const char *requested_name);
+
+/**
+ * ieee80211_alloc_hw - Allocate a new hardware device
  *
  * This must be called once for each hardware device. The returned pointer
  * must be used to refer to this device when calling other functions.
@@ -3055,8 +3125,12 @@ struct ieee80211_ops {
  *
  * Return: A pointer to the new hardware device, or %NULL on error.
  */
+static inline
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
-                                       const struct ieee80211_ops *ops);
+                                       const struct ieee80211_ops *ops)
+{
+       return ieee80211_alloc_hw_nm(priv_data_len, ops, NULL);
+}
 
 /**
  * ieee80211_register_hw - Register hardware device
@@ -4171,6 +4245,22 @@ void ieee80211_iterate_active_interfaces_rtnl(struct ieee80211_hw *hw,
                                                struct ieee80211_vif *vif),
                                              void *data);
 
+/**
+ * ieee80211_iterate_stations_atomic - iterate stations
+ *
+ * This function iterates over all stations associated with a given
+ * hardware that are currently uploaded to the driver and calls the callback
+ * function for them.
+ * This function requires the iterator callback function to be atomic,
+ *
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iterator: the iterator function to call, cannot sleep
+ * @data: first argument of the iterator function
+ */
+void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
+                                      void (*iterator)(void *data,
+                                               struct ieee80211_sta *sta),
+                                      void *data);
 /**
  * ieee80211_queue_work - add work onto the mac80211 workqueue
  *
@@ -4888,4 +4978,32 @@ void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf);
 void ieee80211_tdls_oper_request(struct ieee80211_vif *vif, const u8 *peer,
                                 enum nl80211_tdls_operation oper,
                                 u16 reason_code, gfp_t gfp);
+
+/**
+ * ieee80211_ie_split - split an IE buffer according to ordering
+ *
+ * @ies: the IE buffer
+ * @ielen: the length of the IE buffer
+ * @ids: an array with element IDs that are allowed before
+ *     the split
+ * @n_ids: the size of the element ID array
+ * @offset: offset where to start splitting in the buffer
+ *
+ * This function splits an IE buffer by updating the @offset
+ * variable to point to the location where the buffer should be
+ * split.
+ *
+ * It assumes that the given IE buffer is well-formed, this
+ * has to be guaranteed by the caller!
+ *
+ * It also assumes that the IEs in the buffer are ordered
+ * correctly, if not the result of using this function will not
+ * be ordered correctly either, i.e. it does no reordering.
+ *
+ * The function returns the offset where the next part of the
+ * buffer starts, which may be @ielen if the entire (remainder)
+ * of the buffer should be used.
+ */
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+                         const u8 *ids, int n_ids, size_t offset);
 #endif /* MAC80211_H */
index 2e67cdd19cdc6d34c322056c52dc72fedf2c416b..8f1de6844cb0f09c01cdc0dc1ef646b697d892e7 100644 (file)
@@ -12,9 +12,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-1301 USA.
  */
 #ifndef NET_MAC802154_H
 #define NET_MAC802154_H
  */
 
 /* indicates that the Short Address changed */
-#define IEEE802515_AFILT_SADDR_CHANGED         0x00000001
+#define IEEE802154_AFILT_SADDR_CHANGED         0x00000001
 /* indicates that the IEEE Address changed */
-#define IEEE802515_AFILT_IEEEADDR_CHANGED      0x00000002
+#define IEEE802154_AFILT_IEEEADDR_CHANGED      0x00000002
 /* indicates that the PAN ID changed */
-#define IEEE802515_AFILT_PANID_CHANGED         0x00000004
+#define IEEE802154_AFILT_PANID_CHANGED         0x00000004
 /* indicates that PAN Coordinator status changed */
-#define        IEEE802515_AFILT_PANC_CHANGED           0x00000008
+#define IEEE802154_AFILT_PANC_CHANGED          0x00000008
 
 struct ieee802154_hw_addr_filt {
        __le16  pan_id;         /* Each independent PAN selects a unique
@@ -55,7 +52,7 @@ struct ieee802154_hw_addr_filt {
        u8      pan_coord;
 };
 
-struct ieee802154_dev {
+struct ieee802154_hw {
        /* filled by the driver */
        int     extra_tx_headroom;
        u32     flags;
@@ -76,28 +73,43 @@ struct ieee802154_dev {
  * however, so you are advised to review these flags carefully.
  */
 
-/* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */
-#define        IEEE802154_HW_OMIT_CKSUM        0x00000001
+/* Indicates that xmitter will add FCS on it's own. */
+#define IEEE802154_HW_TX_OMIT_CKSUM    0x00000001
 /* Indicates that receiver will autorespond with ACK frames. */
-#define        IEEE802154_HW_AACK              0x00000002
+#define IEEE802154_HW_AACK             0x00000002
 /* Indicates that transceiver will support transmit power setting. */
-#define        IEEE802154_HW_TXPOWER           0x00000004
+#define IEEE802154_HW_TXPOWER          0x00000004
 /* Indicates that transceiver will support listen before transmit. */
-#define        IEEE802154_HW_LBT               0x00000008
+#define IEEE802154_HW_LBT              0x00000008
 /* Indicates that transceiver will support cca mode setting. */
-#define        IEEE802154_HW_CCA_MODE          0x00000010
+#define IEEE802154_HW_CCA_MODE         0x00000010
 /* Indicates that transceiver will support cca ed level setting. */
-#define        IEEE802154_HW_CCA_ED_LEVEL      0x00000020
+#define IEEE802154_HW_CCA_ED_LEVEL     0x00000020
 /* Indicates that transceiver will support csma (max_be, min_be, csma retries)
  * settings. */
-#define        IEEE802154_HW_CSMA_PARAMS       0x00000040
+#define IEEE802154_HW_CSMA_PARAMS      0x00000040
 /* Indicates that transceiver will support ARET frame retries setting. */
-#define        IEEE802154_HW_FRAME_RETRIES     0x00000080
+#define IEEE802154_HW_FRAME_RETRIES    0x00000080
+/* Indicates that transceiver will support hardware address filter setting. */
+#define IEEE802154_HW_AFILT            0x00000100
+/* Indicates that transceiver will support promiscuous mode setting. */
+#define IEEE802154_HW_PROMISCUOUS      0x00000200
+/* Indicates that receiver omits FCS. */
+#define IEEE802154_HW_RX_OMIT_CKSUM    0x00000400
+/* Indicates that receiver will not filter frames with bad checksum. */
+#define IEEE802154_HW_RX_DROP_BAD_CKSUM        0x00000800
+
+/* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */
+#define IEEE802154_HW_OMIT_CKSUM       (IEEE802154_HW_TX_OMIT_CKSUM | \
+                                        IEEE802154_HW_RX_OMIT_CKSUM)
 
 /* This groups the most common CSMA support fields into one. */
 #define IEEE802154_HW_CSMA             (IEEE802154_HW_CCA_MODE | \
                                         IEEE802154_HW_CCA_ED_LEVEL | \
-                                        IEEE802154_HW_CSMA_PARAMS | \
+                                        IEEE802154_HW_CSMA_PARAMS)
+
+/* This groups the most common ARET support fields into one. */
+#define IEEE802154_HW_ARET             (IEEE802154_HW_CSMA | \
                                         IEEE802154_HW_FRAME_RETRIES)
 
 /* struct ieee802154_ops - callbacks from mac802154 to the driver
@@ -112,12 +124,24 @@ struct ieee802154_dev {
  * stop:  Handler that 802.15.4 module calls for device cleanup.
  *       This function is called after the last interface is removed.
  *
- * xmit:  Handler that 802.15.4 module calls for each transmitted frame.
+ * xmit_sync:
+ *       Handler that 802.15.4 module calls for each transmitted frame.
+ *       skb cntains the buffer starting from the IEEE 802.15.4 header.
+ *       The low-level driver should send the frame based on available
+ *       configuration. This is called by a workqueue and useful for
+ *       synchronous 802.15.4 drivers.
+ *       This function should return zero or negative errno.
+ *
+ *       WARNING:
+ *       This will be deprecated soon. We don't accept synced xmit callbacks
+ *       drivers anymore.
+ *
+ * xmit_async:
+ *       Handler that 802.15.4 module calls for each transmitted frame.
  *       skb cntains the buffer starting from the IEEE 802.15.4 header.
  *       The low-level driver should send the frame based on available
  *       configuration.
- *       This function should return zero or negative errno. Called with
- *       pib_lock held.
+ *       This function should return zero or negative errno.
  *
  * ed:    Handler that 802.15.4 module calls for Energy Detection.
  *       This function should place the value for detected energy
@@ -159,40 +183,50 @@ struct ieee802154_dev {
  * set_frame_retries
  *       Sets the retransmission attempt limit. Called with pib_lock held.
  *       Returns either zero, or negative errno.
+ *
+ * set_promiscuous_mode
+ *       Enables or disable promiscuous mode.
  */
 struct ieee802154_ops {
        struct module   *owner;
-       int             (*start)(struct ieee802154_dev *dev);
-       void            (*stop)(struct ieee802154_dev *dev);
-       int             (*xmit)(struct ieee802154_dev *dev,
-                               struct sk_buff *skb);
-       int             (*ed)(struct ieee802154_dev *dev, u8 *level);
-       int             (*set_channel)(struct ieee802154_dev *dev,
-                                      int page,
-                                      int channel);
-       int             (*set_hw_addr_filt)(struct ieee802154_dev *dev,
-                                         struct ieee802154_hw_addr_filt *filt,
+       int             (*start)(struct ieee802154_hw *hw);
+       void            (*stop)(struct ieee802154_hw *hw);
+       int             (*xmit_sync)(struct ieee802154_hw *hw,
+                                    struct sk_buff *skb);
+       int             (*xmit_async)(struct ieee802154_hw *hw,
+                                     struct sk_buff *skb);
+       int             (*ed)(struct ieee802154_hw *hw, u8 *level);
+       int             (*set_channel)(struct ieee802154_hw *hw, u8 page,
+                                      u8 channel);
+       int             (*set_hw_addr_filt)(struct ieee802154_hw *hw,
+                                           struct ieee802154_hw_addr_filt *filt,
                                            unsigned long changed);
-       int             (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr);
-       int             (*set_txpower)(struct ieee802154_dev *dev, int db);
-       int             (*set_lbt)(struct ieee802154_dev *dev, bool on);
-       int             (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
-       int             (*set_cca_ed_level)(struct ieee802154_dev *dev,
+       int             (*set_txpower)(struct ieee802154_hw *hw, int db);
+       int             (*set_lbt)(struct ieee802154_hw *hw, bool on);
+       int             (*set_cca_mode)(struct ieee802154_hw *hw, u8 mode);
+       int             (*set_cca_ed_level)(struct ieee802154_hw *hw,
                                            s32 level);
-       int             (*set_csma_params)(struct ieee802154_dev *dev,
+       int             (*set_csma_params)(struct ieee802154_hw *hw,
                                           u8 min_be, u8 max_be, u8 retries);
-       int             (*set_frame_retries)(struct ieee802154_dev *dev,
+       int             (*set_frame_retries)(struct ieee802154_hw *hw,
                                             s8 retries);
+       int             (*set_promiscuous_mode)(struct ieee802154_hw *hw,
+                                               const bool on);
 };
 
-/* Basic interface to register ieee802154 device */
-struct ieee802154_dev *
-ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops);
-void ieee802154_free_device(struct ieee802154_dev *dev);
-int ieee802154_register_device(struct ieee802154_dev *dev);
-void ieee802154_unregister_device(struct ieee802154_dev *dev);
+/* Basic interface to register ieee802154 hwice */
+struct ieee802154_hw *
+ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops);
+void ieee802154_free_hw(struct ieee802154_hw *hw);
+int ieee802154_register_hw(struct ieee802154_hw *hw);
+void ieee802154_unregister_hw(struct ieee802154_hw *hw);
 
-void ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb,
+void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb);
+void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb,
                           u8 lqi);
 
+void ieee802154_wake_queue(struct ieee802154_hw *hw);
+void ieee802154_stop_queue(struct ieee802154_hw *hw);
+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb);
+
 #endif /* NET_MAC802154_H */
index b23548e0409848530b1c7f94fb805601c46e583c..b5cdea29d9d970d8091f44bbc7eee4008e31291e 100644 (file)
  * 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-1301 USA.
- *
  */
 
 #ifndef IEEE802154_NL_H
index 6767d75ecb17693eb59a99b8218da4319854ccc0..7789b59c0c400eb99f65d1f0e03cd9773664cf93 100644 (file)
@@ -273,6 +273,7 @@ struct cg_proto;
   *    @sk_rcvtimeo: %SO_RCVTIMEO setting
   *    @sk_sndtimeo: %SO_SNDTIMEO setting
   *    @sk_rxhash: flow hash received from netif layer
+  *    @sk_incoming_cpu: record cpu processing incoming packets
   *    @sk_txhash: computed flow hash for use on transmit
   *    @sk_filter: socket filtering instructions
   *    @sk_protinfo: private area, net family specific, when not using slab
@@ -350,6 +351,12 @@ struct sock {
 #ifdef CONFIG_RPS
        __u32                   sk_rxhash;
 #endif
+       u16                     sk_incoming_cpu;
+       /* 16bit hole
+        * Warned : sk_incoming_cpu can be set from softirq,
+        * Do not use this hole without fully understanding possible issues.
+        */
+
        __u32                   sk_txhash;
 #ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int            sk_napi_id;
@@ -833,6 +840,11 @@ static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
        return sk->sk_backlog_rcv(sk, skb);
 }
 
+static inline void sk_incoming_cpu_update(struct sock *sk)
+{
+       sk->sk_incoming_cpu = raw_smp_processor_id();
+}
+
 static inline void sock_rps_record_flow_hash(__u32 hash)
 {
 #ifdef CONFIG_RPS
index ea0796bdcf88404ef0f127eb6e64ba00c16ea856..f541ccefd4acbeb4ad757be9dbf4b67f204bf21d 100644 (file)
@@ -82,4 +82,6 @@
 
 #define SO_BPF_EXTENSIONS      48
 
+#define SO_INCOMING_CPU                49
+
 #endif /* __ASM_GENERIC_SOCKET_H */
index 4b28dc07bcb1fd3ea358b12c68432bf82fb27b23..9b3025e4377a6e1ab9663341ee433afbd2f1d1c6 100644 (file)
  *     the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
  *     or, if no MAC address given, all stations, on the interface identified
- *     by %NL80211_ATTR_IFINDEX.
+ *     by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ *     %NL80211_ATTR_REASON_CODE can optionally be used to specify which type
+ *     of disconnection indication should be sent to the station
+ *     (Deauthentication or Disassociation frame and reason code for that
+ *     frame).
  *
  * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
  *     destination %NL80211_ATTR_MAC on the interface identified by
  *     before removing a station entry entirely, or before disassociating
  *     or similar, cleanup will happen in the driver/device in this case.
  *
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ *     destination %NL80211_ATTR_MAC on the interface identified by
+ *     %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and
+ *     bandwidth of a channel must be given.
+ * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
+ *     network is determined by the network interface.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -912,6 +925,11 @@ enum nl80211_commands {
        NL80211_CMD_ADD_TX_TS,
        NL80211_CMD_DEL_TX_TS,
 
+       NL80211_CMD_GET_MPP,
+
+       NL80211_CMD_JOIN_OCB,
+       NL80211_CMD_LEAVE_OCB,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -2064,6 +2082,8 @@ enum nl80211_attrs {
  *     and therefore can't be created in the normal ways, use the
  *     %NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
  *     commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ *     This mode corresponds to the MIB variable dot11OCBActivated=true
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
  * @NUM_NL80211_IFTYPES: number of defined interface types
  *
@@ -2083,6 +2103,7 @@ enum nl80211_iftype {
        NL80211_IFTYPE_P2P_CLIENT,
        NL80211_IFTYPE_P2P_GO,
        NL80211_IFTYPE_P2P_DEVICE,
+       NL80211_IFTYPE_OCB,
 
        /* keep last */
        NUM_NL80211_IFTYPES,
@@ -4042,6 +4063,13 @@ enum nl80211_ap_sme_features {
  *     multiplexing powersave, ie. can turn off all but one chain
  *     and then wake the rest up as required after, for example,
  *     rts/cts handshake.
+ * @NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
+ *     TSPEC sessions (TID aka TSID 0-7) with the %NL80211_CMD_ADD_TX_TS
+ *     command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
+ *     needs to be able to handle Block-Ack agreements and other things.
+ * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring
+ *     the vif's MAC address upon creation.
+ *     See 'macaddr' field in the vif_params (cfg80211.h).
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -4070,6 +4098,8 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_ACKTO_ESTIMATION                = 1 << 23,
        NL80211_FEATURE_STATIC_SMPS                     = 1 << 24,
        NL80211_FEATURE_DYNAMIC_SMPS                    = 1 << 25,
+       NL80211_FEATURE_SUPPORTS_WMM_ADMISSION          = 1 << 26,
+       NL80211_FEATURE_MAC_ON_CREATE                   = 1 << 27,
 };
 
 /**
index eb0f1a554d7ba19c95b73315374c34757ba3ec97..9c9b8b4480cd4608d783318b7dbac4c060db210a 100644 (file)
@@ -235,6 +235,7 @@ enum {
 #define RTPROT_NTK     15      /* Netsukuku */
 #define RTPROT_DHCP    16      /* DHCP client */
 #define RTPROT_MROUTED 17      /* Multicast daemon */
+#define RTPROT_BABEL   42      /* Babel daemon */
 
 /* rtm_scope
 
index 142eef55c9e2d92c180786d9919ded72536d94ba..73a7065f0c6bc8243091deb20f723b2cd1f9847e 100644 (file)
@@ -171,37 +171,6 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb,
        return 0;
 }
 
-static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
-                      struct net_device *dev, skb_delivery_cb deliver_skb)
-{
-       struct sk_buff *new;
-       int stat;
-
-       new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
-                             GFP_ATOMIC);
-       kfree_skb(skb);
-
-       if (!new)
-               return -ENOMEM;
-
-       skb_push(new, sizeof(struct ipv6hdr));
-       skb_reset_network_header(new);
-       skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
-
-       new->protocol = htons(ETH_P_IPV6);
-       new->pkt_type = PACKET_HOST;
-       new->dev = dev;
-
-       raw_dump_table(__func__, "raw skb data dump before receiving",
-                      new->data, new->len);
-
-       stat = deliver_skb(new, dev);
-
-       kfree_skb(new);
-
-       return stat;
-}
-
 /* Uncompress function for multicast destination address,
  * when M bit is set.
  */
@@ -332,10 +301,12 @@ err:
 /* TTL uncompression values */
 static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
 
-int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
-                       const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
-                       const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
-                       u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb)
+int
+lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
+                        const u8 *saddr, const u8 saddr_type,
+                        const u8 saddr_len, const u8 *daddr,
+                        const u8 daddr_type, const u8 daddr_len,
+                        u8 iphc0, u8 iphc1)
 {
        struct ipv6hdr hdr = {};
        u8 tmp, num_context = 0;
@@ -460,7 +431,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
        /* UDP data uncompression */
        if (iphc0 & LOWPAN_IPHC_NH_C) {
                struct udphdr uh;
-               struct sk_buff *new;
+               const int needed = sizeof(struct udphdr) + sizeof(hdr);
 
                if (uncompress_udp_header(skb, &uh))
                        goto drop;
@@ -468,14 +439,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
                /* replace the compressed UDP head by the uncompressed UDP
                 * header
                 */
-               new = skb_copy_expand(skb, sizeof(struct udphdr),
-                                     skb_tailroom(skb), GFP_ATOMIC);
-               kfree_skb(skb);
-
-               if (!new)
-                       return -ENOMEM;
-
-               skb = new;
+               err = skb_cow(skb, needed);
+               if (unlikely(err)) {
+                       kfree_skb(skb);
+                       return err;
+               }
 
                skb_push(skb, sizeof(struct udphdr));
                skb_reset_transport_header(skb);
@@ -485,6 +453,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
                               (u8 *)&uh, sizeof(uh));
 
                hdr.nexthdr = UIP_PROTO_UDP;
+       } else {
+               err = skb_cow(skb, sizeof(hdr));
+               if (unlikely(err)) {
+                       kfree_skb(skb);
+                       return err;
+               }
        }
 
        hdr.payload_len = htons(skb->len);
@@ -497,15 +471,18 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
                hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
                hdr.hop_limit, &hdr.daddr);
 
-       raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
+       skb_push(skb, sizeof(hdr));
+       skb_reset_network_header(skb);
+       skb_copy_to_linear_data(skb, &hdr, sizeof(hdr));
 
-       return skb_deliver(skb, &hdr, dev, deliver_skb);
+       raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
 
+       return 0;
 drop:
        kfree_skb(skb);
        return -EINVAL;
 }
-EXPORT_SYMBOL_GPL(lowpan_process_data);
+EXPORT_SYMBOL_GPL(lowpan_header_decompress);
 
 static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
                                  const struct in6_addr *ipaddr,
index c2e0d14433df6678011e07b00045c68e5cf7f998..eef298d1745200b8fe8bccbb5445e03148e70e53 100644 (file)
@@ -53,7 +53,7 @@ struct skb_cb {
  * The list contains struct lowpan_dev elements.
  */
 static LIST_HEAD(bt_6lowpan_devices);
-static DEFINE_RWLOCK(devices_lock);
+static DEFINE_SPINLOCK(devices_lock);
 
 /* If psm is set to 0 (default value), then 6lowpan is disabled.
  * Other values are used to indicate a Protocol Service Multiplexer
@@ -67,6 +67,7 @@ static struct l2cap_chan *listen_chan;
 
 struct lowpan_peer {
        struct list_head list;
+       struct rcu_head rcu;
        struct l2cap_chan *chan;
 
        /* peer addresses in various formats */
@@ -86,6 +87,13 @@ struct lowpan_dev {
        struct delayed_work notify_peers;
 };
 
+static inline void peer_free(struct rcu_head *head)
+{
+       struct lowpan_peer *e = container_of(head, struct lowpan_peer, rcu);
+
+       kfree(e);
+}
+
 static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
 {
        return netdev_priv(netdev);
@@ -93,13 +101,14 @@ static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
 
 static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
 {
-       list_add(&peer->list, &dev->peers);
+       list_add_rcu(&peer->list, &dev->peers);
        atomic_inc(&dev->peer_count);
 }
 
 static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
 {
-       list_del(&peer->list);
+       list_del_rcu(&peer->list);
+       call_rcu(&peer->rcu, peer_free);
 
        module_put(THIS_MODULE);
 
@@ -114,31 +123,37 @@ static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
 static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
                                                 bdaddr_t *ba, __u8 type)
 {
-       struct lowpan_peer *peer, *tmp;
+       struct lowpan_peer *peer;
 
        BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
               ba, type);
 
-       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(peer, &dev->peers, list) {
                BT_DBG("dst addr %pMR dst type %d",
                       &peer->chan->dst, peer->chan->dst_type);
 
                if (bacmp(&peer->chan->dst, ba))
                        continue;
 
-               if (type == peer->chan->dst_type)
+               if (type == peer->chan->dst_type) {
+                       rcu_read_unlock();
                        return peer;
+               }
        }
 
+       rcu_read_unlock();
+
        return NULL;
 }
 
-static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev,
-                                                  struct l2cap_chan *chan)
+static inline struct lowpan_peer *__peer_lookup_chan(struct lowpan_dev *dev,
+                                                    struct l2cap_chan *chan)
 {
-       struct lowpan_peer *peer, *tmp;
+       struct lowpan_peer *peer;
 
-       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+       list_for_each_entry_rcu(peer, &dev->peers, list) {
                if (peer->chan == chan)
                        return peer;
        }
@@ -146,12 +161,12 @@ static inline struct lowpan_peer *peer_lookup_chan(struct lowpan_dev *dev,
        return NULL;
 }
 
-static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
-                                                  struct l2cap_conn *conn)
+static inline struct lowpan_peer *__peer_lookup_conn(struct lowpan_dev *dev,
+                                                    struct l2cap_conn *conn)
 {
-       struct lowpan_peer *peer, *tmp;
+       struct lowpan_peer *peer;
 
-       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+       list_for_each_entry_rcu(peer, &dev->peers, list) {
                if (peer->chan->conn == conn)
                        return peer;
        }
@@ -163,7 +178,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
                                                  struct in6_addr *daddr,
                                                  struct sk_buff *skb)
 {
-       struct lowpan_peer *peer, *tmp;
+       struct lowpan_peer *peer;
        struct in6_addr *nexthop;
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
        int count = atomic_read(&dev->peer_count);
@@ -174,9 +189,13 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
         * send the packet. If only one peer exists, then we can send the
         * packet right away.
         */
-       if (count == 1)
-               return list_first_entry(&dev->peers, struct lowpan_peer,
-                                       list);
+       if (count == 1) {
+               rcu_read_lock();
+               peer = list_first_or_null_rcu(&dev->peers, struct lowpan_peer,
+                                             list);
+               rcu_read_unlock();
+               return peer;
+       }
 
        if (!rt) {
                nexthop = &lowpan_cb(skb)->gw;
@@ -195,53 +214,57 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
 
        BT_DBG("gw %pI6c", nexthop);
 
-       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(peer, &dev->peers, list) {
                BT_DBG("dst addr %pMR dst type %d ip %pI6c",
                       &peer->chan->dst, peer->chan->dst_type,
                       &peer->peer_addr);
 
-               if (!ipv6_addr_cmp(&peer->peer_addr, nexthop))
+               if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) {
+                       rcu_read_unlock();
                        return peer;
+               }
        }
 
+       rcu_read_unlock();
+
        return NULL;
 }
 
 static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
 {
-       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *entry;
        struct lowpan_peer *peer = NULL;
-       unsigned long flags;
 
-       read_lock_irqsave(&devices_lock, flags);
+       rcu_read_lock();
 
-       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
-               peer = peer_lookup_conn(entry, conn);
+       list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+               peer = __peer_lookup_conn(entry, conn);
                if (peer)
                        break;
        }
 
-       read_unlock_irqrestore(&devices_lock, flags);
+       rcu_read_unlock();
 
        return peer;
 }
 
 static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
 {
-       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *entry;
        struct lowpan_dev *dev = NULL;
-       unsigned long flags;
 
-       read_lock_irqsave(&devices_lock, flags);
+       rcu_read_lock();
 
-       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+       list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
                if (conn->hcon->hdev == entry->hdev) {
                        dev = entry;
                        break;
                }
        }
 
-       read_unlock_irqrestore(&devices_lock, flags);
+       rcu_read_unlock();
 
        return dev;
 }
@@ -249,35 +272,27 @@ static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
 static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
 {
        struct sk_buff *skb_cp;
-       int ret;
 
        skb_cp = skb_copy(skb, GFP_ATOMIC);
        if (!skb_cp)
-               return -ENOMEM;
-
-       ret = netif_rx(skb_cp);
-       if (ret < 0) {
-               BT_DBG("receive skb %d", ret);
                return NET_RX_DROP;
-       }
 
-       return ret;
+       return netif_rx(skb_cp);
 }
 
-static int process_data(struct sk_buff *skb, struct net_device *netdev,
-                       struct l2cap_chan *chan)
+static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
+                          struct l2cap_chan *chan)
 {
        const u8 *saddr, *daddr;
        u8 iphc0, iphc1;
        struct lowpan_dev *dev;
        struct lowpan_peer *peer;
-       unsigned long flags;
 
        dev = lowpan_dev(netdev);
 
-       read_lock_irqsave(&devices_lock, flags);
-       peer = peer_lookup_chan(dev, chan);
-       read_unlock_irqrestore(&devices_lock, flags);
+       rcu_read_lock();
+       peer = __peer_lookup_chan(dev, chan);
+       rcu_read_unlock();
        if (!peer)
                goto drop;
 
@@ -294,10 +309,11 @@ static int process_data(struct sk_buff *skb, struct net_device *netdev,
        if (lowpan_fetch_skb_u8(skb, &iphc1))
                goto drop;
 
-       return lowpan_process_data(skb, netdev,
-                                  saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
-                                  daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
-                                  iphc0, iphc1, give_skb_to_upper);
+       return lowpan_header_decompress(skb, netdev,
+                                       saddr, IEEE802154_ADDR_LONG,
+                                       EUI64_ADDR_LEN, daddr,
+                                       IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+                                       iphc0, iphc1);
 
 drop:
        kfree_skb(skb);
@@ -316,6 +332,10 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
        if (dev->type != ARPHRD_6LOWPAN)
                goto drop;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto drop;
+
        /* check that it's our buffer */
        if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
                /* Copy the packet so that the IPv6 header is
@@ -340,8 +360,8 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
                dev->stats.rx_bytes += skb->len;
                dev->stats.rx_packets++;
 
-               kfree_skb(local_skb);
-               kfree_skb(skb);
+               consume_skb(local_skb);
+               consume_skb(skb);
        } else {
                switch (skb->data[0] & 0xe0) {
                case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
@@ -349,14 +369,25 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
                        if (!local_skb)
                                goto drop;
 
-                       ret = process_data(local_skb, dev, chan);
-                       if (ret != NET_RX_SUCCESS)
+                       ret = iphc_decompress(local_skb, dev, chan);
+                       if (ret < 0)
                                goto drop;
 
+                       local_skb->protocol = htons(ETH_P_IPV6);
+                       local_skb->pkt_type = PACKET_HOST;
+                       local_skb->dev = dev;
+
+                       if (give_skb_to_upper(local_skb, dev)
+                                       != NET_RX_SUCCESS) {
+                               kfree_skb(local_skb);
+                               goto drop;
+                       }
+
                        dev->stats.rx_bytes += skb->len;
                        dev->stats.rx_packets++;
 
-                       kfree_skb(skb);
+                       consume_skb(local_skb);
+                       consume_skb(skb);
                        break;
                default:
                        break;
@@ -443,7 +474,6 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
        if (ipv6_addr_is_multicast(&ipv6_daddr)) {
                lowpan_cb(skb)->chan = NULL;
        } else {
-               unsigned long flags;
                u8 addr_type;
 
                /* Get destination BT device from skb.
@@ -454,19 +484,14 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
                BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
                       addr_type, &ipv6_daddr);
 
-               read_lock_irqsave(&devices_lock, flags);
                peer = peer_lookup_ba(dev, &addr, addr_type);
-               read_unlock_irqrestore(&devices_lock, flags);
-
                if (!peer) {
                        /* The packet might be sent to 6lowpan interface
                         * because of routing (either via default route
                         * or user set route) so get peer according to
                         * the destination address.
                         */
-                       read_lock_irqsave(&devices_lock, flags);
                        peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
-                       read_unlock_irqrestore(&devices_lock, flags);
                        if (!peer) {
                                BT_DBG("no such peer %pMR found", &addr);
                                return -ENOENT;
@@ -549,14 +574,13 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
 static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 {
        struct sk_buff *local_skb;
-       struct lowpan_dev *entry, *tmp;
-       unsigned long flags;
+       struct lowpan_dev *entry;
        int err = 0;
 
-       read_lock_irqsave(&devices_lock, flags);
+       rcu_read_lock();
 
-       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
-               struct lowpan_peer *pentry, *ptmp;
+       list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+               struct lowpan_peer *pentry;
                struct lowpan_dev *dev;
 
                if (entry->netdev != netdev)
@@ -564,7 +588,7 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
 
                dev = lowpan_dev(entry->netdev);
 
-               list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+               list_for_each_entry_rcu(pentry, &dev->peers, list) {
                        int ret;
 
                        local_skb = skb_clone(skb, GFP_ATOMIC);
@@ -581,7 +605,7 @@ static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
                }
        }
 
-       read_unlock_irqrestore(&devices_lock, flags);
+       rcu_read_unlock();
 
        return err;
 }
@@ -638,7 +662,26 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
        return err < 0 ? NET_XMIT_DROP : err;
 }
 
+static struct lock_class_key bt_tx_busylock;
+static struct lock_class_key bt_netdev_xmit_lock_key;
+
+static void bt_set_lockdep_class_one(struct net_device *dev,
+                                    struct netdev_queue *txq,
+                                    void *_unused)
+{
+       lockdep_set_class(&txq->_xmit_lock, &bt_netdev_xmit_lock_key);
+}
+
+static int bt_dev_init(struct net_device *dev)
+{
+       netdev_for_each_tx_queue(dev, bt_set_lockdep_class_one, NULL);
+       dev->qdisc_tx_busylock = &bt_tx_busylock;
+
+       return 0;
+}
+
 static const struct net_device_ops netdev_ops = {
+       .ndo_init               = bt_dev_init,
        .ndo_start_xmit         = bt_xmit,
 };
 
@@ -783,7 +826,6 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
                                        struct lowpan_dev *dev)
 {
        struct lowpan_peer *peer;
-       unsigned long flags;
 
        peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
        if (!peer)
@@ -806,10 +848,10 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
         */
        set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8);
 
-       write_lock_irqsave(&devices_lock, flags);
+       spin_lock(&devices_lock);
        INIT_LIST_HEAD(&peer->list);
        peer_add(dev, peer);
-       write_unlock_irqrestore(&devices_lock, flags);
+       spin_unlock(&devices_lock);
 
        /* Notifying peers about us needs to be done without locks held */
        INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
@@ -822,7 +864,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
 {
        struct net_device *netdev;
        int err = 0;
-       unsigned long flags;
 
        netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE,
                              NET_NAME_UNKNOWN, netdev_setup);
@@ -852,10 +893,10 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
        (*dev)->hdev = chan->conn->hcon->hdev;
        INIT_LIST_HEAD(&(*dev)->peers);
 
-       write_lock_irqsave(&devices_lock, flags);
+       spin_lock(&devices_lock);
        INIT_LIST_HEAD(&(*dev)->list);
-       list_add(&(*dev)->list, &bt_6lowpan_devices);
-       write_unlock_irqrestore(&devices_lock, flags);
+       list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
+       spin_unlock(&devices_lock);
 
        return 0;
 
@@ -909,11 +950,10 @@ static void delete_netdev(struct work_struct *work)
 
 static void chan_close_cb(struct l2cap_chan *chan)
 {
-       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *entry;
        struct lowpan_dev *dev = NULL;
        struct lowpan_peer *peer;
        int err = -ENOENT;
-       unsigned long flags;
        bool last = false, removed = true;
 
        BT_DBG("chan %p conn %p", chan, chan->conn);
@@ -928,11 +968,11 @@ static void chan_close_cb(struct l2cap_chan *chan)
                removed = false;
        }
 
-       write_lock_irqsave(&devices_lock, flags);
+       spin_lock(&devices_lock);
 
-       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+       list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
                dev = lowpan_dev(entry->netdev);
-               peer = peer_lookup_chan(dev, chan);
+               peer = __peer_lookup_chan(dev, chan);
                if (peer) {
                        last = peer_del(dev, peer);
                        err = 0;
@@ -943,13 +983,12 @@ static void chan_close_cb(struct l2cap_chan *chan)
                               atomic_read(&chan->kref.refcount));
 
                        l2cap_chan_put(chan);
-                       kfree(peer);
                        break;
                }
        }
 
        if (!err && last && dev && !atomic_read(&dev->peer_count)) {
-               write_unlock_irqrestore(&devices_lock, flags);
+               spin_unlock(&devices_lock);
 
                cancel_delayed_work_sync(&dev->notify_peers);
 
@@ -960,7 +999,7 @@ static void chan_close_cb(struct l2cap_chan *chan)
                        schedule_work(&entry->delete_netdev);
                }
        } else {
-               write_unlock_irqrestore(&devices_lock, flags);
+               spin_unlock(&devices_lock);
        }
 
        return;
@@ -1152,10 +1191,9 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
 
 static void disconnect_all_peers(void)
 {
-       struct lowpan_dev *entry, *tmp_dev;
+       struct lowpan_dev *entry;
        struct lowpan_peer *peer, *tmp_peer, *new_peer;
        struct list_head peers;
-       unsigned long flags;
 
        INIT_LIST_HEAD(&peers);
 
@@ -1164,10 +1202,10 @@ static void disconnect_all_peers(void)
         * with the same list at the same time.
         */
 
-       read_lock_irqsave(&devices_lock, flags);
+       rcu_read_lock();
 
-       list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) {
-               list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list) {
+       list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
+               list_for_each_entry_rcu(peer, &entry->peers, list) {
                        new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
                        if (!new_peer)
                                break;
@@ -1179,26 +1217,36 @@ static void disconnect_all_peers(void)
                }
        }
 
-       read_unlock_irqrestore(&devices_lock, flags);
+       rcu_read_unlock();
 
+       spin_lock(&devices_lock);
        list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
                l2cap_chan_close(peer->chan, ENOENT);
-               kfree(peer);
+
+               list_del_rcu(&peer->list);
+               call_rcu(&peer->rcu, peer_free);
+
+               module_put(THIS_MODULE);
        }
+       spin_unlock(&devices_lock);
 }
 
-static int lowpan_psm_set(void *data, u64 val)
-{
+struct set_psm {
+       struct work_struct work;
        u16 psm;
+};
+
+static void do_psm_set(struct work_struct *work)
+{
+       struct set_psm *set_psm = container_of(work, struct set_psm, work);
 
-       psm = val;
-       if (psm == 0 || psm_6lowpan != psm)
+       if (set_psm->psm == 0 || psm_6lowpan != set_psm->psm)
                /* Disconnect existing connections if 6lowpan is
                 * disabled (psm = 0), or if psm changes.
                 */
                disconnect_all_peers();
 
-       psm_6lowpan = psm;
+       psm_6lowpan = set_psm->psm;
 
        if (listen_chan) {
                l2cap_chan_close(listen_chan, 0);
@@ -1207,6 +1255,22 @@ static int lowpan_psm_set(void *data, u64 val)
 
        listen_chan = bt_6lowpan_listen();
 
+       kfree(set_psm);
+}
+
+static int lowpan_psm_set(void *data, u64 val)
+{
+       struct set_psm *set_psm;
+
+       set_psm = kzalloc(sizeof(*set_psm), GFP_KERNEL);
+       if (!set_psm)
+               return -ENOMEM;
+
+       set_psm->psm = val;
+       INIT_WORK(&set_psm->work, do_psm_set);
+
+       schedule_work(&set_psm->work);
+
        return 0;
 }
 
@@ -1288,19 +1352,18 @@ static ssize_t lowpan_control_write(struct file *fp,
 
 static int lowpan_control_show(struct seq_file *f, void *ptr)
 {
-       struct lowpan_dev *entry, *tmp_dev;
-       struct lowpan_peer *peer, *tmp_peer;
-       unsigned long flags;
+       struct lowpan_dev *entry;
+       struct lowpan_peer *peer;
 
-       read_lock_irqsave(&devices_lock, flags);
+       spin_lock(&devices_lock);
 
-       list_for_each_entry_safe(entry, tmp_dev, &bt_6lowpan_devices, list) {
-               list_for_each_entry_safe(peer, tmp_peer, &entry->peers, list)
+       list_for_each_entry(entry, &bt_6lowpan_devices, list) {
+               list_for_each_entry(peer, &entry->peers, list)
                        seq_printf(f, "%pMR (type %u)\n",
                                   &peer->chan->dst, peer->chan->dst_type);
        }
 
-       read_unlock_irqrestore(&devices_lock, flags);
+       spin_unlock(&devices_lock);
 
        return 0;
 }
@@ -1322,7 +1385,6 @@ static void disconnect_devices(void)
 {
        struct lowpan_dev *entry, *tmp, *new_dev;
        struct list_head devices;
-       unsigned long flags;
 
        INIT_LIST_HEAD(&devices);
 
@@ -1331,9 +1393,9 @@ static void disconnect_devices(void)
         * devices list.
         */
 
-       read_lock_irqsave(&devices_lock, flags);
+       rcu_read_lock();
 
-       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+       list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
                new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC);
                if (!new_dev)
                        break;
@@ -1341,10 +1403,10 @@ static void disconnect_devices(void)
                new_dev->netdev = entry->netdev;
                INIT_LIST_HEAD(&new_dev->list);
 
-               list_add(&new_dev->list, &devices);
+               list_add_rcu(&new_dev->list, &devices);
        }
 
-       read_unlock_irqrestore(&devices_lock, flags);
+       rcu_read_unlock();
 
        list_for_each_entry_safe(entry, tmp, &devices, list) {
                ifdown(entry->netdev);
@@ -1359,17 +1421,15 @@ static int device_event(struct notifier_block *unused,
                        unsigned long event, void *ptr)
 {
        struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
-       struct lowpan_dev *entry, *tmp;
-       unsigned long flags;
+       struct lowpan_dev *entry;
 
        if (netdev->type != ARPHRD_6LOWPAN)
                return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_UNREGISTER:
-               write_lock_irqsave(&devices_lock, flags);
-               list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
-                                        list) {
+               spin_lock(&devices_lock);
+               list_for_each_entry(entry, &bt_6lowpan_devices, list) {
                        if (entry->netdev == netdev) {
                                BT_DBG("Unregistered netdev %s %p",
                                       netdev->name, netdev);
@@ -1378,7 +1438,7 @@ static int device_event(struct notifier_block *unused,
                                break;
                        }
                }
-               write_unlock_irqrestore(&devices_lock, flags);
+               spin_unlock(&devices_lock);
                break;
        }
 
index b9517bd171901e7c6a9395791f3ecfc7fbefdd6d..96887ae8375b52cf545708a3f9ea14fa40fc996a 100644 (file)
@@ -141,10 +141,11 @@ int hci_disconnect(struct hci_conn *conn, __u8 reason)
         */
        if (conn->type == ACL_LINK && conn->role == HCI_ROLE_MASTER) {
                struct hci_dev *hdev = conn->hdev;
-               struct hci_cp_read_clock_offset cp;
+               struct hci_cp_read_clock_offset clkoff_cp;
 
-               cp.handle = cpu_to_le16(conn->handle);
-               hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(cp), &cp);
+               clkoff_cp.handle = cpu_to_le16(conn->handle);
+               hci_send_cmd(hdev, HCI_OP_READ_CLOCK_OFFSET, sizeof(clkoff_cp),
+                            &clkoff_cp);
        }
 
        conn->state = BT_DISCONN;
@@ -415,7 +416,7 @@ static void le_conn_timeout(struct work_struct *work)
         * happen with broken hardware or if low duty cycle was used
         * (which doesn't have a timeout of its own).
         */
-       if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
+       if (conn->role == HCI_ROLE_SLAVE) {
                u8 enable = 0x00;
                hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable),
                             &enable);
@@ -517,7 +518,7 @@ int hci_conn_del(struct hci_conn *conn)
                /* Unacked frames */
                hdev->acl_cnt += conn->sent;
        } else if (conn->type == LE_LINK) {
-               cancel_delayed_work_sync(&conn->le_conn_timeout);
+               cancel_delayed_work(&conn->le_conn_timeout);
 
                if (hdev->le_pkts)
                        hdev->le_cnt += conn->sent;
@@ -544,6 +545,9 @@ int hci_conn_del(struct hci_conn *conn)
 
        hci_conn_del_sysfs(conn);
 
+       if (test_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags))
+               hci_conn_params_del(conn->hdev, &conn->dst, conn->dst_type);
+
        hci_dev_put(hdev);
 
        hci_conn_put(conn);
index cb05d7f16a34acc0ca78958d3e5d612453f7d154..91995f8ab0a0dd410bc922373376fa24054273c9 100644 (file)
@@ -4477,7 +4477,7 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete)
 
        BT_DBG("length %u", skb_queue_len(&req->cmd_q));
 
-       /* If an error occured during request building, remove all HCI
+       /* If an error occurred during request building, remove all HCI
         * commands queued on the HCI request queue.
         */
        if (req->err) {
@@ -4546,7 +4546,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
                return -ENOMEM;
        }
 
-       /* Stand-alone HCI commands must be flaged as
+       /* Stand-alone HCI commands must be flagged as
         * single-command requests.
         */
        bt_cb(skb)->req.start = true;
@@ -4566,7 +4566,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
 
        BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
 
-       /* If an error occured during request building, there is no point in
+       /* If an error occurred during request building, there is no point in
         * queueing the HCI command. We can simply return.
         */
        if (req->err)
@@ -4661,8 +4661,12 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
 
                skb_shinfo(skb)->frag_list = NULL;
 
-               /* Queue all fragments atomically */
-               spin_lock(&queue->lock);
+               /* Queue all fragments atomically. We need to use spin_lock_bh
+                * here because of 6LoWPAN links, as there this function is
+                * called from softirq and using normal spin lock could cause
+                * deadlocks.
+                */
+               spin_lock_bh(&queue->lock);
 
                __skb_queue_tail(queue, skb);
 
@@ -4679,7 +4683,7 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
                        __skb_queue_tail(queue, skb);
                } while (list);
 
-               spin_unlock(&queue->lock);
+               spin_unlock_bh(&queue->lock);
        }
 }
 
index 8b0a2a6de4199cea5610890a887296d04dec3eca..aa152140c3e279bd6599b5b09498f748e501c08e 100644 (file)
@@ -205,6 +205,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
        hdev->le_scan_type = LE_SCAN_PASSIVE;
 
        hdev->ssp_debug_mode = 0;
+
+       hci_bdaddr_list_clear(&hdev->le_white_list);
 }
 
 static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1045,7 +1047,7 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       /* If we're doing connection initation as peripheral. Set a
+       /* If we're doing connection initiation as peripheral. Set a
         * timeout in case something goes wrong.
         */
        if (*sent) {
@@ -1577,8 +1579,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
        struct inquiry_entry *e;
 
        if (conn && !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, bdaddr, ACL_LINK, 0x00, 0, name,
-                                     name_len, conn->dev_class);
+               mgmt_device_connected(hdev, conn, 0, name, name_len);
 
        if (discov->state == DISCOVERY_STOPPED)
                return;
@@ -2536,9 +2537,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
                cp.pscan_rep_mode = 0x02;
                hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
        } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, &conn->dst, conn->type,
-                                     conn->dst_type, 0, NULL, 0,
-                                     conn->dev_class);
+               mgmt_device_connected(hdev, conn, 0, NULL, 0);
 
        if (!hci_outgoing_auth_needed(hdev, conn)) {
                conn->state = BT_CONNECTED;
@@ -3434,9 +3433,7 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
                cp.pscan_rep_mode = 0x02;
                hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
        } else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, &conn->dst, conn->type,
-                                     conn->dst_type, 0, NULL, 0,
-                                     conn->dev_class);
+               mgmt_device_connected(hdev, conn, 0, NULL, 0);
 
        if (!hci_outgoing_auth_needed(hdev, conn)) {
                conn->state = BT_CONNECTED;
@@ -4214,8 +4211,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
-               mgmt_device_connected(hdev, &conn->dst, conn->type,
-                                     conn->dst_type, 0, NULL, 0, NULL);
+               mgmt_device_connected(hdev, conn, 0, NULL, 0);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
@@ -4269,25 +4265,26 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev,
 }
 
 /* This function requires the caller holds hdev->lock */
-static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
-                                 u8 addr_type, u8 adv_type)
+static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
+                                             bdaddr_t *addr,
+                                             u8 addr_type, u8 adv_type)
 {
        struct hci_conn *conn;
        struct hci_conn_params *params;
 
        /* If the event is not connectable don't proceed further */
        if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
-               return;
+               return NULL;
 
        /* Ignore if the device is blocked */
        if (hci_bdaddr_list_lookup(&hdev->blacklist, addr, addr_type))
-               return;
+               return NULL;
 
        /* Most controller will fail if we try to create new connections
         * while we have an existing one in slave role.
         */
        if (hdev->conn_hash.le_num_slave > 0)
-               return;
+               return NULL;
 
        /* If we're not connectable only connect devices that we have in
         * our pend_le_conns list.
@@ -4295,7 +4292,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
        params = hci_pend_le_action_lookup(&hdev->pend_le_conns,
                                           addr, addr_type);
        if (!params)
-               return;
+               return NULL;
 
        switch (params->auto_connect) {
        case HCI_AUTO_CONN_DIRECT:
@@ -4304,7 +4301,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
                 * incoming connections from slave devices.
                 */
                if (adv_type != LE_ADV_DIRECT_IND)
-                       return;
+                       return NULL;
                break;
        case HCI_AUTO_CONN_ALWAYS:
                /* Devices advertising with ADV_IND or ADV_DIRECT_IND
@@ -4315,7 +4312,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
                 */
                break;
        default:
-               return;
+               return NULL;
        }
 
        conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
@@ -4328,7 +4325,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
                 * count consistent once the connection is established.
                 */
                params->conn = hci_conn_get(conn);
-               return;
+               return conn;
        }
 
        switch (PTR_ERR(conn)) {
@@ -4341,7 +4338,10 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
                break;
        default:
                BT_DBG("Failed to connect: err %ld", PTR_ERR(conn));
+               return NULL;
        }
+
+       return NULL;
 }
 
 static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
@@ -4349,6 +4349,7 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
 {
        struct discovery_state *d = &hdev->discovery;
        struct smp_irk *irk;
+       struct hci_conn *conn;
        bool match;
        u32 flags;
 
@@ -4360,7 +4361,14 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
        }
 
        /* Check if we have been requested to connect to this device */
-       check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+       conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+       if (conn && type == LE_ADV_IND) {
+               /* Store report for later inclusion by
+                * mgmt_device_connected
+                */
+               memcpy(conn->le_adv_data, data, len);
+               conn->le_adv_data_len = len;
+       }
 
        /* Passive scanning shouldn't trigger any device found events,
         * except for devices marked as CONN_REPORT for which we do send
index 29e1ec7189bd0a027b43efaf179fe448c2d8f946..5e2cd25359781784018890be26b8196ff801dd55 100644 (file)
@@ -987,7 +987,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        skb_queue_tail(&hdev->raw_q, skb);
                        queue_work(hdev->workqueue, &hdev->tx_work);
                } else {
-                       /* Stand-alone HCI commands must be flaged as
+                       /* Stand-alone HCI commands must be flagged as
                         * single-command requests.
                         */
                        bt_cb(skb)->req.start = true;
index b6f9777e057da11105d63deabf9ebd0dc897436c..fc15174c612c3d087c43ccf736eda23aa2c60054 100644 (file)
@@ -3873,9 +3873,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
        hci_dev_lock(hdev);
        if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
            !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
-               mgmt_device_connected(hdev, &hcon->dst, hcon->type,
-                                     hcon->dst_type, 0, NULL, 0,
-                                     hcon->dev_class);
+               mgmt_device_connected(hdev, hcon, 0, NULL, 0);
        hci_dev_unlock(hdev);
 
        l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
@@ -4084,7 +4082,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
                chan->num_conf_req++;
        }
 
-       /* Got Conf Rsp PENDING from remote side and asume we sent
+       /* Got Conf Rsp PENDING from remote side and assume we sent
           Conf Rsp PENDING in the code above */
        if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
            test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
@@ -5494,6 +5492,7 @@ static inline int l2cap_le_credits(struct l2cap_conn *conn,
        if (credits > max_credits) {
                BT_ERR("LE credits overflow");
                l2cap_send_disconn_req(chan, ECONNRESET);
+               l2cap_chan_unlock(chan);
 
                /* Return 0 so that we don't trigger an unnecessary
                 * command reject packet.
index efb71b022ab6520527b3087dbf917ddcb925438e..9c4daf715cf804ed3e23b240f793ea3410f73a4b 100644 (file)
@@ -2725,10 +2725,40 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
        }
 
        if (cp->addr.type == BDADDR_BREDR) {
+               /* If disconnection is requested, then look up the
+                * connection. If the remote device is connected, it
+                * will be later used to terminate the link.
+                *
+                * Setting it to NULL explicitly will cause no
+                * termination of the link.
+                */
+               if (cp->disconnect)
+                       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+                                                      &cp->addr.bdaddr);
+               else
+                       conn = NULL;
+
                err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
        } else {
                u8 addr_type;
 
+               conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
+                                              &cp->addr.bdaddr);
+               if (conn) {
+                       /* Defer clearing up the connection parameters
+                        * until closing to give a chance of keeping
+                        * them if a repairing happens.
+                        */
+                       set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
+
+                       /* If disconnection is not requested, then
+                        * clear the connection variable so that the
+                        * link is not terminated.
+                        */
+                       if (!cp->disconnect)
+                               conn = NULL;
+               }
+
                if (cp->addr.type == BDADDR_LE_PUBLIC)
                        addr_type = ADDR_LE_DEV_PUBLIC;
                else
@@ -2736,8 +2766,6 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
 
                hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
 
-               hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
-
                err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
        }
 
@@ -2747,17 +2775,9 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
-       if (cp->disconnect) {
-               if (cp->addr.type == BDADDR_BREDR)
-                       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
-                                                      &cp->addr.bdaddr);
-               else
-                       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
-                                                      &cp->addr.bdaddr);
-       } else {
-               conn = NULL;
-       }
-
+       /* If the connection variable is set, then termination of the
+        * link is requested.
+        */
        if (!conn) {
                err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
                                   &rp, sizeof(rp));
@@ -3062,6 +3082,11 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
        hci_conn_put(conn);
 
        mgmt_pending_remove(cmd);
+
+       /* The device is paired so there is no need to remove
+        * its connection parameters anymore.
+        */
+       clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
 }
 
 void mgmt_smp_complete(struct hci_conn *conn, bool complete)
@@ -6171,26 +6196,36 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
        return eir_len;
 }
 
-void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
-                          u8 addr_type, u32 flags, u8 *name, u8 name_len,
-                          u8 *dev_class)
+void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
+                          u32 flags, u8 *name, u8 name_len)
 {
        char buf[512];
        struct mgmt_ev_device_connected *ev = (void *) buf;
        u16 eir_len = 0;
 
-       bacpy(&ev->addr.bdaddr, bdaddr);
-       ev->addr.type = link_to_bdaddr(link_type, addr_type);
+       bacpy(&ev->addr.bdaddr, &conn->dst);
+       ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
 
        ev->flags = __cpu_to_le32(flags);
 
-       if (name_len > 0)
-               eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
-                                         name, name_len);
+       /* We must ensure that the EIR Data fields are ordered and
+        * unique. Keep it simple for now and avoid the problem by not
+        * adding any BR/EDR data to the LE adv.
+        */
+       if (conn->le_adv_data_len > 0) {
+               memcpy(&ev->eir[eir_len],
+                      conn->le_adv_data, conn->le_adv_data_len);
+               eir_len = conn->le_adv_data_len;
+       } else {
+               if (name_len > 0)
+                       eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
+                                                 name, name_len);
 
-       if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
-               eir_len = eir_append_data(ev->eir, eir_len,
-                                         EIR_CLASS_OF_DEV, dev_class, 3);
+               if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
+                       eir_len = eir_append_data(ev->eir, eir_len,
+                                                 EIR_CLASS_OF_DEV,
+                                                 conn->dev_class, 3);
+       }
 
        ev->eir_len = cpu_to_le16(eir_len);
 
index af73bc3acb406a6256565a18d0ddf2611a96e07f..bce9c3d393248e882afe309feaf1b6b71b9cd51f 100644 (file)
@@ -78,8 +78,8 @@ static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
 #define __get_type(b)     ((b & 0xef))
 
 #define __test_ea(b)      ((b & 0x01))
-#define __test_cr(b)      ((b & 0x02))
-#define __test_pf(b)      ((b & 0x10))
+#define __test_cr(b)      (!!(b & 0x02))
+#define __test_pf(b)      (!!(b & 0x10))
 
 #define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
 #define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))
@@ -904,7 +904,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
        hdr->len  = __len8(sizeof(*mcc) + 1);
 
        mcc = (void *) ptr; ptr += sizeof(*mcc);
-       mcc->type = __mcc_type(cr, RFCOMM_NSC);
+       mcc->type = __mcc_type(0, RFCOMM_NSC);
        mcc->len  = __len8(1);
 
        /* Type that we didn't like */
index f09b6b65cf6b22079d6ce60d53f2613ccf6a7745..3ebf65b508813b57c42ec3c2b4f75c1b97e9122d 100644 (file)
@@ -191,16 +191,13 @@ int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
        return 0;
 }
 
-static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7],
-                 u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat, bdaddr_t *ra,
-                 u8 res[16])
+static int smp_c1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r[16],
+                 u8 preq[7], u8 pres[7], u8 _iat, bdaddr_t *ia, u8 _rat,
+                 bdaddr_t *ra, u8 res[16])
 {
-       struct hci_dev *hdev = smp->conn->hcon->hdev;
        u8 p1[16], p2[16];
        int err;
 
-       BT_DBG("%s", hdev->name);
-
        memset(p1, 0, 16);
 
        /* p1 = pres || preq || _rat || _iat */
@@ -218,7 +215,7 @@ static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7],
        u128_xor((u128 *) res, (u128 *) r, (u128 *) p1);
 
        /* res = e(k, res) */
-       err = smp_e(smp->tfm_aes, k, res);
+       err = smp_e(tfm_aes, k, res);
        if (err) {
                BT_ERR("Encrypt data error");
                return err;
@@ -228,26 +225,23 @@ static int smp_c1(struct smp_chan *smp, u8 k[16], u8 r[16], u8 preq[7],
        u128_xor((u128 *) res, (u128 *) res, (u128 *) p2);
 
        /* res = e(k, res) */
-       err = smp_e(smp->tfm_aes, k, res);
+       err = smp_e(tfm_aes, k, res);
        if (err)
                BT_ERR("Encrypt data error");
 
        return err;
 }
 
-static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16],
-                 u8 _r[16])
+static int smp_s1(struct crypto_blkcipher *tfm_aes, u8 k[16], u8 r1[16],
+                 u8 r2[16], u8 _r[16])
 {
-       struct hci_dev *hdev = smp->conn->hcon->hdev;
        int err;
 
-       BT_DBG("%s", hdev->name);
-
        /* Just least significant octets from r1 and r2 are considered */
        memcpy(_r, r2, 8);
        memcpy(_r + 8, r1, 8);
 
-       err = smp_e(smp->tfm_aes, k, _r);
+       err = smp_e(tfm_aes, k, _r);
        if (err)
                BT_ERR("Encrypt data error");
 
@@ -547,7 +541,7 @@ static u8 smp_confirm(struct smp_chan *smp)
 
        BT_DBG("conn %p", conn);
 
-       ret = smp_c1(smp, smp->tk, smp->prnd, smp->preq, smp->prsp,
+       ret = smp_c1(smp->tfm_aes, smp->tk, smp->prnd, smp->preq, smp->prsp,
                     conn->hcon->init_addr_type, &conn->hcon->init_addr,
                     conn->hcon->resp_addr_type, &conn->hcon->resp_addr,
                     cp.confirm_val);
@@ -578,7 +572,7 @@ static u8 smp_random(struct smp_chan *smp)
 
        BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
-       ret = smp_c1(smp, smp->tk, smp->rrnd, smp->preq, smp->prsp,
+       ret = smp_c1(smp->tfm_aes, smp->tk, smp->rrnd, smp->preq, smp->prsp,
                     hcon->init_addr_type, &hcon->init_addr,
                     hcon->resp_addr_type, &hcon->resp_addr, confirm);
        if (ret)
@@ -594,7 +588,7 @@ static u8 smp_random(struct smp_chan *smp)
                __le64 rand = 0;
                __le16 ediv = 0;
 
-               smp_s1(smp, smp->tk, smp->rrnd, smp->prnd, stk);
+               smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk);
 
                memset(stk + smp->enc_key_size, 0,
                       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
@@ -613,7 +607,7 @@ static u8 smp_random(struct smp_chan *smp)
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(smp->prnd),
                             smp->prnd);
 
-               smp_s1(smp, smp->tk, smp->prnd, smp->rrnd, stk);
+               smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk);
 
                memset(stk + smp->enc_key_size, 0,
                       SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size);
@@ -970,7 +964,7 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
        if (sec_level > conn->hcon->pending_sec_level)
                conn->hcon->pending_sec_level = sec_level;
 
-       /* If we need MITM check that it can be acheived */
+       /* If we need MITM check that it can be achieved */
        if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
                u8 method;
 
@@ -1028,7 +1022,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
        auth = rsp->auth_req & AUTH_REQ_MASK;
 
-       /* If we need MITM check that it can be acheived */
+       /* If we need MITM check that it can be achieved */
        if (conn->hcon->pending_sec_level >= BT_SECURITY_HIGH) {
                u8 method;
 
index 70bb609c283d54a396553fd19faeef8c4e4ae820..bb09b0364619fd577acc45c067211a33d8f0b142 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/if_macvlan.h>
 #include <linux/errqueue.h>
+#include <linux/hrtimer.h>
 
 #include "net-sysfs.h"
 
@@ -4412,7 +4413,6 @@ EXPORT_SYMBOL(__napi_schedule_irqoff);
 void __napi_complete(struct napi_struct *n)
 {
        BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state));
-       BUG_ON(n->gro_list);
 
        list_del_init(&n->poll_list);
        smp_mb__before_atomic();
@@ -4420,7 +4420,7 @@ void __napi_complete(struct napi_struct *n)
 }
 EXPORT_SYMBOL(__napi_complete);
 
-void napi_complete(struct napi_struct *n)
+void napi_complete_done(struct napi_struct *n, int work_done)
 {
        unsigned long flags;
 
@@ -4431,8 +4431,18 @@ void napi_complete(struct napi_struct *n)
        if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state)))
                return;
 
-       napi_gro_flush(n, false);
+       if (n->gro_list) {
+               unsigned long timeout = 0;
 
+               if (work_done)
+                       timeout = n->dev->gro_flush_timeout;
+
+               if (timeout)
+                       hrtimer_start(&n->timer, ns_to_ktime(timeout),
+                                     HRTIMER_MODE_REL_PINNED);
+               else
+                       napi_gro_flush(n, false);
+       }
        if (likely(list_empty(&n->poll_list))) {
                WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state));
        } else {
@@ -4442,7 +4452,7 @@ void napi_complete(struct napi_struct *n)
                local_irq_restore(flags);
        }
 }
-EXPORT_SYMBOL(napi_complete);
+EXPORT_SYMBOL(napi_complete_done);
 
 /* must be called under rcu_read_lock(), as we dont take a reference */
 struct napi_struct *napi_by_id(unsigned int napi_id)
@@ -4496,10 +4506,23 @@ void napi_hash_del(struct napi_struct *napi)
 }
 EXPORT_SYMBOL_GPL(napi_hash_del);
 
+static enum hrtimer_restart napi_watchdog(struct hrtimer *timer)
+{
+       struct napi_struct *napi;
+
+       napi = container_of(timer, struct napi_struct, timer);
+       if (napi->gro_list)
+               napi_schedule(napi);
+
+       return HRTIMER_NORESTART;
+}
+
 void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
                    int (*poll)(struct napi_struct *, int), int weight)
 {
        INIT_LIST_HEAD(&napi->poll_list);
+       hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+       napi->timer.function = napi_watchdog;
        napi->gro_count = 0;
        napi->gro_list = NULL;
        napi->skb = NULL;
@@ -4518,6 +4541,20 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
 }
 EXPORT_SYMBOL(netif_napi_add);
 
+void napi_disable(struct napi_struct *n)
+{
+       might_sleep();
+       set_bit(NAPI_STATE_DISABLE, &n->state);
+
+       while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
+               msleep(1);
+
+       hrtimer_cancel(&n->timer);
+
+       clear_bit(NAPI_STATE_DISABLE, &n->state);
+}
+EXPORT_SYMBOL(napi_disable);
+
 void netif_napi_del(struct napi_struct *napi)
 {
        list_del_init(&napi->dev_list);
index 9dd06699b09c9434e60aa40a948adf69d5505d2d..1a24602cd54e63caa38e40cdedf8009944e0824b 100644 (file)
@@ -325,6 +325,23 @@ static ssize_t tx_queue_len_store(struct device *dev,
 }
 NETDEVICE_SHOW_RW(tx_queue_len, fmt_ulong);
 
+static int change_gro_flush_timeout(struct net_device *dev, unsigned long val)
+{
+       dev->gro_flush_timeout = val;
+       return 0;
+}
+
+static ssize_t gro_flush_timeout_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
+{
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       return netdev_store(dev, attr, buf, len, change_gro_flush_timeout);
+}
+NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong);
+
 static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t len)
 {
@@ -422,6 +439,7 @@ static struct attribute *net_class_attrs[] = {
        &dev_attr_mtu.attr,
        &dev_attr_flags.attr,
        &dev_attr_tx_queue_len.attr,
+       &dev_attr_gro_flush_timeout.attr,
        &dev_attr_phys_port_id.attr,
        NULL,
 };
index ac56dd06c306f3712e57ce8e4724c79565589499..0725cf0cb685787b2122606437da53299fb24621 100644 (file)
@@ -1213,6 +1213,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = sk->sk_max_pacing_rate;
                break;
 
+       case SO_INCOMING_CPU:
+               v.val = sk->sk_incoming_cpu;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
@@ -1517,6 +1521,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
 
                newsk->sk_err      = 0;
                newsk->sk_priority = 0;
+               newsk->sk_incoming_cpu = raw_smp_processor_id();
                /*
                 * Before updating sk_refcnt, we must commit prior changes to memory
                 * (Documentation/RCU/rculist_nulls.txt for details)
index dd646a8025cb559233d7b321095abec2ce606cf6..4648f12098ad6490f44f2446c4a9c67323e2fbef 100644 (file)
@@ -192,12 +192,12 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
         */
        drv = dsa_switch_probe(host_dev, pd->sw_addr, &name);
        if (drv == NULL) {
-               printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
-                      dst->master_netdev->name, index);
+               netdev_err(dst->master_netdev, "[%d]: could not detect attached switch\n",
+                          index);
                return ERR_PTR(-EINVAL);
        }
-       printk(KERN_INFO "%s[%d]: detected a %s switch\n",
-               dst->master_netdev->name, index, name);
+       netdev_info(dst->master_netdev, "[%d]: detected a %s switch\n",
+                   index, name);
 
 
        /*
@@ -225,7 +225,8 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
 
                if (!strcmp(name, "cpu")) {
                        if (dst->cpu_switch != -1) {
-                               printk(KERN_ERR "multiple cpu ports?!\n");
+                               netdev_err(dst->master_netdev,
+                                          "multiple cpu ports?!\n");
                                ret = -EINVAL;
                                goto out;
                        }
@@ -320,10 +321,8 @@ dsa_switch_setup(struct dsa_switch_tree *dst, int index,
 
                slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
                if (slave_dev == NULL) {
-                       printk(KERN_ERR "%s[%d]: can't create dsa "
-                              "slave device for port %d(%s)\n",
-                              dst->master_netdev->name,
-                              index, i, pd->port_names[i]);
+                       netdev_err(dst->master_netdev, "[%d]: can't create dsa slave device for port %d(%s)\n",
+                                  index, i, pd->port_names[i]);
                        continue;
                }
 
@@ -701,15 +700,13 @@ static inline void dsa_of_remove(struct platform_device *pdev)
 
 static int dsa_probe(struct platform_device *pdev)
 {
-       static int dsa_version_printed;
        struct dsa_platform_data *pd = pdev->dev.platform_data;
        struct net_device *dev;
        struct dsa_switch_tree *dst;
        int i, ret;
 
-       if (!dsa_version_printed++)
-               printk(KERN_NOTICE "Distributed Switch Architecture "
-                       "driver version %s\n", dsa_driver_version);
+       pr_notice_once("Distributed Switch Architecture driver version %s\n",
+                      dsa_driver_version);
 
        if (pdev->dev.of_node) {
                ret = dsa_of_probe(pdev);
@@ -753,9 +750,8 @@ static int dsa_probe(struct platform_device *pdev)
 
                ds = dsa_switch_setup(dst, i, &pdev->dev, pd->chip[i].host_dev);
                if (IS_ERR(ds)) {
-                       printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
-                               "instance (error %ld)\n", dev->name, i,
-                               PTR_ERR(ds));
+                       netdev_err(dev, "[%d]: couldn't create dsa switch instance (error %ld)\n",
+                                  i, PTR_ERR(ds));
                        continue;
                }
 
index 0ea466dad81801ed4c25365f226d7a79267e0de4..528380a3e296001b9c727e9f35e07f403d7f050b 100644 (file)
@@ -532,7 +532,7 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
                 */
                ret = of_phy_register_fixed_link(port_dn);
                if (ret) {
-                       pr_err("failed to register fixed PHY\n");
+                       netdev_err(slave_dev, "failed to register fixed PHY\n");
                        return;
                }
                phy_is_fixed = true;
@@ -558,8 +558,8 @@ static void dsa_slave_phy_setup(struct dsa_slave_priv *p,
                phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
                                   p->phy_interface);
        } else {
-               pr_info("attached PHY at address %d [%s]\n",
-                       p->phy->addr, p->phy->drv->name);
+               netdev_info(slave_dev, "attached PHY at address %d [%s]\n",
+                           p->phy->addr, p->phy->drv->name);
        }
 }
 
@@ -657,8 +657,8 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
 
        ret = register_netdev(slave_dev);
        if (ret) {
-               printk(KERN_ERR "%s: error %d registering interface %s\n",
-                               master->name, ret, slave_dev->name);
+               netdev_err(master, "error %d registering interface %s\n",
+                          ret, slave_dev->name);
                free_netdev(slave_dev);
                return NULL;
        }
index 44136297b673a2b2645f481fb723222fa97b951a..519a65452d90c6e77c534f24665065439508b708 100644 (file)
@@ -49,8 +49,8 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/netdevice.h>
+#include <linux/ieee802154.h>
 #include <net/af_ieee802154.h>
-#include <net/ieee802154.h>
 #include <net/ieee802154_netdev.h>
 #include <net/6lowpan.h>
 #include <net/ipv6.h>
 #include "reassembly.h"
 
 static LIST_HEAD(lowpan_devices);
+static int lowpan_open_count;
 
 /* private device info */
 struct lowpan_dev_info {
        struct net_device       *real_dev; /* real WPAN device ptr */
        struct mutex            dev_list_mtx; /* mutex for list ops */
-       __be16                  fragment_tag;
+       u16                     fragment_tag;
 };
 
 struct lowpan_dev_record {
@@ -140,24 +141,33 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb,
        struct sk_buff *skb_cp;
        int stat = NET_RX_SUCCESS;
 
+       skb->protocol = htons(ETH_P_IPV6);
+       skb->pkt_type = PACKET_HOST;
+
        rcu_read_lock();
        list_for_each_entry_rcu(entry, &lowpan_devices, list)
                if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
                        skb_cp = skb_copy(skb, GFP_ATOMIC);
                        if (!skb_cp) {
-                               stat = -ENOMEM;
-                               break;
+                               kfree_skb(skb);
+                               rcu_read_unlock();
+                               return NET_RX_DROP;
                        }
 
                        skb_cp->dev = entry->ldev;
                        stat = netif_rx(skb_cp);
+                       if (stat == NET_RX_DROP)
+                               break;
                }
        rcu_read_unlock();
 
+       consume_skb(skb);
+
        return stat;
 }
 
-static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
+static int
+iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
 {
        u8 iphc0, iphc1;
        struct ieee802154_addr_sa sa, da;
@@ -187,10 +197,9 @@ static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
        else
                dap = &da.hwaddr;
 
-       return lowpan_process_data(skb, skb->dev, sap, sa.addr_type,
-                                  IEEE802154_ADDR_LEN, dap, da.addr_type,
-                                  IEEE802154_ADDR_LEN, iphc0, iphc1,
-                                  lowpan_give_skb_to_devices);
+       return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
+                                       IEEE802154_ADDR_LEN, dap, da.addr_type,
+                                       IEEE802154_ADDR_LEN, iphc0, iphc1);
 
 drop:
        kfree_skb(skb);
@@ -233,7 +242,7 @@ lowpan_alloc_frag(struct sk_buff *skb, int size,
                                     &master_hdr->source, size);
                if (rc < 0) {
                        kfree_skb(frag);
-                       return ERR_PTR(-rc);
+                       return ERR_PTR(rc);
                }
        } else {
                frag = ERR_PTR(-ENOMEM);
@@ -275,7 +284,8 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev,
 
        dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
                     skb->mac_len;
-       frag_tag = lowpan_dev_info(dev)->fragment_tag++;
+       frag_tag = htons(lowpan_dev_info(dev)->fragment_tag);
+       lowpan_dev_info(dev)->fragment_tag++;
 
        frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07);
        frag_hdr[1] = dgram_size & 0xff;
@@ -294,7 +304,7 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev,
                                  frag_len + skb_network_header_len(skb));
        if (rc) {
                pr_debug("%s unable to send FRAG1 packet (tag: %d)",
-                        __func__, frag_tag);
+                        __func__, ntohs(frag_tag));
                goto err;
        }
 
@@ -315,7 +325,7 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev,
                                          frag_len);
                if (rc) {
                        pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n",
-                                __func__, frag_tag, skb_offset);
+                                __func__, ntohs(frag_tag), skb_offset);
                        goto err;
                }
        } while (skb_unprocessed > frag_cap);
@@ -515,6 +525,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
        if (!netif_running(dev))
                goto drop_skb;
 
+       if (skb->pkt_type == PACKET_OTHERHOST)
+               goto drop_skb;
+
        if (dev->type != ARPHRD_IEEE802154)
                goto drop_skb;
 
@@ -523,55 +536,67 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
 
        /* check that it's our buffer */
        if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
-               skb->protocol = htons(ETH_P_IPV6);
-               skb->pkt_type = PACKET_HOST;
-
                /* Pull off the 1-byte of 6lowpan header. */
                skb_pull(skb, 1);
-
-               ret = lowpan_give_skb_to_devices(skb, NULL);
-               if (ret == NET_RX_DROP)
-                       goto drop;
+               return lowpan_give_skb_to_devices(skb, NULL);
        } else {
                switch (skb->data[0] & 0xe0) {
                case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
-                       ret = process_data(skb, &hdr);
-                       if (ret == NET_RX_DROP)
+                       ret = iphc_decompress(skb, &hdr);
+                       if (ret < 0)
                                goto drop;
-                       break;
+
+                       return lowpan_give_skb_to_devices(skb, NULL);
                case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
                        ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
                        if (ret == 1) {
-                               ret = process_data(skb, &hdr);
-                               if (ret == NET_RX_DROP)
+                               ret = iphc_decompress(skb, &hdr);
+                               if (ret < 0)
                                        goto drop;
+
+                               return lowpan_give_skb_to_devices(skb, NULL);
+                       } else if (ret == -1) {
+                               return NET_RX_DROP;
+                       } else {
+                               return NET_RX_SUCCESS;
                        }
-                       break;
                case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
                        ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
                        if (ret == 1) {
-                               ret = process_data(skb, &hdr);
-                               if (ret == NET_RX_DROP)
+                               ret = iphc_decompress(skb, &hdr);
+                               if (ret < 0)
                                        goto drop;
+
+                               return lowpan_give_skb_to_devices(skb, NULL);
+                       } else if (ret == -1) {
+                               return NET_RX_DROP;
+                       } else {
+                               return NET_RX_SUCCESS;
                        }
-                       break;
                default:
                        break;
                }
        }
 
-       return NET_RX_SUCCESS;
 drop_skb:
        kfree_skb(skb);
 drop:
        return NET_RX_DROP;
 }
 
+static struct packet_type lowpan_packet_type = {
+       .type = htons(ETH_P_IEEE802154),
+       .func = lowpan_rcv,
+};
+
 static int lowpan_newlink(struct net *src_net, struct net_device *dev,
                          struct nlattr *tb[], struct nlattr *data[])
 {
        struct net_device *real_dev;
        struct lowpan_dev_record *entry;
+       int ret;
+
+       ASSERT_RTNL();
 
        pr_debug("adding new link\n");
 
@@ -606,9 +631,14 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
        list_add_tail(&entry->list, &lowpan_devices);
        mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
 
-       register_netdevice(dev);
+       ret = register_netdevice(dev);
+       if (ret >= 0) {
+               if (!lowpan_open_count)
+                       dev_add_pack(&lowpan_packet_type);
+               lowpan_open_count++;
+       }
 
-       return 0;
+       return ret;
 }
 
 static void lowpan_dellink(struct net_device *dev, struct list_head *head)
@@ -619,6 +649,10 @@ static void lowpan_dellink(struct net_device *dev, struct list_head *head)
 
        ASSERT_RTNL();
 
+       lowpan_open_count--;
+       if (!lowpan_open_count)
+               dev_remove_pack(&lowpan_packet_type);
+
        mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
        list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
                if (entry->ldev == dev) {
@@ -681,11 +715,6 @@ static struct notifier_block lowpan_dev_notifier = {
        .notifier_call = lowpan_device_event,
 };
 
-static struct packet_type lowpan_packet_type = {
-       .type = htons(ETH_P_IEEE802154),
-       .func = lowpan_rcv,
-};
-
 static int __init lowpan_init_module(void)
 {
        int err = 0;
@@ -698,8 +727,6 @@ static int __init lowpan_init_module(void)
        if (err < 0)
                goto out_frag;
 
-       dev_add_pack(&lowpan_packet_type);
-
        err = register_netdevice_notifier(&lowpan_dev_notifier);
        if (err < 0)
                goto out_pack;
@@ -707,7 +734,6 @@ static int __init lowpan_init_module(void)
        return 0;
 
 out_pack:
-       dev_remove_pack(&lowpan_packet_type);
        lowpan_netlink_fini();
 out_frag:
        lowpan_net_frag_exit();
@@ -719,8 +745,6 @@ static void __exit lowpan_cleanup_module(void)
 {
        lowpan_netlink_fini();
 
-       dev_remove_pack(&lowpan_packet_type);
-
        lowpan_net_frag_exit();
 
        unregister_netdevice_notifier(&lowpan_dev_notifier);
index 3914b1ed42743c50aaa4fe0a40927133cf25dae1..38354d4a70cbe1ac0bcf4b5c8042f5c4a86612a3 100644 (file)
@@ -2,8 +2,8 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
 obj-$(CONFIG_IEEE802154_6LOWPAN) += ieee802154_6lowpan.o
 
 ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o
-ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \
-                header_ops.o
+ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \
+                header_ops.o sysfs.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
 
 ccflags-y += -D__CHECK_ENDIAN__
index 8330a09bfc95e6877351029cff36b542af11c66f..343b63e6f95378ff1ee31cf07706128bb212861a 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
index 29e0de63001b68930f11eab46e6d444a8ee69b96..26da1e179737365b08436f5ec5157bc506f0e05f 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
similarity index 60%
rename from net/ieee802154/wpan-class.c
rename to net/ieee802154/core.c
index 4955e0fe5883ae705edb822b62aab36c93e7e646..620abc2ba5fc89e62c794da0f673b85d957cf3c2 100644 (file)
  * 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-1301 USA.
- *
  */
 
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/device.h>
 
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 
 #include "ieee802154.h"
-
-#define MASTER_SHOW_COMPLEX(name, format_string, args...)              \
-static ssize_t name ## _show(struct device *dev,                       \
-                           struct device_attribute *attr, char *buf)   \
-{                                                                      \
-       struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \
-       int ret;                                                        \
-                                                                       \
-       mutex_lock(&phy->pib_lock);                                     \
-       ret = snprintf(buf, PAGE_SIZE, format_string "\n", args);       \
-       mutex_unlock(&phy->pib_lock);                                   \
-       return ret;                                                     \
-}                                                                      \
-static DEVICE_ATTR_RO(name);
-
-#define MASTER_SHOW(field, format_string)                              \
-       MASTER_SHOW_COMPLEX(field, format_string, phy->field)
-
-MASTER_SHOW(current_channel, "%d");
-MASTER_SHOW(current_page, "%d");
-MASTER_SHOW(transmit_power, "%d +- 1 dB");
-MASTER_SHOW(cca_mode, "%d");
-
-static ssize_t channels_supported_show(struct device *dev,
-                                      struct device_attribute *attr,
-                                      char *buf)
-{
-       struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
-       int ret;
-       int i, len = 0;
-
-       mutex_lock(&phy->pib_lock);
-       for (i = 0; i < 32; i++) {
-               ret = snprintf(buf + len, PAGE_SIZE - len,
-                              "%#09x\n", phy->channels_supported[i]);
-               if (ret < 0)
-                       break;
-               len += ret;
-       }
-       mutex_unlock(&phy->pib_lock);
-       return len;
-}
-static DEVICE_ATTR_RO(channels_supported);
-
-static struct attribute *pmib_attrs[] = {
-       &dev_attr_current_channel.attr,
-       &dev_attr_current_page.attr,
-       &dev_attr_channels_supported.attr,
-       &dev_attr_transmit_power.attr,
-       &dev_attr_cca_mode.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(pmib);
-
-static void wpan_phy_release(struct device *d)
-{
-       struct wpan_phy *phy = container_of(d, struct wpan_phy, dev);
-
-       kfree(phy);
-}
-
-static struct class wpan_phy_class = {
-       .name = "ieee802154",
-       .dev_release = wpan_phy_release,
-       .dev_groups = pmib_groups,
-};
+#include "sysfs.h"
 
 static DEFINE_MUTEX(wpan_phy_mutex);
 static int wpan_phy_idx;
@@ -201,7 +132,7 @@ static int __init wpan_phy_class_init(void)
 {
        int rc;
 
-       rc = class_register(&wpan_phy_class);
+       rc = wpan_phy_sysfs_init();
        if (rc)
                goto err;
 
@@ -211,7 +142,7 @@ static int __init wpan_phy_class_init(void)
 
        return 0;
 err_nl:
-       class_unregister(&wpan_phy_class);
+       wpan_phy_sysfs_exit();
 err:
        return rc;
 }
@@ -220,7 +151,7 @@ subsys_initcall(wpan_phy_class_init);
 static void __exit wpan_phy_class_exit(void)
 {
        ieee802154_nl_exit();
-       class_unregister(&wpan_phy_class);
+       wpan_phy_sysfs_exit();
 }
 module_exit(wpan_phy_class_exit);
 
index fc9193eabd41650290a053a71d11fd0fd2f57e60..b8555ec71387f1c98f2403ee22926cff846225a9 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
@@ -27,9 +23,9 @@
 #include <linux/if_arp.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/ieee802154.h>
 #include <net/sock.h>
 #include <net/af_ieee802154.h>
-#include <net/ieee802154.h>
 #include <net/ieee802154_netdev.h>
 
 #include <asm/ioctls.h>
index c09294e39ca60326d5b40c8431bf202ce5559225..a051b69931779438b33f61456203c451167fa591 100644 (file)
@@ -14,8 +14,9 @@
  * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
  */
 
+#include <linux/ieee802154.h>
+
 #include <net/mac802154.h>
-#include <net/ieee802154.h>
 #include <net/ieee802154_netdev.h>
 
 static int
index 5d352f86979e40b191e08d4bb1d63100560fd1b6..42ae63a345abb83296627c20aadda4239fa7db47 100644 (file)
  * 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-1301 USA.
- *
  */
 #ifndef IEEE_802154_LOCAL_H
 #define IEEE_802154_LOCAL_H
index 9222966f5e6d7438183825ffe306a3c4ab502b10..6c3c2595a201822f18c86b5e9080a640017cbc08 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
index c6bfe22bfa5ebedff765e6dcd4bf7bebd26d0b49..abd0f31bdc665d40145340ec343dad06d47f8a43 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
@@ -26,6 +22,7 @@
 #include <linux/kernel.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
+#include <linux/ieee802154.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
 #include <net/sock.h>
@@ -33,9 +30,8 @@
 #include <linux/export.h>
 #include <net/af_ieee802154.h>
 #include <net/nl802154.h>
-#include <net/ieee802154.h>
 #include <net/ieee802154_netdev.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 
 #include "ieee802154.h"
 
@@ -668,20 +664,6 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info)
 
        phy = ops->get_phy(dev);
 
-       if ((!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
-           (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
-           (!phy->set_cca_ed_level &&
-            info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) ||
-           (!phy->set_csma_params &&
-            (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] ||
-             info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] ||
-             info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])) ||
-           (!phy->set_frame_retries &&
-            info->attrs[IEEE802154_ATTR_FRAME_RETRIES])) {
-               rc = -EOPNOTSUPP;
-               goto out_phy;
-       }
-
        ops->get_mac_params(dev, &params);
 
        if (info->attrs[IEEE802154_ATTR_TXPOWER])
@@ -712,10 +694,9 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info)
 
        wpan_phy_put(phy);
        dev_put(dev);
-       return rc;
 
-out_phy:
-       wpan_phy_put(phy);
+       return 0;
+
 out:
        dev_put(dev);
        return rc;
index 972baf83411af7c64a6f11826ff7b1ab61b43ec4..0afe760ff5126d6e24530236377d6b9e19b71728 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
@@ -27,7 +23,7 @@
 #include <linux/if_arp.h>
 #include <net/netlink.h>
 #include <net/genetlink.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 #include <net/af_ieee802154.h>
 #include <net/ieee802154_netdev.h>
 #include <net/rtnetlink.h> /* for rtnl_{un,}lock */
index 3a703ab88348fc38481ec583ff5d0885ae8c9655..35c4326684548d88f408f84ded46ce6ac2d04ebc 100644 (file)
  * 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-1301 USA.
- *
  */
 
 #include <linux/kernel.h>
index 73a4d53463dec13f6bdf4b318cbc97c0ce1e76d7..21c38945ab8b0b2ddef710b609f58d4ebecaaf5c 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
index 7cfcd6885225b57cb94e1ac51a25baeb76d83380..9d980ed3ffe2c5ed5d1683f9ee1a962751706e21 100644 (file)
@@ -33,7 +33,7 @@
 static const char lowpan_frags_cache_name[] = "lowpan-frags";
 
 struct lowpan_frag_info {
-       __be16 d_tag;
+       u16 d_tag;
        u16 d_size;
        u8 d_offset;
 };
@@ -48,7 +48,7 @@ static struct inet_frags lowpan_frags;
 static int lowpan_frag_reasm(struct lowpan_frag_queue *fq,
                             struct sk_buff *prev, struct net_device *dev);
 
-static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size,
+static unsigned int lowpan_hash_frag(u16 tag, u16 d_size,
                                     const struct ieee802154_addr *saddr,
                                     const struct ieee802154_addr *daddr)
 {
@@ -330,11 +330,13 @@ static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type,
 {
        bool fail;
        u8 pattern = 0, low = 0;
+       __be16 d_tag = 0;
 
        fail = lowpan_fetch_skb(skb, &pattern, 1);
        fail |= lowpan_fetch_skb(skb, &low, 1);
        frag_info->d_size = (pattern & 7) << 8 | low;
-       fail |= lowpan_fetch_skb(skb, &frag_info->d_tag, 2);
+       fail |= lowpan_fetch_skb(skb, &d_tag, 2);
+       frag_info->d_tag = ntohs(d_tag);
 
        if (frag_type == LOWPAN_DISPATCH_FRAGN) {
                fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1);
index 74e4a7c98191109cadf7ae029c7f42602630cbc7..836b16fa001f19852fec7f2890b8ef303d2c0773 100644 (file)
@@ -4,7 +4,7 @@
 #include <net/inet_frag.h>
 
 struct lowpan_create_arg {
-       __be16 tag;
+       u16 tag;
        u16 d_size;
        const struct ieee802154_addr *src;
        const struct ieee802154_addr *dst;
@@ -15,7 +15,7 @@ struct lowpan_create_arg {
 struct lowpan_frag_queue {
        struct inet_frag_queue  q;
 
-       __be16                  tag;
+       u16                     tag;
        u16                     d_size;
        struct ieee802154_addr  saddr;
        struct ieee802154_addr  daddr;
diff --git a/net/ieee802154/sysfs.c b/net/ieee802154/sysfs.c
new file mode 100644 (file)
index 0000000..eb9ca6f
--- /dev/null
@@ -0,0 +1,94 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ *
+ * Authors:
+ * Alexander Aring <aar@pengutronix.de>
+ *
+ * Based on: net/wireless/sysfs.c
+ */
+
+#include <linux/device.h>
+
+#include <net/cfg802154.h>
+
+#define MASTER_SHOW_COMPLEX(name, format_string, args...)              \
+static ssize_t name ## _show(struct device *dev,                       \
+                           struct device_attribute *attr, char *buf)   \
+{                                                                      \
+       struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \
+       int ret;                                                        \
+                                                                       \
+       mutex_lock(&phy->pib_lock);                                     \
+       ret = snprintf(buf, PAGE_SIZE, format_string "\n", args);       \
+       mutex_unlock(&phy->pib_lock);                                   \
+       return ret;                                                     \
+}                                                                      \
+static DEVICE_ATTR_RO(name)
+
+#define MASTER_SHOW(field, format_string)                              \
+       MASTER_SHOW_COMPLEX(field, format_string, phy->field)
+
+MASTER_SHOW(current_channel, "%d");
+MASTER_SHOW(current_page, "%d");
+MASTER_SHOW(transmit_power, "%d +- 1 dB");
+MASTER_SHOW(cca_mode, "%d");
+
+static ssize_t channels_supported_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buf)
+{
+       struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev);
+       int ret;
+       int i, len = 0;
+
+       mutex_lock(&phy->pib_lock);
+       for (i = 0; i < 32; i++) {
+               ret = snprintf(buf + len, PAGE_SIZE - len,
+                              "%#09x\n", phy->channels_supported[i]);
+               if (ret < 0)
+                       break;
+               len += ret;
+       }
+       mutex_unlock(&phy->pib_lock);
+       return len;
+}
+static DEVICE_ATTR_RO(channels_supported);
+
+static void wpan_phy_release(struct device *d)
+{
+       struct wpan_phy *phy = container_of(d, struct wpan_phy, dev);
+
+       kfree(phy);
+}
+
+static struct attribute *pmib_attrs[] = {
+       &dev_attr_current_channel.attr,
+       &dev_attr_current_page.attr,
+       &dev_attr_channels_supported.attr,
+       &dev_attr_transmit_power.attr,
+       &dev_attr_cca_mode.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(pmib);
+
+struct class wpan_phy_class = {
+       .name = "ieee802154",
+       .dev_release = wpan_phy_release,
+       .dev_groups = pmib_groups,
+};
+
+int wpan_phy_sysfs_init(void)
+{
+       return class_register(&wpan_phy_class);
+}
+
+void wpan_phy_sysfs_exit(void)
+{
+       class_unregister(&wpan_phy_class);
+}
diff --git a/net/ieee802154/sysfs.h b/net/ieee802154/sysfs.h
new file mode 100644 (file)
index 0000000..aa42e39
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __IEEE802154_SYSFS_H
+#define __IEEE802154_SYSFS_H
+
+int wpan_phy_sysfs_init(void);
+void wpan_phy_sysfs_exit(void);
+
+extern struct class wpan_phy_class;
+
+#endif /* __IEEE802154_SYSFS_H */
index ee8fa4bf3b734d051330b38bc1fa029bcd392774..43385a9fa44196bd54be66416413c5c7eb03057a 100644 (file)
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/compat.h>
+#include <linux/uio.h>
+
+struct raw_frag_vec {
+       struct iovec *iov;
+       union {
+               struct icmphdr icmph;
+               char c[1];
+       } hdr;
+       int hlen;
+};
 
 static struct raw_hashinfo raw_v4_hashinfo = {
        .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
@@ -420,53 +430,57 @@ error:
        return err;
 }
 
-static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg)
+static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
 {
-       struct iovec *iov;
-       u8 __user *type = NULL;
-       u8 __user *code = NULL;
-       int probed = 0;
-       unsigned int i;
+       int err;
 
-       if (!msg->msg_iov)
+       if (fl4->flowi4_proto != IPPROTO_ICMP)
                return 0;
 
-       for (i = 0; i < msg->msg_iovlen; i++) {
-               iov = &msg->msg_iov[i];
-               if (!iov)
-                       continue;
-
-               switch (fl4->flowi4_proto) {
-               case IPPROTO_ICMP:
-                       /* check if one-byte field is readable or not. */
-                       if (iov->iov_base && iov->iov_len < 1)
-                               break;
-
-                       if (!type) {
-                               type = iov->iov_base;
-                               /* check if code field is readable or not. */
-                               if (iov->iov_len > 1)
-                                       code = type + 1;
-                       } else if (!code)
-                               code = iov->iov_base;
-
-                       if (type && code) {
-                               if (get_user(fl4->fl4_icmp_type, type) ||
-                                   get_user(fl4->fl4_icmp_code, code))
-                                       return -EFAULT;
-                               probed = 1;
-                       }
-                       break;
-               default:
-                       probed = 1;
-                       break;
-               }
-               if (probed)
-                       break;
-       }
+       /* We only need the first two bytes. */
+       rfv->hlen = 2;
+
+       err = memcpy_fromiovec(rfv->hdr.c, rfv->iov, rfv->hlen);
+       if (err)
+               return err;
+
+       fl4->fl4_icmp_type = rfv->hdr.icmph.type;
+       fl4->fl4_icmp_code = rfv->hdr.icmph.code;
+
        return 0;
 }
 
+static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
+                      struct sk_buff *skb)
+{
+       struct raw_frag_vec *rfv = from;
+
+       if (offset < rfv->hlen) {
+               int copy = min(rfv->hlen - offset, len);
+
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       memcpy(to, rfv->hdr.c + offset, copy);
+               else
+                       skb->csum = csum_block_add(
+                               skb->csum,
+                               csum_partial_copy_nocheck(rfv->hdr.c + offset,
+                                                         to, copy, 0),
+                               odd);
+
+               odd = 0;
+               offset += copy;
+               to += copy;
+               len -= copy;
+
+               if (!len)
+                       return 0;
+       }
+
+       offset -= rfv->hlen;
+
+       return ip_generic_getfrag(rfv->iov, to, offset, len, odd, skb);
+}
+
 static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                       size_t len)
 {
@@ -480,6 +494,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        u8  tos;
        int err;
        struct ip_options_data opt_copy;
+       struct raw_frag_vec rfv;
 
        err = -EMSGSIZE;
        if (len > 0xFFFF)
@@ -585,7 +600,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                           daddr, saddr, 0, 0);
 
        if (!inet->hdrincl) {
-               err = raw_probe_proto_opt(&fl4, msg);
+               rfv.iov = msg->msg_iov;
+               rfv.hlen = 0;
+
+               err = raw_probe_proto_opt(&rfv, &fl4);
                if (err)
                        goto done;
        }
@@ -616,8 +634,8 @@ back_from_confirm:
                if (!ipc.addr)
                        ipc.addr = fl4.daddr;
                lock_sock(sk);
-               err = ip_append_data(sk, &fl4, ip_generic_getfrag,
-                                    msg->msg_iov, len, 0,
+               err = ip_append_data(sk, &fl4, raw_getfrag,
+                                    &rfv, len, 0,
                                     &ipc, &rt, msg->msg_flags);
                if (err)
                        ip_flush_pending_frames(sk);
index 9c7d7621466b1241f404a5ca11de809dcff2d02a..2c6a955fd5c32bf102534a6d4f8a661cf5641331 100644 (file)
@@ -1429,6 +1429,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                struct dst_entry *dst = sk->sk_rx_dst;
 
                sock_rps_save_rxhash(sk, skb);
+               sk_mark_napi_id(sk, skb);
                if (dst) {
                        if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
                            dst->ops->check(dst, 0) == NULL) {
@@ -1450,6 +1451,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 
                if (nsk != sk) {
                        sock_rps_save_rxhash(nsk, skb);
+                       sk_mark_napi_id(sk, skb);
                        if (tcp_child_process(sk, nsk, skb)) {
                                rsk = nsk;
                                goto reset;
@@ -1661,7 +1663,7 @@ process:
        if (sk_filter(sk, skb))
                goto discard_and_relse;
 
-       sk_mark_napi_id(sk, skb);
+       sk_incoming_cpu_update(sk);
        skb->dev = NULL;
 
        bh_lock_sock_nested(sk);
index 5d0fdca8e965c0361b757f8d85cfb26b91ea11b7..d13751685f44a734707ff4d6fca1881dd7ad3833 100644 (file)
@@ -1445,6 +1445,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (inet_sk(sk)->inet_daddr) {
                sock_rps_save_rxhash(sk, skb);
                sk_mark_napi_id(sk, skb);
+               sk_incoming_cpu_update(sk);
        }
 
        rc = sock_queue_rcv_skb(sk, skb);
index ace29b60813cf8a1d7182ad2262cbcbd21810fa7..1985b4933a6bbc6a24ae502f601afac29896fab8 100644 (file)
@@ -1293,6 +1293,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                struct dst_entry *dst = sk->sk_rx_dst;
 
                sock_rps_save_rxhash(sk, skb);
+               sk_mark_napi_id(sk, skb);
                if (dst) {
                        if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
                            dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
@@ -1322,6 +1323,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                 */
                if (nsk != sk) {
                        sock_rps_save_rxhash(nsk, skb);
+                       sk_mark_napi_id(sk, skb);
                        if (tcp_child_process(sk, nsk, skb))
                                goto reset;
                        if (opt_skb)
@@ -1454,7 +1456,7 @@ process:
        if (sk_filter(sk, skb))
                goto discard_and_relse;
 
-       sk_mark_napi_id(sk, skb);
+       sk_incoming_cpu_update(sk);
        skb->dev = NULL;
 
        bh_lock_sock_nested(sk);
index b756355e9739b38b86d4adc1aa492be52f6806e9..d1fe362749063516b80d0700d48b272d24a8c417 100644 (file)
@@ -577,6 +577,7 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (!ipv6_addr_any(&sk->sk_v6_daddr)) {
                sock_rps_save_rxhash(sk, skb);
                sk_mark_napi_id(sk, skb);
+               sk_incoming_cpu_update(sk);
        }
 
        rc = sock_queue_rcv_skb(sk, skb);
index aeb6a483b3bc881e4b45c6dad7aacc9ae57bde37..75cc6801a4316dbeb25958192f018b8808681096 100644 (file)
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL_HT
        ---help---
          This option enables the 'minstrel_ht' TX rate control algorithm
 
+config MAC80211_RC_MINSTREL_VHT
+       bool "Minstrel 802.11ac support" if EXPERT
+       depends on MAC80211_RC_MINSTREL_HT
+       default n
+       ---help---
+         This option enables VHT in the 'minstrel_ht' TX rate control algorithm
+
 choice
        prompt "Default rate control algorithm"
        depends on MAC80211_HAS_RC
@@ -169,6 +176,17 @@ config MAC80211_HT_DEBUG
 
          Do not select this option.
 
+config MAC80211_OCB_DEBUG
+       bool "Verbose OCB debugging"
+       depends on MAC80211_DEBUG_MENU
+       ---help---
+         Selecting this option causes mac80211 to print out
+         very verbose OCB debugging messages. It should not
+         be selected on production systems as those messages
+         are remotely triggerable.
+
+         Do not select this option.
+
 config MAC80211_IBSS_DEBUG
        bool "Verbose IBSS debugging"
        depends on MAC80211_DEBUG_MENU
index 7273d2796dd1a79e4a529bb38a69a7722a7dec3e..e53671b1105e039ad95fadc8c3f96fd090550cc3 100644 (file)
@@ -27,7 +27,8 @@ mac80211-y := \
        event.o \
        chan.o \
        trace.o mlme.o \
-       tdls.o
+       tdls.o \
+       ocb.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
index d6986f3aa5c469fa15dfbc585d72ec0b5cc53af4..9242c60048cf960ef30e988ee87f4d870e6f95ab 100644 (file)
@@ -149,11 +149,6 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
        rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
 }
 
-static inline int ieee80211_ac_from_tid(int tid)
-{
-       return ieee802_1d_to_ac[tid & 7];
-}
-
 /*
  * When multiple aggregation sessions on multiple stations
  * are being created/destroyed simultaneously, we need to
index 343da1e35025199bbef7d6680e0770fbdc3eadd2..06185940cbb66a3abf35230ce92b03c7716248a1 100644 (file)
@@ -20,6 +20,7 @@
 #include "cfg.h"
 #include "rate.h"
 #include "mesh.h"
+#include "wme.h"
 
 static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
                                                const char *name,
@@ -190,7 +191,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                 * receive the key. When wpa_supplicant has roamed
                 * using FT, it attempts to set the key before
                 * association has completed, this rejects that attempt
-                * so it will set the key again after assocation.
+                * so it will set the key again after association.
                 *
                 * TODO: accept the key if we have a station entry and
                 *       add it to the device after the station.
@@ -229,6 +230,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        case NUM_NL80211_IFTYPES:
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_OCB:
                /* shouldn't happen */
                WARN_ON_ONCE(1);
                break;
@@ -1225,14 +1227,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
-                                const u8 *mac)
+                                struct station_del_parameters *params)
 {
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (mac)
-               return sta_info_destroy_addr_bss(sdata, mac);
+       if (params->mac)
+               return sta_info_destroy_addr_bss(sdata, params->mac);
 
        sta_info_flush(sdata);
        return 0;
@@ -1516,6 +1518,57 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static void mpp_set_pinfo(struct mesh_path *mpath, u8 *mpp,
+                         struct mpath_info *pinfo)
+{
+       memset(pinfo, 0, sizeof(*pinfo));
+       memcpy(mpp, mpath->mpp, ETH_ALEN);
+
+       pinfo->generation = mpp_paths_generation;
+}
+
+static int ieee80211_get_mpp(struct wiphy *wiphy, struct net_device *dev,
+                            u8 *dst, u8 *mpp, struct mpath_info *pinfo)
+
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup(sdata, dst);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int ieee80211_dump_mpp(struct wiphy *wiphy, struct net_device *dev,
+                             int idx, u8 *dst, u8 *mpp,
+                             struct mpath_info *pinfo)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct mesh_path *mpath;
+
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       rcu_read_lock();
+       mpath = mpp_path_lookup_by_idx(sdata, idx);
+       if (!mpath) {
+               rcu_read_unlock();
+               return -ENOENT;
+       }
+       memcpy(dst, mpath->dst, ETH_ALEN);
+       mpp_set_pinfo(mpath, mpp, pinfo);
+       rcu_read_unlock();
+       return 0;
+}
+
 static int ieee80211_get_mesh_config(struct wiphy *wiphy,
                                struct net_device *dev,
                                struct mesh_config *conf)
@@ -1966,6 +2019,17 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
 }
 
+static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev,
+                             struct ocb_setup *setup)
+{
+       return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup);
+}
+
+static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev)
+{
+       return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev));
+}
+
 static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
                                    int rate[IEEE80211_NUM_BANDS])
 {
@@ -2081,6 +2145,9 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy,
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
+       if (local->ops->get_txpower)
+               return drv_get_txpower(local, sdata, dbm);
+
        if (!local->use_chanctx)
                *dbm = local->hw.conf.power_level;
        else
@@ -2850,11 +2917,7 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                if (sdata->reserved_ready)
                        return 0;
 
-               err = ieee80211_vif_use_reserved_context(sdata);
-               if (err)
-                       return err;
-
-               return 0;
+               return ieee80211_vif_use_reserved_context(sdata);
        }
 
        if (!cfg80211_chandef_identical(&sdata->vif.bss_conf.chandef,
@@ -2868,7 +2931,6 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                return err;
 
        ieee80211_bss_info_change_notify(sdata, changed);
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
 
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
@@ -2876,6 +2938,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_sub_if_data *sdata)
                sdata->csa_block_tx = false;
        }
 
+       err = drv_post_channel_switch(sdata);
+       if (err)
+               return err;
+
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);
+
        return 0;
 }
 
@@ -3053,9 +3121,11 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel_switch ch_switch;
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *chanctx;
-       int err, changed = 0;
+       u32 changed = 0;
+       int err;
 
        sdata_assert_lock(sdata);
        lockdep_assert_held(&local->mtx);
@@ -3088,6 +3158,10 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       err = drv_pre_channel_switch(sdata, &ch_switch);
+       if (err)
+               goto out;
+
        err = ieee80211_vif_reserve_chanctx(sdata, &params->chandef,
                                            chanctx->mode,
                                            params->radar_required);
@@ -3101,6 +3175,12 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                goto out;
        }
 
+       ch_switch.timestamp = 0;
+       ch_switch.device_timestamp = 0;
+       ch_switch.block_tx = params->block_tx;
+       ch_switch.chandef = params->chandef;
+       ch_switch.count = params->count;
+
        err = ieee80211_set_csa_beacon(sdata, params, &changed);
        if (err) {
                ieee80211_vif_unreserve_chanctx(sdata);
@@ -3521,6 +3601,76 @@ static int ieee80211_set_ap_chanwidth(struct wiphy *wiphy,
        return ret;
 }
 
+static int ieee80211_add_tx_ts(struct wiphy *wiphy, struct net_device *dev,
+                              u8 tsid, const u8 *peer, u8 up,
+                              u16 admitted_time)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       int ac = ieee802_1d_to_ac[up];
+
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               return -EOPNOTSUPP;
+
+       if (!(sdata->wmm_acm & BIT(up)))
+               return -EINVAL;
+
+       if (ifmgd->tx_tspec[ac].admitted_time)
+               return -EBUSY;
+
+       if (admitted_time) {
+               ifmgd->tx_tspec[ac].admitted_time = 32 * admitted_time;
+               ifmgd->tx_tspec[ac].tsid = tsid;
+               ifmgd->tx_tspec[ac].up = up;
+       }
+
+       return 0;
+}
+
+static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
+                              u8 tsid, const u8 *peer)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       int ac;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+
+               /* skip unused entries */
+               if (!tx_tspec->admitted_time)
+                       continue;
+
+               if (tx_tspec->tsid != tsid)
+                       continue;
+
+               /* due to this new packets will be reassigned to non-ACM ACs */
+               tx_tspec->up = -1;
+
+               /* Make sure that all packets have been sent to avoid to
+                * restore the QoS params on packets that are still on the
+                * queues.
+                */
+               synchronize_net();
+               ieee80211_flush_queues(local, sdata);
+
+               /* restore the normal QoS parameters
+                * (unconditionally to avoid races)
+                */
+               tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
+               tx_tspec->downgraded = false;
+               ieee80211_sta_handle_tspec_ac_params(sdata);
+
+               /* finally clear all the data */
+               memset(tx_tspec, 0, sizeof(*tx_tspec));
+
+               return 0;
+       }
+
+       return -ENOENT;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -3547,11 +3697,15 @@ const struct cfg80211_ops mac80211_config_ops = {
        .change_mpath = ieee80211_change_mpath,
        .get_mpath = ieee80211_get_mpath,
        .dump_mpath = ieee80211_dump_mpath,
+       .get_mpp = ieee80211_get_mpp,
+       .dump_mpp = ieee80211_dump_mpp,
        .update_mesh_config = ieee80211_update_mesh_config,
        .get_mesh_config = ieee80211_get_mesh_config,
        .join_mesh = ieee80211_join_mesh,
        .leave_mesh = ieee80211_leave_mesh,
 #endif
+       .join_ocb = ieee80211_join_ocb,
+       .leave_ocb = ieee80211_leave_ocb,
        .change_bss = ieee80211_change_bss,
        .set_txq_params = ieee80211_set_txq_params,
        .set_monitor_channel = ieee80211_set_monitor_channel,
@@ -3597,4 +3751,6 @@ const struct cfg80211_ops mac80211_config_ops = {
        .channel_switch = ieee80211_channel_switch,
        .set_qos_map = ieee80211_set_qos_map,
        .set_ap_chanwidth = ieee80211_set_ap_chanwidth,
+       .add_tx_ts = ieee80211_add_tx_ts,
+       .del_tx_ts = ieee80211_del_tx_ts,
 };
index 4c74e8da64b909cc36befe4c5ecb29af5ff7629e..c7c51422029822269762e40527a7ad44ddcbe991 100644 (file)
@@ -270,6 +270,7 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_WDS:
                case NL80211_IFTYPE_MESH_POINT:
+               case NL80211_IFTYPE_OCB:
                        width = vif->bss_conf.chandef.width;
                        break;
                case NL80211_IFTYPE_UNSPECIFIED:
@@ -674,6 +675,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_WDS:
                case NL80211_IFTYPE_MESH_POINT:
+               case NL80211_IFTYPE_OCB:
                        break;
                default:
                        WARN_ON_ONCE(1);
@@ -909,6 +911,7 @@ ieee80211_vif_chanctx_reservation_complete(struct ieee80211_sub_if_data *sdata)
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_MESH_POINT:
+       case NL80211_IFTYPE_OCB:
                ieee80211_queue_work(&sdata->local->hw,
                                     &sdata->csa_finalize_work);
                break;
@@ -1634,7 +1637,7 @@ int ieee80211_vif_change_bandwidth(struct ieee80211_sub_if_data *sdata,
                }
                break;
        case IEEE80211_CHANCTX_WILL_BE_REPLACED:
-               /* TODO: Perhaps the bandwith change could be treated as a
+               /* TODO: Perhaps the bandwidth change could be treated as a
                 * reservation itself? */
                ret = -EBUSY;
                goto out;
index 493d68061f0c2717d8828809e8ec27d87d6d08b6..1956b3115dd5916283a613701cf799108292b7c7 100644 (file)
@@ -2,6 +2,12 @@
 #define __MAC80211_DEBUG_H
 #include <net/cfg80211.h>
 
+#ifdef CONFIG_MAC80211_OCB_DEBUG
+#define MAC80211_OCB_DEBUG 1
+#else
+#define MAC80211_OCB_DEBUG 0
+#endif
+
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
 #define MAC80211_IBSS_DEBUG 1
 #else
@@ -131,6 +137,10 @@ do {                                                                       \
        _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(),                \
                   sdata, fmt, ##__VA_ARGS__)
 
+#define ocb_dbg(sdata, fmt, ...)                                       \
+       _sdata_dbg(MAC80211_OCB_DEBUG,                                  \
+                  sdata, fmt, ##__VA_ARGS__)
+
 #define ibss_dbg(sdata, fmt, ...)                                      \
        _sdata_dbg(MAC80211_IBSS_DEBUG,                                 \
                   sdata, fmt, ##__VA_ARGS__)
index 1521cabad3d6d0f246acfc37b7512a489f14965a..5523b94c7c908f89e7d489903f486a99d738e7d3 100644 (file)
@@ -300,10 +300,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
 
        lockdep_assert_held(&sdata->local->key_mtx);
 
-       if (sdata->debugfs.default_unicast_key) {
-               debugfs_remove(sdata->debugfs.default_unicast_key);
-               sdata->debugfs.default_unicast_key = NULL;
-       }
+       debugfs_remove(sdata->debugfs.default_unicast_key);
+       sdata->debugfs.default_unicast_key = NULL;
 
        if (sdata->default_unicast_key) {
                key = key_mtx_dereference(sdata->local,
@@ -314,10 +312,8 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata)
                                               sdata->vif.debugfs_dir, buf);
        }
 
-       if (sdata->debugfs.default_multicast_key) {
-               debugfs_remove(sdata->debugfs.default_multicast_key);
-               sdata->debugfs.default_multicast_key = NULL;
-       }
+       debugfs_remove(sdata->debugfs.default_multicast_key);
+       sdata->debugfs.default_multicast_key = NULL;
 
        if (sdata->default_multicast_key) {
                key = key_mtx_dereference(sdata->local,
index 196d48c68134a08b644fc97f8f1a1fc740ec7bdf..9759dd1f0734000337790aabca58066d411a80be 100644 (file)
@@ -214,7 +214,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
                                    BSS_CHANGED_BEACON_ENABLED) &&
                         sdata->vif.type != NL80211_IFTYPE_AP &&
                         sdata->vif.type != NL80211_IFTYPE_ADHOC &&
-                        sdata->vif.type != NL80211_IFTYPE_MESH_POINT))
+                        sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+                        sdata->vif.type != NL80211_IFTYPE_OCB))
                return;
 
        if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
@@ -631,6 +632,12 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
        if (!check_sdata_in_driver(sdata))
                return -EIO;
 
+       if (WARN_ONCE(params->cw_min == 0 ||
+                     params->cw_min > params->cw_max,
+                     "%s: invalid CW_min/CW_max: %d/%d\n",
+                     sdata->name, params->cw_min, params->cw_max))
+               return -EINVAL;
+
        trace_drv_conf_tx(local, sdata, ac, params);
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, &sdata->vif,
@@ -764,12 +771,13 @@ static inline void drv_flush(struct ieee80211_local *local,
 }
 
 static inline void drv_channel_switch(struct ieee80211_local *local,
-                                    struct ieee80211_channel_switch *ch_switch)
+                                     struct ieee80211_sub_if_data *sdata,
+                                     struct ieee80211_channel_switch *ch_switch)
 {
        might_sleep();
 
-       trace_drv_channel_switch(local, ch_switch);
-       local->ops->channel_switch(&local->hw, ch_switch);
+       trace_drv_channel_switch(local, sdata, ch_switch);
+       local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch);
        trace_drv_return_void(local);
 }
 
@@ -1144,13 +1152,15 @@ static inline void drv_stop_ap(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
-static inline void drv_restart_complete(struct ieee80211_local *local)
+static inline void
+drv_reconfig_complete(struct ieee80211_local *local,
+                     enum ieee80211_reconfig_type reconfig_type)
 {
        might_sleep();
 
-       trace_drv_restart_complete(local);
-       if (local->ops->restart_complete)
-               local->ops->restart_complete(&local->hw);
+       trace_drv_reconfig_complete(local, reconfig_type);
+       if (local->ops->reconfig_complete)
+               local->ops->reconfig_complete(&local->hw, reconfig_type);
        trace_drv_return_void(local);
 }
 
@@ -1196,6 +1206,40 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
        }
 }
 
+static inline int
+drv_pre_channel_switch(struct ieee80211_sub_if_data *sdata,
+                      struct ieee80211_channel_switch *ch_switch)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret = 0;
+
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       trace_drv_pre_channel_switch(local, sdata, ch_switch);
+       if (local->ops->pre_channel_switch)
+               ret = local->ops->pre_channel_switch(&local->hw, &sdata->vif,
+                                                    ch_switch);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+static inline int
+drv_post_channel_switch(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       int ret = 0;
+
+       if (!check_sdata_in_driver(sdata))
+               return -EIO;
+
+       trace_drv_post_channel_switch(local, sdata);
+       if (local->ops->post_channel_switch)
+               ret = local->ops->post_channel_switch(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
 static inline int drv_join_ibss(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata)
 {
@@ -1238,4 +1282,18 @@ static inline u32 drv_get_expected_throughput(struct ieee80211_local *local,
        return ret;
 }
 
+static inline int drv_get_txpower(struct ieee80211_local *local,
+                                 struct ieee80211_sub_if_data *sdata, int *dbm)
+{
+       int ret;
+
+       if (!local->ops->get_txpower)
+               return -EOPNOTSUPP;
+
+       ret = local->ops->get_txpower(&local->hw, &sdata->vif, dbm);
+       trace_drv_get_txpower(local, sdata, *dbm, ret);
+
+       return ret;
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index c2aaec4dfcf0ea38da3e45cfdc7b8ad0ecef5fc8..a51c993ece7346ed27a40b69fd994d0b6b22fc2a 100644 (file)
@@ -131,7 +131,7 @@ enum ieee80211_bss_corrupt_data_flags {
  *
  * These are bss flags that are attached to a bss in the
  * @valid_data field of &struct ieee80211_bss.  They show which parts
- * of the data structure were recieved as a result of an un-corrupted
+ * of the data structure were received as a result of an un-corrupted
  * beacon/probe response.
  */
 enum ieee80211_bss_valid_data_flags {
@@ -399,6 +399,24 @@ struct ieee80211_mgd_assoc_data {
        u8 ie[];
 };
 
+struct ieee80211_sta_tx_tspec {
+       /* timestamp of the first packet in the time slice */
+       unsigned long time_slice_start;
+
+       u32 admitted_time; /* in usecs, unlike over the air */
+       u8 tsid;
+       s8 up; /* signed to be able to invalidate with -1 during teardown */
+
+       /* consumed TX time in microseconds in the time slice */
+       u32 consumed_tx_time;
+       enum {
+               TX_TSPEC_ACTION_NONE = 0,
+               TX_TSPEC_ACTION_DOWNGRADE,
+               TX_TSPEC_ACTION_STOP_DOWNGRADE,
+       } action;
+       bool downgraded;
+};
+
 struct ieee80211_if_managed {
        struct timer_list timer;
        struct timer_list conn_mon_timer;
@@ -434,6 +452,8 @@ struct ieee80211_if_managed {
 
        unsigned int flags;
 
+       bool csa_waiting_bcn;
+
        bool beacon_crc_valid;
        u32 beacon_crc;
 
@@ -507,6 +527,16 @@ struct ieee80211_if_managed {
 
        u8 tdls_peer[ETH_ALEN] __aligned(2);
        struct delayed_work tdls_peer_del_work;
+
+       /* WMM-AC TSPEC support */
+       struct ieee80211_sta_tx_tspec tx_tspec[IEEE80211_NUM_ACS];
+       /* Use a separate work struct so that we can do something here
+        * while the sdata->work is flushing the queues, for example.
+        * otherwise, in scenarios where we hardly get any traffic out
+        * on the BE queue, but there's a lot of VO traffic, we might
+        * get stuck in a downgraded situation and flush takes forever.
+        */
+       struct delayed_work tx_tspec_wk;
 };
 
 struct ieee80211_if_ibss {
@@ -546,6 +576,25 @@ struct ieee80211_if_ibss {
        } state;
 };
 
+/**
+ * struct ieee80211_if_ocb - OCB mode state
+ *
+ * @housekeeping_timer: timer for periodic invocation of a housekeeping task
+ * @wrkq_flags: OCB deferred task action
+ * @incomplete_lock: delayed STA insertion lock
+ * @incomplete_stations: list of STAs waiting for delayed insertion
+ * @joined: indication if the interface is connected to an OCB network
+ */
+struct ieee80211_if_ocb {
+       struct timer_list housekeeping_timer;
+       unsigned long wrkq_flags;
+
+       spinlock_t incomplete_lock;
+       struct list_head incomplete_stations;
+
+       bool joined;
+};
+
 /**
  * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface
  *
@@ -839,6 +888,7 @@ struct ieee80211_sub_if_data {
                struct ieee80211_if_managed mgd;
                struct ieee80211_if_ibss ibss;
                struct ieee80211_if_mesh mesh;
+               struct ieee80211_if_ocb ocb;
                u32 mntr_flags;
        } u;
 
@@ -1307,6 +1357,9 @@ struct ieee80211_local {
        /* virtual monitor interface */
        struct ieee80211_sub_if_data __rcu *monitor_sdata;
        struct cfg80211_chan_def monitor_chandef;
+
+       /* extended capabilities provided by mac80211 */
+       u8 ext_capa[8];
 };
 
 static inline struct ieee80211_sub_if_data *
@@ -1454,6 +1507,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
                                  __le16 fc, bool acked);
 void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata);
 
 /* IBSS code */
 void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -1471,6 +1525,15 @@ int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
 int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
 
+/* OCB code */
+void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
+                            const u8 *bssid, const u8 *addr, u32 supp_rates);
+void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata);
+int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
+                      struct ocb_setup *setup);
+int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata);
+
 /* mesh code */
 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
@@ -1758,6 +1821,13 @@ static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames)
        return true;
 }
 
+extern const int ieee802_1d_to_ac[8];
+
+static inline int ieee80211_ac_from_tid(int tid)
+{
+       return ieee802_1d_to_ac[tid & 7];
+}
+
 void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
 void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
 void ieee80211_dynamic_ps_timer(unsigned long data);
@@ -1767,7 +1837,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_hdr *hdr);
 void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
-                            struct ieee80211_hdr *hdr, bool ack);
+                            struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
 
 void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
                                     unsigned long queues,
@@ -1833,8 +1903,10 @@ int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
 void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
 void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);
 
-size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
-                         const u8 *ids, int n_ids, size_t offset);
+size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
+                             const u8 *ids, int n_ids,
+                             const u8 *after_ric, int n_after_ric,
+                             size_t offset);
 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
 u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
                              u16 cap);
index af237223a8cd9bd3aa6121576650238d42e3bbb0..6b631c049eba0b8c7b877296987ff04413b867f9 100644 (file)
@@ -258,6 +258,15 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
                if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
+                       /*
+                        * Only OCB and monitor mode may coexist
+                        */
+                       if ((sdata->vif.type == NL80211_IFTYPE_OCB &&
+                            nsdata->vif.type != NL80211_IFTYPE_MONITOR) ||
+                           (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+                            nsdata->vif.type == NL80211_IFTYPE_OCB))
+                               return -EBUSY;
+
                        /*
                         * Allow only a single IBSS interface to be up at any
                         * time. This is restricted because beacon distribution
@@ -521,6 +530,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_P2P_DEVICE:
+       case NL80211_IFTYPE_OCB:
                /* no special treatment */
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
@@ -631,6 +641,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_MESH_POINT:
+               case NL80211_IFTYPE_OCB:
                        netif_carrier_off(dev);
                        break;
                case NL80211_IFTYPE_WDS:
@@ -842,6 +853,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        sdata_lock(sdata);
        mutex_lock(&local->mtx);
        sdata->vif.csa_active = false;
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               sdata->u.mgd.csa_waiting_bcn = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1279,6 +1292,9 @@ static void ieee80211_iface_work(struct work_struct *work)
                        break;
                ieee80211_mesh_work(sdata);
                break;
+       case NL80211_IFTYPE_OCB:
+               ieee80211_ocb_work(sdata);
+               break;
        default:
                break;
        }
@@ -1298,6 +1314,9 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
 static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                                  enum nl80211_iftype type)
 {
+       static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff,
+                                                   0xff, 0xff, 0xff};
+
        /* clear type-dependent union */
        memset(&sdata->u, 0, sizeof(sdata->u));
 
@@ -1349,6 +1368,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
                ieee80211_sta_setup_sdata(sdata);
                break;
+       case NL80211_IFTYPE_OCB:
+               sdata->vif.bss_conf.bssid = bssid_wildcard;
+               ieee80211_ocb_setup_sdata(sdata);
+               break;
        case NL80211_IFTYPE_ADHOC:
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
                ieee80211_ibss_setup_sdata(sdata);
@@ -1396,6 +1419,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_OCB:
                /*
                 * Could maybe also all others here?
                 * Just not sure how that interacts
@@ -1411,6 +1435,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_OCB:
                /*
                 * Could probably support everything
                 * but WDS here (WDS do_open can fail
@@ -1669,7 +1694,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                }
 
                ieee80211_assign_perm_addr(local, ndev->perm_addr, type);
-               memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
+               if (params && is_valid_ether_addr(params->macaddr))
+                       memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN);
+               else
+                       memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
                SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
 
                /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */
index 4712150dc2109df0b6f17162da8ec5119a94ec0a..434a91ad12c88dabcc2674413e86d08386c3b37d 100644 (file)
@@ -94,8 +94,17 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        might_sleep();
 
-       if (key->flags & KEY_FLAG_TAINTED)
+       if (key->flags & KEY_FLAG_TAINTED) {
+               /* If we get here, it's during resume and the key is
+                * tainted so shouldn't be used/programmed any more.
+                * However, its flags may still indicate that it was
+                * programmed into the device (since we're in resume)
+                * so clear that flag now to avoid trying to remove
+                * it again later.
+                */
+               key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
                return -EINVAL;
+       }
 
        if (!key->local->ops->set_key)
                goto out_unsupported;
index 0de7c93bf62b5a3352de711ab9deeaa21649d8a1..282a4f36eb924f1fc51ebb75726d87eeaee2e38f 100644 (file)
@@ -478,13 +478,9 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
        },
 };
 
-static const u8 extended_capabilities[] = {
-       0, 0, 0, 0, 0, 0, 0,
-       WLAN_EXT_CAPA8_OPMODE_NOTIF,
-};
-
-struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
-                                       const struct ieee80211_ops *ops)
+struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
+                                          const struct ieee80211_ops *ops,
+                                          const char *requested_name)
 {
        struct ieee80211_local *local;
        int priv_size, i;
@@ -524,7 +520,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
         */
        priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
 
-       wiphy = wiphy_new(&mac80211_config_ops, priv_size);
+       wiphy = wiphy_new_nm(&mac80211_config_ops, priv_size, requested_name);
 
        if (!wiphy)
                return NULL;
@@ -539,10 +535,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                        WIPHY_FLAG_REPORTS_OBSS |
                        WIPHY_FLAG_OFFCHAN_TX;
 
-       wiphy->extended_capabilities = extended_capabilities;
-       wiphy->extended_capabilities_mask = extended_capabilities;
-       wiphy->extended_capabilities_len = ARRAY_SIZE(extended_capabilities);
-
        if (ops->remain_on_channel)
                wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
 
@@ -550,6 +542,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                           NL80211_FEATURE_SAE |
                           NL80211_FEATURE_HT_IBSS |
                           NL80211_FEATURE_VIF_TXPOWER |
+                          NL80211_FEATURE_MAC_ON_CREATE |
                           NL80211_FEATURE_USERSPACE_MPM;
 
        if (!ops->hw_scan)
@@ -591,6 +584,13 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
        wiphy->vht_capa_mod_mask = &mac80211_vht_capa_mod_mask;
 
+       local->ext_capa[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF;
+
+       wiphy->extended_capabilities = local->ext_capa;
+       wiphy->extended_capabilities_mask = local->ext_capa;
+       wiphy->extended_capabilities_len =
+               ARRAY_SIZE(local->ext_capa);
+
        INIT_LIST_HEAD(&local->interfaces);
 
        __hw_addr_init(&local->mc_list);
@@ -651,7 +651,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        return &local->hw;
 }
-EXPORT_SYMBOL(ieee80211_alloc_hw);
+EXPORT_SYMBOL(ieee80211_alloc_hw_nm);
 
 static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
 {
@@ -787,13 +787,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))
                        return -EINVAL;
 
-               /* DFS currently not supported with channel context drivers */
+               /* DFS is not supported with multi-channel combinations yet */
                for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
                        const struct ieee80211_iface_combination *comb;
 
                        comb = &local->hw.wiphy->iface_combinations[i];
 
-                       if (comb->radar_detect_widths)
+                       if (comb->radar_detect_widths &&
+                           comb->num_different_channels > 1)
                                return -EINVAL;
                }
        }
@@ -958,6 +959,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)
                local->hw.wiphy->flags |= WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
 
+       /* mac80211 supports eCSA, if the driver supports STA CSA at all */
+       if (local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)
+               local->ext_capa[0] |= WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING;
+
        local->hw.wiphy->max_num_csa_counters = IEEE80211_MAX_CSA_COUNTERS_NUM;
 
        result = wiphy_register(local->hw.wiphy);
@@ -1019,7 +1024,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        }
 
        /* add one default STA interface if supported */
-       if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
+       if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION) &&
+           !(hw->flags & IEEE80211_HW_NO_AUTO_VIF)) {
                result = ieee80211_if_add(local, "wlan%d", NULL,
                                          NL80211_IFTYPE_STATION, NULL);
                if (result)
index f39a19f9090fe0d91181b8cb4487dd928232d24b..50c8473cf9dc5a8c75c7d963001f51390a68e247 100644 (file)
@@ -270,6 +270,8 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
                 const u8 *dst, const u8 *mpp);
 struct mesh_path *
 mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx);
 void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
 void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
 void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
@@ -317,6 +319,7 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);
 
 bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
 extern int mesh_paths_generation;
+extern int mpp_paths_generation;
 
 #ifdef CONFIG_MAC80211_MESH
 static inline
index a6699dceae7c8aeeff4419d8cc2815f9d86adf5e..b890e225a8f1b98681c53c764fc5252e5f2d5c8d 100644 (file)
@@ -44,6 +44,7 @@ static struct mesh_table __rcu *mesh_paths;
 static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
 
 int mesh_paths_generation;
+int mpp_paths_generation;
 
 /* This lock will have the grow table function as writer and add / delete nodes
  * as readers. RCU provides sufficient protection only when reading the table
@@ -409,6 +410,33 @@ mesh_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
        return NULL;
 }
 
+/**
+ * mpp_path_lookup_by_idx - look up a path in the proxy path table by its index
+ * @idx: index
+ * @sdata: local subif, or NULL for all entries
+ *
+ * Returns: pointer to the proxy path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *
+mpp_path_lookup_by_idx(struct ieee80211_sub_if_data *sdata, int idx)
+{
+       struct mesh_table *tbl = rcu_dereference(mpp_paths);
+       struct mpath_node *node;
+       int i;
+       int j = 0;
+
+       for_each_mesh_entry(tbl, node, i) {
+               if (sdata && node->mpath->sdata != sdata)
+                       continue;
+               if (j++ == idx)
+                       return node->mpath;
+       }
+
+       return NULL;
+}
+
 /**
  * mesh_path_add_gate - add the given mpath to a mesh gate to our path table
  * @mpath: gate path to add to table
@@ -691,6 +719,9 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
 
        spin_unlock(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
+
+       mpp_paths_generation++;
+
        if (grow) {
                set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
                ieee80211_queue_work(&local->hw, &sdata->work);
index 2de88704278b85b8d9ce47f2ef77905108d456e7..213a420704a62f9dfecd25a7873fe25734a31ce7 100644 (file)
@@ -775,11 +775,30 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        WLAN_EID_QOS_CAPA,
                        WLAN_EID_RRM_ENABLED_CAPABILITIES,
                        WLAN_EID_MOBILITY_DOMAIN,
+                       WLAN_EID_FAST_BSS_TRANSITION,   /* reassoc only */
+                       WLAN_EID_RIC_DATA,              /* reassoc only */
                        WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
                };
-               noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
-                                            before_ht, ARRAY_SIZE(before_ht),
-                                            offset);
+               static const u8 after_ric[] = {
+                       WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
+                       WLAN_EID_HT_CAPABILITY,
+                       WLAN_EID_BSS_COEX_2040,
+                       WLAN_EID_EXT_CAPABILITY,
+                       WLAN_EID_QOS_TRAFFIC_CAPA,
+                       WLAN_EID_TIM_BCAST_REQ,
+                       WLAN_EID_INTERWORKING,
+                       /* 60GHz doesn't happen right now */
+                       WLAN_EID_VHT_CAPABILITY,
+                       WLAN_EID_OPMODE_NOTIF,
+               };
+
+               noffset = ieee80211_ie_split_ric(assoc_data->ie,
+                                                assoc_data->ie_len,
+                                                before_ht,
+                                                ARRAY_SIZE(before_ht),
+                                                after_ric,
+                                                ARRAY_SIZE(after_ric),
+                                                offset);
                pos = skb_put(skb, noffset - offset);
                memcpy(pos, assoc_data->ie + offset, noffset - offset);
                offset = noffset;
@@ -813,6 +832,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                        WLAN_EID_TIM_BCAST_REQ,
                        WLAN_EID_INTERWORKING,
                };
+
+               /* RIC already taken above, so no need to handle here anymore */
                noffset = ieee80211_ie_split(assoc_data->ie, assoc_data->ie_len,
                                             before_vht, ARRAY_SIZE(before_vht),
                                             offset);
@@ -1001,14 +1022,7 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        /* XXX: shouldn't really modify cfg80211-owned data! */
        ifmgd->associated->channel = sdata->csa_chandef.chan;
 
-       sdata->vif.csa_active = false;
-
-       /* XXX: wait for a beacon first? */
-       if (sdata->csa_block_tx) {
-               ieee80211_wake_vif_queues(local, sdata,
-                                         IEEE80211_QUEUE_STOP_REASON_CSA);
-               sdata->csa_block_tx = false;
-       }
+       ifmgd->csa_waiting_bcn = true;
 
        ieee80211_sta_reset_beacon_monitor(sdata);
        ieee80211_sta_reset_conn_monitor(sdata);
@@ -1019,6 +1033,35 @@ out:
        sdata_unlock(sdata);
 }
 
+static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       int ret;
+
+       sdata_assert_lock(sdata);
+
+       WARN_ON(!sdata->vif.csa_active);
+
+       if (sdata->csa_block_tx) {
+               ieee80211_wake_vif_queues(local, sdata,
+                                         IEEE80211_QUEUE_STOP_REASON_CSA);
+               sdata->csa_block_tx = false;
+       }
+
+       sdata->vif.csa_active = false;
+       ifmgd->csa_waiting_bcn = false;
+
+       ret = drv_post_channel_switch(sdata);
+       if (ret) {
+               sdata_info(sdata,
+                          "driver post channel switch failed, disconnecting\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               return;
+       }
+}
+
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
@@ -1046,7 +1089,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 static void
 ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
-                                u64 timestamp, struct ieee802_11_elems *elems,
+                                u64 timestamp, u32 device_timestamp,
+                                struct ieee802_11_elems *elems,
                                 bool beacon)
 {
        struct ieee80211_local *local = sdata->local;
@@ -1056,6 +1100,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_chanctx *chanctx;
        enum ieee80211_band current_band;
        struct ieee80211_csa_ie csa_ie;
+       struct ieee80211_channel_switch ch_switch;
        int res;
 
        sdata_assert_lock(sdata);
@@ -1110,21 +1155,31 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       if (local->use_chanctx) {
-               u32 num_chanctx = 0;
-               list_for_each_entry(chanctx, &local->chanctx_list, list)
-                      num_chanctx++;
+       if (local->use_chanctx &&
+           !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+               sdata_info(sdata,
+                          "driver doesn't support chan-switch with channel contexts\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               mutex_unlock(&local->chanctx_mtx);
+               mutex_unlock(&local->mtx);
+               return;
+       }
 
-               if (num_chanctx > 1 ||
-                   !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
-                       sdata_info(sdata,
-                                  "not handling chan-switch with channel contexts\n");
-                       ieee80211_queue_work(&local->hw,
-                                            &ifmgd->csa_connection_drop_work);
-                       mutex_unlock(&local->chanctx_mtx);
-                       mutex_unlock(&local->mtx);
-                       return;
-               }
+       ch_switch.timestamp = timestamp;
+       ch_switch.device_timestamp = device_timestamp;
+       ch_switch.block_tx = csa_ie.mode;
+       ch_switch.chandef = csa_ie.chandef;
+       ch_switch.count = csa_ie.count;
+
+       if (drv_pre_channel_switch(sdata, &ch_switch)) {
+               sdata_info(sdata,
+                          "preparing for channel switch failed, disconnecting\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               mutex_unlock(&local->chanctx_mtx);
+               mutex_unlock(&local->mtx);
+               return;
        }
 
        res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
@@ -1152,14 +1207,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        if (local->ops->channel_switch) {
                /* use driver's channel switch callback */
-               struct ieee80211_channel_switch ch_switch = {
-                       .timestamp = timestamp,
-                       .block_tx = csa_ie.mode,
-                       .chandef = csa_ie.chandef,
-                       .count = csa_ie.count,
-               };
-
-               drv_channel_switch(local, &ch_switch);
+               drv_channel_switch(local, sdata, &ch_switch);
                return;
        }
 
@@ -1579,6 +1627,95 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
        mutex_unlock(&sdata->local->mtx);
 }
 
+static bool
+__ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       bool ret;
+       int ac;
+
+       if (local->hw.queues < IEEE80211_NUM_ACS)
+               return false;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+               int non_acm_ac;
+               unsigned long now = jiffies;
+
+               if (tx_tspec->action == TX_TSPEC_ACTION_NONE &&
+                   tx_tspec->admitted_time &&
+                   time_after(now, tx_tspec->time_slice_start + HZ)) {
+                       tx_tspec->consumed_tx_time = 0;
+                       tx_tspec->time_slice_start = now;
+
+                       if (tx_tspec->downgraded)
+                               tx_tspec->action =
+                                       TX_TSPEC_ACTION_STOP_DOWNGRADE;
+               }
+
+               switch (tx_tspec->action) {
+               case TX_TSPEC_ACTION_STOP_DOWNGRADE:
+                       /* take the original parameters */
+                       if (drv_conf_tx(local, sdata, ac, &sdata->tx_conf[ac]))
+                               sdata_err(sdata,
+                                         "failed to set TX queue parameters for queue %d\n",
+                                         ac);
+                       tx_tspec->action = TX_TSPEC_ACTION_NONE;
+                       tx_tspec->downgraded = false;
+                       ret = true;
+                       break;
+               case TX_TSPEC_ACTION_DOWNGRADE:
+                       if (time_after(now, tx_tspec->time_slice_start + HZ)) {
+                               tx_tspec->action = TX_TSPEC_ACTION_NONE;
+                               ret = true;
+                               break;
+                       }
+                       /* downgrade next lower non-ACM AC */
+                       for (non_acm_ac = ac + 1;
+                            non_acm_ac < IEEE80211_NUM_ACS;
+                            non_acm_ac++)
+                               if (!(sdata->wmm_acm & BIT(7 - 2 * non_acm_ac)))
+                                       break;
+                       /* The loop will result in using BK even if it requires
+                        * admission control, such configuration makes no sense
+                        * and we have to transmit somehow - the AC selection
+                        * does the same thing.
+                        */
+                       if (drv_conf_tx(local, sdata, ac,
+                                       &sdata->tx_conf[non_acm_ac]))
+                               sdata_err(sdata,
+                                         "failed to set TX queue parameters for queue %d\n",
+                                         ac);
+                       tx_tspec->action = TX_TSPEC_ACTION_NONE;
+                       ret = true;
+                       schedule_delayed_work(&ifmgd->tx_tspec_wk,
+                               tx_tspec->time_slice_start + HZ - now + 1);
+                       break;
+               case TX_TSPEC_ACTION_NONE:
+                       /* nothing now */
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+void ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
+{
+       if (__ieee80211_sta_handle_tspec_ac_params(sdata))
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
+}
+
+static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       sdata = container_of(work, struct ieee80211_sub_if_data,
+                            u.mgd.tx_tspec_wk.work);
+       ieee80211_sta_handle_tspec_ac_params(sdata);
+}
+
 /* MLME */
 static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
                                     struct ieee80211_sub_if_data *sdata,
@@ -1663,12 +1800,14 @@ static bool ieee80211_sta_wmm_params(struct ieee80211_local *local,
                params.uapsd = uapsd;
 
                mlme_dbg(sdata,
-                        "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
+                        "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
                         queue, aci, acm,
                         params.aifs, params.cw_min, params.cw_max,
-                        params.txop, params.uapsd);
+                        params.txop, params.uapsd,
+                        ifmgd->tx_tspec[queue].downgraded);
                sdata->tx_conf[queue] = params;
-               if (drv_conf_tx(local, sdata, queue, &params))
+               if (!ifmgd->tx_tspec[queue].downgraded &&
+                   drv_conf_tx(local, sdata, queue, &params))
                        sdata_err(sdata,
                                  "failed to set TX queue parameters for queue %d\n",
                                  queue);
@@ -1923,6 +2062,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        ieee80211_vif_release_channel(sdata);
 
        sdata->vif.csa_active = false;
+       ifmgd->csa_waiting_bcn = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -1930,6 +2070,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        }
        mutex_unlock(&local->mtx);
 
+       /* existing TX TSPEC sessions no longer exist */
+       memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec));
+       cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
+
        sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 }
 
@@ -1982,9 +2126,46 @@ out:
        mutex_unlock(&local->mtx);
 }
 
+static void ieee80211_sta_tx_wmm_ac_notify(struct ieee80211_sub_if_data *sdata,
+                                          struct ieee80211_hdr *hdr,
+                                          u16 tx_time)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u16 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+       int ac = ieee80211_ac_from_tid(tid);
+       struct ieee80211_sta_tx_tspec *tx_tspec = &ifmgd->tx_tspec[ac];
+       unsigned long now = jiffies;
+
+       if (likely(!tx_tspec->admitted_time))
+               return;
+
+       if (time_after(now, tx_tspec->time_slice_start + HZ)) {
+               tx_tspec->consumed_tx_time = 0;
+               tx_tspec->time_slice_start = now;
+
+               if (tx_tspec->downgraded) {
+                       tx_tspec->action = TX_TSPEC_ACTION_STOP_DOWNGRADE;
+                       schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
+               }
+       }
+
+       if (tx_tspec->downgraded)
+               return;
+
+       tx_tspec->consumed_tx_time += tx_time;
+
+       if (tx_tspec->consumed_tx_time >= tx_tspec->admitted_time) {
+               tx_tspec->downgraded = true;
+               tx_tspec->action = TX_TSPEC_ACTION_DOWNGRADE;
+               schedule_delayed_work(&ifmgd->tx_tspec_wk, 0);
+       }
+}
+
 void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
-                            struct ieee80211_hdr *hdr, bool ack)
+                            struct ieee80211_hdr *hdr, bool ack, u16 tx_time)
 {
+       ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
+
        if (!ieee80211_is_data(hdr->frame_control))
            return;
 
@@ -2047,8 +2228,6 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
 
        ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
        run_again(sdata, ifmgd->probe_timeout);
-       if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
-               ieee80211_flush_queues(sdata->local, sdata);
 }
 
 static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
@@ -2171,6 +2350,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
                               true, frame_buf);
        mutex_lock(&local->mtx);
        sdata->vif.csa_active = false;
+       ifmgd->csa_waiting_bcn = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3195,6 +3375,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       if (ifmgd->csa_waiting_bcn)
+               ieee80211_chswitch_post_beacon(sdata);
+
        if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
                return;
        ifmgd->beacon_crc = ncrc;
@@ -3203,6 +3386,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 
        ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+                                        rx_status->device_timestamp,
                                         &elems, true);
 
        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
@@ -3334,8 +3518,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                break;
 
                        ieee80211_sta_process_chanswitch(sdata,
-                                                        rx_status->mactime,
-                                                        &elems, false);
+                                                rx_status->mactime,
+                                                rx_status->device_timestamp,
+                                                &elems, false);
                } else if (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC) {
                        ies_len = skb->len -
                                  offsetof(struct ieee80211_mgmt,
@@ -3356,8 +3541,9 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                &mgmt->u.action.u.ext_chan_switch.data;
 
                        ieee80211_sta_process_chanswitch(sdata,
-                                                        rx_status->mactime,
-                                                        &elems, false);
+                                                rx_status->mactime,
+                                                rx_status->device_timestamp,
+                                                &elems, false);
                }
                break;
        }
@@ -3664,11 +3850,12 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        if (local->quiescing)
                return;
 
-       if (sdata->vif.csa_active)
+       if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
                return;
 
        sdata->u.mgd.connection_loss = false;
@@ -3686,7 +3873,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
        if (local->quiescing)
                return;
 
-       if (sdata->vif.csa_active)
+       if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
                return;
 
        ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
@@ -3798,6 +3985,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
                    (unsigned long) sdata);
        setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
                    (unsigned long) sdata);
+       INIT_DELAYED_WORK(&ifmgd->tx_tspec_wk,
+                         ieee80211_sta_handle_tspec_ac_params_wk);
 
        ifmgd->flags = 0;
        ifmgd->powersave = sdata->wdev.ps;
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
new file mode 100644 (file)
index 0000000..358d5f9
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * OCB mode implementation
+ *
+ * Copyright: (c) 2014 Czech Technical University in Prague
+ *            (c) 2014 Volkswagen Group Research
+ * Author:    Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
+ * Funded by: Volkswagen Group Research
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "driver-ops.h"
+#include "rate.h"
+
+#define IEEE80211_OCB_HOUSEKEEPING_INTERVAL            (60 * HZ)
+#define IEEE80211_OCB_PEER_INACTIVITY_LIMIT            (240 * HZ)
+#define IEEE80211_OCB_MAX_STA_ENTRIES                  128
+
+/**
+ * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks
+ * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks
+ *
+ * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb
+ */
+enum ocb_deferred_task_flags {
+       OCB_WORK_HOUSEKEEPING,
+};
+
+void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
+                            const u8 *bssid, const u8 *addr,
+                            u32 supp_rates)
+{
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_supported_band *sband;
+       enum nl80211_bss_scan_width scan_width;
+       struct sta_info *sta;
+       int band;
+
+       /* XXX: Consider removing the least recently used entry and
+        *      allow new one to be added.
+        */
+       if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) {
+               net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n",
+                                    sdata->name, addr);
+               return;
+       }
+
+       ocb_dbg(sdata, "Adding new OCB station %pM\n", addr);
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (WARN_ON_ONCE(!chanctx_conf)) {
+               rcu_read_unlock();
+               return;
+       }
+       band = chanctx_conf->def.chan->band;
+       scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
+       rcu_read_unlock();
+
+       sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+       if (!sta)
+               return;
+
+       sta->last_rx = jiffies;
+
+       /* Add only mandatory rates for now */
+       sband = local->hw.wiphy->bands[band];
+       sta->sta.supp_rates[band] =
+               ieee80211_mandatory_rates(sband, scan_width);
+
+       spin_lock(&ifocb->incomplete_lock);
+       list_add(&sta->list, &ifocb->incomplete_stations);
+       spin_unlock(&ifocb->incomplete_lock);
+       ieee80211_queue_work(&local->hw, &sdata->work);
+}
+
+static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
+       __acquires(RCU)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       u8 addr[ETH_ALEN];
+
+       memcpy(addr, sta->sta.addr, ETH_ALEN);
+
+       ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n",
+               addr, sdata->name);
+
+       sta_info_move_state(sta, IEEE80211_STA_AUTH);
+       sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+       sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+
+       rate_control_rate_init(sta);
+
+       /* If it fails, maybe we raced another insertion? */
+       if (sta_info_insert_rcu(sta))
+               return sta_info_get(sdata, addr);
+       return sta;
+}
+
+static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+       ocb_dbg(sdata, "Running ocb housekeeping\n");
+
+       ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT);
+
+       mod_timer(&ifocb->housekeeping_timer,
+                 round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL));
+}
+
+void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+       struct sta_info *sta;
+
+       if (ifocb->joined != true)
+               return;
+
+       sdata_lock(sdata);
+
+       spin_lock_bh(&ifocb->incomplete_lock);
+       while (!list_empty(&ifocb->incomplete_stations)) {
+               sta = list_first_entry(&ifocb->incomplete_stations,
+                                      struct sta_info, list);
+               list_del(&sta->list);
+               spin_unlock_bh(&ifocb->incomplete_lock);
+
+               ieee80211_ocb_finish_sta(sta);
+               rcu_read_unlock();
+               spin_lock_bh(&ifocb->incomplete_lock);
+       }
+       spin_unlock_bh(&ifocb->incomplete_lock);
+
+       if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags))
+               ieee80211_ocb_housekeeping(sdata);
+
+       sdata_unlock(sdata);
+}
+
+static void ieee80211_ocb_housekeeping_timer(unsigned long data)
+{
+       struct ieee80211_sub_if_data *sdata = (void *)data;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+       set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
+
+       ieee80211_queue_work(&local->hw, &sdata->work);
+}
+
+void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+
+       setup_timer(&ifocb->housekeeping_timer,
+                   ieee80211_ocb_housekeeping_timer,
+                   (unsigned long)sdata);
+       INIT_LIST_HEAD(&ifocb->incomplete_stations);
+       spin_lock_init(&ifocb->incomplete_lock);
+}
+
+int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
+                      struct ocb_setup *setup)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+       u32 changed = BSS_CHANGED_OCB;
+       int err;
+
+       if (ifocb->joined == true)
+               return -EINVAL;
+
+       sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+       sdata->smps_mode = IEEE80211_SMPS_OFF;
+       sdata->needed_rx_chains = sdata->local->rx_chains;
+
+       mutex_lock(&sdata->local->mtx);
+       err = ieee80211_vif_use_channel(sdata, &setup->chandef,
+                                       IEEE80211_CHANCTX_SHARED);
+       mutex_unlock(&sdata->local->mtx);
+       if (err)
+               return err;
+
+       ieee80211_bss_info_change_notify(sdata, changed);
+
+       ifocb->joined = true;
+
+       set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
+       ieee80211_queue_work(&local->hw, &sdata->work);
+
+       netif_carrier_on(sdata->dev);
+       return 0;
+}
+
+int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ocb *ifocb = &sdata->u.ocb;
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+
+       ifocb->joined = false;
+       sta_info_flush(sdata);
+
+       spin_lock_bh(&ifocb->incomplete_lock);
+       while (!list_empty(&ifocb->incomplete_stations)) {
+               sta = list_first_entry(&ifocb->incomplete_stations,
+                                      struct sta_info, list);
+               list_del(&sta->list);
+               spin_unlock_bh(&ifocb->incomplete_lock);
+
+               sta_info_free(local, sta);
+               spin_lock_bh(&ifocb->incomplete_lock);
+       }
+       spin_unlock_bh(&ifocb->incomplete_lock);
+
+       netif_carrier_off(sdata->dev);
+       clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state);
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB);
+
+       mutex_lock(&sdata->local->mtx);
+       ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&sdata->local->mtx);
+
+       skb_queue_purge(&sdata->skb_queue);
+
+       del_timer_sync(&sdata->u.ocb.housekeeping_timer);
+       /* If the timer fired while we waited for it, it will have
+        * requeued the work. Now the work will be running again
+        * but will not rearm the timer again because it checks
+        * whether we are connected to the network or not -- at this
+        * point we shouldn't be anymore.
+        */
+
+       return 0;
+}
index 2baa7ed8789dce2752a3f69d5cc3627bbbd47c76..c2b91bf47f6d8d0caa64a29fce45c3cf8f76a83b 100644 (file)
@@ -191,7 +191,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
                 * (1) if any success probabilitiy >= 95%, out of those rates
                 * choose the maximum throughput rate as max_prob_rate
                 * (2) if all success probabilities < 95%, the rate with
-                * highest success probability is choosen as max_prob_rate */
+                * highest success probability is chosen as max_prob_rate */
                if (mrs->probability >= MINSTREL_FRAC(95, 100)) {
                        if (mrs->cur_tp >= mi->r[tmp_prob_rate].stats.cur_tp)
                                tmp_prob_rate = i;
index df90ce2db00c042a31bf3cd79dab3cfefcacbc35..c50fd94d2aefc16113b36231ee309512f44922c5 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/skbuff.h>
 #include <linux/debugfs.h>
 #include <linux/random.h>
+#include <linux/moduleparam.h>
 #include <linux/ieee80211.h>
 #include <net/mac80211.h>
 #include "rate.h"
 /* Transmit duration for the raw data part of an average sized packet */
 #define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
 
+#define BW_20                  0
+#define BW_40                  1
+#define BW_80                  2
+
 /*
  * Define group sort order: HT40 -> SGI -> #streams
  */
 #define GROUP_IDX(_streams, _sgi, _ht40)       \
+       MINSTREL_HT_GROUP_0 +                   \
        MINSTREL_MAX_STREAMS * 2 * _ht40 +      \
-       MINSTREL_MAX_STREAMS * _sgi +           \
+       MINSTREL_MAX_STREAMS * _sgi +   \
        _streams - 1
 
 /* MCS rate information for an MCS group */
@@ -47,6 +53,7 @@
        [GROUP_IDX(_streams, _sgi, _ht40)] = {                          \
        .streams = _streams,                                            \
        .flags =                                                        \
+               IEEE80211_TX_RC_MCS |                                   \
                (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |                 \
                (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),             \
        .duration = {                                                   \
        }                                                               \
 }
 
+#define VHT_GROUP_IDX(_streams, _sgi, _bw)                             \
+       (MINSTREL_VHT_GROUP_0 +                                         \
+        MINSTREL_MAX_STREAMS * 2 * (_bw) +                             \
+        MINSTREL_MAX_STREAMS * (_sgi) +                                \
+        (_streams) - 1)
+
+#define BW2VBPS(_bw, r3, r2, r1)                                       \
+       (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
+
+#define VHT_GROUP(_streams, _sgi, _bw)                                 \
+       [VHT_GROUP_IDX(_streams, _sgi, _bw)] = {                        \
+       .streams = _streams,                                            \
+       .flags =                                                        \
+               IEEE80211_TX_RC_VHT_MCS |                               \
+               (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) |                 \
+               (_bw == BW_80 ? IEEE80211_TX_RC_80_MHZ_WIDTH :          \
+                _bw == BW_40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0),      \
+       .duration = {                                                   \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw,  117,  54,  26)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw,  234, 108,  52)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw,  351, 162,  78)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw,  468, 216, 104)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw,  702, 324, 156)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw,  936, 432, 208)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw, 1053, 486, 234)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw, 1170, 540, 260)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw, 1404, 648, 312)),             \
+               MCS_DURATION(_streams, _sgi,                            \
+                            BW2VBPS(_bw, 1560, 720, 346))              \
+       }                                                               \
+}
+
 #define CCK_DURATION(_bitrate, _short, _len)           \
        (1000 * (10 /* SIFS */ +                        \
         (_short ? 72 + 24 : 144 + 48) +                \
        CCK_ACK_DURATION(55, _short),                   \
        CCK_ACK_DURATION(110, _short)
 
-#define CCK_GROUP                                              \
-       [MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS] = {     \
-               .streams = 0,                                   \
-               .duration = {                                   \
-                       CCK_DURATION_LIST(false),               \
-                       CCK_DURATION_LIST(true)                 \
-               }                                               \
+#define CCK_GROUP                                      \
+       [MINSTREL_CCK_GROUP] = {                        \
+               .streams = 0,                           \
+               .flags = 0,                             \
+               .duration = {                           \
+                       CCK_DURATION_LIST(false),       \
+                       CCK_DURATION_LIST(true)         \
+               }                                       \
        }
 
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+static bool minstrel_vht_only = true;
+module_param(minstrel_vht_only, bool, 0644);
+MODULE_PARM_DESC(minstrel_vht_only,
+                "Use only VHT rates when VHT is supported by sta.");
+#endif
+
 /*
  * To enable sufficiently targeted rate sampling, MCS rates are divided into
  * groups, based on the number of streams and flags (HT40, SGI) that they
  * use.
  *
  * Sortorder has to be fixed for GROUP_IDX macro to be applicable:
- * HT40 -> SGI -> #streams
+ * BW -> SGI -> #streams
  */
 const struct mcs_group minstrel_mcs_groups[] = {
-       MCS_GROUP(1, 0, 0),
-       MCS_GROUP(2, 0, 0),
+       MCS_GROUP(1, 0, BW_20),
+       MCS_GROUP(2, 0, BW_20),
 #if MINSTREL_MAX_STREAMS >= 3
-       MCS_GROUP(3, 0, 0),
+       MCS_GROUP(3, 0, BW_20),
 #endif
 
-       MCS_GROUP(1, 1, 0),
-       MCS_GROUP(2, 1, 0),
+       MCS_GROUP(1, 1, BW_20),
+       MCS_GROUP(2, 1, BW_20),
 #if MINSTREL_MAX_STREAMS >= 3
-       MCS_GROUP(3, 1, 0),
+       MCS_GROUP(3, 1, BW_20),
 #endif
 
-       MCS_GROUP(1, 0, 1),
-       MCS_GROUP(2, 0, 1),
+       MCS_GROUP(1, 0, BW_40),
+       MCS_GROUP(2, 0, BW_40),
 #if MINSTREL_MAX_STREAMS >= 3
-       MCS_GROUP(3, 0, 1),
+       MCS_GROUP(3, 0, BW_40),
 #endif
 
-       MCS_GROUP(1, 1, 1),
-       MCS_GROUP(2, 1, 1),
+       MCS_GROUP(1, 1, BW_40),
+       MCS_GROUP(2, 1, BW_40),
 #if MINSTREL_MAX_STREAMS >= 3
-       MCS_GROUP(3, 1, 1),
+       MCS_GROUP(3, 1, BW_40),
 #endif
 
-       /* must be last */
-       CCK_GROUP
-};
+       CCK_GROUP,
 
-#define MINSTREL_CCK_GROUP     (ARRAY_SIZE(minstrel_mcs_groups) - 1)
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+       VHT_GROUP(1, 0, BW_20),
+       VHT_GROUP(2, 0, BW_20),
+#if MINSTREL_MAX_STREAMS >= 3
+       VHT_GROUP(3, 0, BW_20),
+#endif
+
+       VHT_GROUP(1, 1, BW_20),
+       VHT_GROUP(2, 1, BW_20),
+#if MINSTREL_MAX_STREAMS >= 3
+       VHT_GROUP(3, 1, BW_20),
+#endif
+
+       VHT_GROUP(1, 0, BW_40),
+       VHT_GROUP(2, 0, BW_40),
+#if MINSTREL_MAX_STREAMS >= 3
+       VHT_GROUP(3, 0, BW_40),
+#endif
+
+       VHT_GROUP(1, 1, BW_40),
+       VHT_GROUP(2, 1, BW_40),
+#if MINSTREL_MAX_STREAMS >= 3
+       VHT_GROUP(3, 1, BW_40),
+#endif
+
+       VHT_GROUP(1, 0, BW_80),
+       VHT_GROUP(2, 0, BW_80),
+#if MINSTREL_MAX_STREAMS >= 3
+       VHT_GROUP(3, 0, BW_80),
+#endif
+
+       VHT_GROUP(1, 1, BW_80),
+       VHT_GROUP(2, 1, BW_80),
+#if MINSTREL_MAX_STREAMS >= 3
+       VHT_GROUP(3, 1, BW_80),
+#endif
+#endif
+};
 
 static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly;
 
 static void
 minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi);
 
+/*
+ * Some VHT MCSes are invalid (when Ndbps / Nes is not an integer)
+ * e.g for MCS9@20MHzx1Nss: Ndbps=8x52*(5/6) Nes=1
+ *
+ * Returns the valid mcs map for struct minstrel_mcs_group_data.supported
+ */
+static u16
+minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map)
+{
+       u16 mask = 0;
+
+       if (bw == BW_20) {
+               if (nss != 3 && nss != 6)
+                       mask = BIT(9);
+       } else if (bw == BW_80) {
+               if (nss == 3 || nss == 7)
+                       mask = BIT(6);
+               else if (nss == 6)
+                       mask = BIT(9);
+       } else {
+               WARN_ON(bw != BW_40);
+       }
+
+       switch ((le16_to_cpu(mcs_map) >> (2 * (nss - 1))) & 3) {
+       case IEEE80211_VHT_MCS_SUPPORT_0_7:
+               mask |= 0x300;
+               break;
+       case IEEE80211_VHT_MCS_SUPPORT_0_8:
+               mask |= 0x200;
+               break;
+       case IEEE80211_VHT_MCS_SUPPORT_0_9:
+               break;
+       default:
+               mask = 0x3ff;
+       }
+
+       return 0x3ff & ~mask;
+}
+
 /*
  * Look up an MCS group index based on mac80211 rate information
  */
 static int
 minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
 {
-       return GROUP_IDX((rate->idx / MCS_GROUP_RATES) + 1,
+       return GROUP_IDX((rate->idx / 8) + 1,
                         !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
                         !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH));
 }
 
+static int
+minstrel_vht_get_group_idx(struct ieee80211_tx_rate *rate)
+{
+       return VHT_GROUP_IDX(ieee80211_rate_get_vht_nss(rate),
+                            !!(rate->flags & IEEE80211_TX_RC_SHORT_GI),
+                            !!(rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) +
+                            2*!!(rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH));
+}
+
 static struct minstrel_rate_stats *
 minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
                      struct ieee80211_tx_rate *rate)
@@ -149,6 +288,9 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
        if (rate->flags & IEEE80211_TX_RC_MCS) {
                group = minstrel_ht_get_group_idx(rate);
                idx = rate->idx % 8;
+       } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+               group = minstrel_vht_get_group_idx(rate);
+               idx = ieee80211_rate_get_vht_mcs(rate);
        } else {
                group = MINSTREL_CCK_GROUP;
 
@@ -240,8 +382,8 @@ minstrel_ht_calc_tp(struct minstrel_ht_sta *mi, int group, int rate)
  * MCS groups, CCK rates do not provide aggregation and are therefore at last.
  */
 static void
-minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index,
-                              u8 *tp_list)
+minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index,
+                              u16 *tp_list)
 {
        int cur_group, cur_idx, cur_thr, cur_prob;
        int tmp_group, tmp_idx, tmp_thr, tmp_prob;
@@ -278,7 +420,7 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u8 index,
  * Find and set the topmost probability rate per sta and per group
  */
 static void
-minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index)
+minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index)
 {
        struct minstrel_mcs_group_data *mg;
        struct minstrel_rate_stats *mr;
@@ -321,8 +463,8 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u8 index)
  */
 static void
 minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi,
-                                u8 tmp_mcs_tp_rate[MAX_THR_RATES],
-                                u8 tmp_cck_tp_rate[MAX_THR_RATES])
+                                u16 tmp_mcs_tp_rate[MAX_THR_RATES],
+                                u16 tmp_cck_tp_rate[MAX_THR_RATES])
 {
        unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp;
        int i;
@@ -386,8 +528,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
        struct minstrel_mcs_group_data *mg;
        struct minstrel_rate_stats *mr;
        int group, i, j;
-       u8 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
-       u8 tmp_cck_tp_rate[MAX_THR_RATES], index;
+       u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES];
+       u16 tmp_cck_tp_rate[MAX_THR_RATES], index;
 
        if (mi->ampdu_packets > 0) {
                mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
@@ -485,7 +627,8 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rat
        if (!rate->count)
                return false;
 
-       if (rate->flags & IEEE80211_TX_RC_MCS)
+       if (rate->flags & IEEE80211_TX_RC_MCS ||
+           rate->flags & IEEE80211_TX_RC_VHT_MCS)
                return true;
 
        return rate->idx == mp->cck_rates[0] ||
@@ -517,7 +660,7 @@ minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
 }
 
 static void
-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u8 *idx, bool primary)
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
 {
        int group, orig_group;
 
@@ -714,7 +857,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
        const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
        struct minstrel_rate_stats *mr;
        u8 idx;
-       u16 flags;
+       u16 flags = group->flags;
 
        mr = minstrel_get_ratestats(mi, index);
        if (!mr->retry_updated)
@@ -730,13 +873,13 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
                ratetbl->rate[offset].count_rts = mr->retry_count_rtscts;
        }
 
-       if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
+       if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP)
                idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)];
-               flags = 0;
-       } else {
+       else if (flags & IEEE80211_TX_RC_VHT_MCS)
+               idx = ((group->streams - 1) << 4) |
+                     ((index % MCS_GROUP_RATES) & 0xF);
+       else
                idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8;
-               flags = IEEE80211_TX_RC_MCS | group->flags;
-       }
 
        if (offset > 0) {
                ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts;
@@ -916,13 +1059,15 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
                int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
                rate->idx = mp->cck_rates[idx];
-               rate->flags = 0;
-               return;
+       } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) {
+               ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES,
+                                      sample_group->streams);
+       } else {
+               rate->idx = sample_idx % MCS_GROUP_RATES +
+                           (sample_group->streams - 1) * 8;
        }
 
-       rate->idx = sample_idx % MCS_GROUP_RATES +
-                   (sample_group->streams - 1) * 8;
-       rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
+       rate->flags = sample_group->flags;
 }
 
 static void
@@ -962,6 +1107,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
        struct minstrel_ht_sta *mi = &msp->ht;
        struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
        u16 sta_cap = sta->ht_cap.cap;
+       struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
+       int use_vht;
        int n_supported = 0;
        int ack_dur;
        int stbc;
@@ -971,8 +1118,14 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
        if (!sta->ht_cap.ht_supported)
                goto use_legacy;
 
-       BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
-               MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1);
+       BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB);
+
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+       if (vht_cap->vht_supported)
+               use_vht = vht_cap->vht_mcs.tx_mcs_map != cpu_to_le16(~0);
+       else
+#endif
+       use_vht = 0;
 
        msp->is_ht = true;
        memset(mi, 0, sizeof(*mi));
@@ -997,22 +1150,28 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
        }
        mi->sample_tries = 4;
 
-       stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
-               IEEE80211_HT_CAP_RX_STBC_SHIFT;
-       mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+       /* TODO tx_flags for vht - ATM the RC API is not fine-grained enough */
+       if (!use_vht) {
+               stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
+                       IEEE80211_HT_CAP_RX_STBC_SHIFT;
+               mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
 
-       if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
-               mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+               if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+                       mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+       }
 
        for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+               u32 gflags = minstrel_mcs_groups[i].flags;
+               int bw, nss;
+
                mi->groups[i].supported = 0;
                if (i == MINSTREL_CCK_GROUP) {
                        minstrel_ht_update_cck(mp, mi, sband, sta);
                        continue;
                }
 
-               if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
-                       if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
+               if (gflags & IEEE80211_TX_RC_SHORT_GI) {
+                       if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
                                if (!(sta_cap & IEEE80211_HT_CAP_SGI_40))
                                        continue;
                        } else {
@@ -1021,17 +1180,51 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
                        }
                }
 
-               if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
+               if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH &&
                    sta->bandwidth < IEEE80211_STA_RX_BW_40)
                        continue;
 
+               nss = minstrel_mcs_groups[i].streams;
+
                /* Mark MCS > 7 as unsupported if STA is in static SMPS mode */
-               if (sta->smps_mode == IEEE80211_SMPS_STATIC &&
-                   minstrel_mcs_groups[i].streams > 1)
+               if (sta->smps_mode == IEEE80211_SMPS_STATIC && nss > 1)
+                       continue;
+
+               /* HT rate */
+               if (gflags & IEEE80211_TX_RC_MCS) {
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+                       if (use_vht && minstrel_vht_only)
+                               continue;
+#endif
+                       mi->groups[i].supported = mcs->rx_mask[nss - 1];
+                       if (mi->groups[i].supported)
+                               n_supported++;
                        continue;
+               }
+
+               /* VHT rate */
+               if (!vht_cap->vht_supported ||
+                   WARN_ON(!(gflags & IEEE80211_TX_RC_VHT_MCS)) ||
+                   WARN_ON(gflags & IEEE80211_TX_RC_160_MHZ_WIDTH))
+                       continue;
+
+               if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH) {
+                       if (sta->bandwidth < IEEE80211_STA_RX_BW_80 ||
+                           ((gflags & IEEE80211_TX_RC_SHORT_GI) &&
+                            !(vht_cap->cap & IEEE80211_VHT_CAP_SHORT_GI_80))) {
+                               continue;
+                       }
+               }
+
+               if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+                       bw = BW_40;
+               else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+                       bw = BW_80;
+               else
+                       bw = BW_20;
 
-               mi->groups[i].supported =
-                       mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+               mi->groups[i].supported = minstrel_get_valid_vht_rates(bw, nss,
+                               vht_cap->vht_mcs.tx_mcs_map);
 
                if (mi->groups[i].supported)
                        n_supported++;
index 01570e0e014b0995beef18504825b848ec00cbad..f2217d6aa0c2ee28b158616711b99895b250df44 100644 (file)
  * The number of streams can be changed to 2 to reduce code
  * size and memory footprint.
  */
-#define MINSTREL_MAX_STREAMS   3
-#define MINSTREL_STREAM_GROUPS 4
+#define MINSTREL_MAX_STREAMS           3
+#define MINSTREL_HT_STREAM_GROUPS      4 /* BW(=2) * SGI(=2) */
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+#define MINSTREL_VHT_STREAM_GROUPS     6 /* BW(=3) * SGI(=2) */
+#else
+#define MINSTREL_VHT_STREAM_GROUPS     0
+#endif
 
-#define MCS_GROUP_RATES        8
+#define MINSTREL_HT_GROUPS_NB  (MINSTREL_MAX_STREAMS *         \
+                                MINSTREL_HT_STREAM_GROUPS)
+#define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS *         \
+                                MINSTREL_VHT_STREAM_GROUPS)
+#define MINSTREL_CCK_GROUPS_NB 1
+#define MINSTREL_GROUPS_NB     (MINSTREL_HT_GROUPS_NB +        \
+                                MINSTREL_VHT_GROUPS_NB +       \
+                                MINSTREL_CCK_GROUPS_NB)
+
+#define MINSTREL_HT_GROUP_0    0
+#define MINSTREL_CCK_GROUP     (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB)
+#define MINSTREL_VHT_GROUP_0   (MINSTREL_CCK_GROUP + 1)
+
+#ifdef CONFIG_MAC80211_RC_MINSTREL_VHT
+#define MCS_GROUP_RATES                10
+#else
+#define MCS_GROUP_RATES                8
+#endif
 
 struct mcs_group {
        u32 flags;
@@ -31,11 +53,11 @@ struct minstrel_mcs_group_data {
        u8 column;
 
        /* bitfield of supported MCS rates of this group */
-       u8 supported;
+       u16 supported;
 
        /* sorted rate set within a MCS group*/
-       u8 max_group_tp_rate[MAX_THR_RATES];
-       u8 max_group_prob_rate;
+       u16 max_group_tp_rate[MAX_THR_RATES];
+       u16 max_group_prob_rate;
 
        /* MCS rate statistics */
        struct minstrel_rate_stats rates[MCS_GROUP_RATES];
@@ -52,8 +74,8 @@ struct minstrel_ht_sta {
        unsigned int avg_ampdu_len;
 
        /* overall sorted rate set */
-       u8 max_tp_rate[MAX_THR_RATES];
-       u8 max_prob_rate;
+       u16 max_tp_rate[MAX_THR_RATES];
+       u16 max_prob_rate;
 
        /* time of last status update */
        unsigned long stats_update;
@@ -80,7 +102,7 @@ struct minstrel_ht_sta {
        u8 cck_supported_short;
 
        /* MCS rate group info and statistics */
-       struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS + 1];
+       struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB];
 };
 
 struct minstrel_ht_sta_priv {
index d537bec9375463eb115b0f26260f8f3d03759596..20c676b8e5b68fa366ed670640e9091c39ebfde3 100644 (file)
 static char *
 minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
 {
-       unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
        const struct mcs_group *mg;
        unsigned int j, tp, prob, eprob;
        char htmode = '2';
        char gimode = 'L';
+       u32 gflags;
 
        if (!mi->groups[i].supported)
                return p;
 
        mg = &minstrel_mcs_groups[i];
-       if (mg->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+       gflags = mg->flags;
+
+       if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
                htmode = '4';
-       if (mg->flags & IEEE80211_TX_RC_SHORT_GI)
+       else if (gflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+               htmode = '8';
+       if (gflags & IEEE80211_TX_RC_SHORT_GI)
                gimode = 'S';
 
        for (j = 0; j < MCS_GROUP_RATES; j++) {
@@ -41,10 +45,12 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
                if (!(mi->groups[i].supported & BIT(j)))
                        continue;
 
-               if (i == max_mcs)
-                       p += sprintf(p, "CCK/%cP   ", j < 4 ? 'L' : 'S');
+               if (gflags & IEEE80211_TX_RC_MCS)
+                       p += sprintf(p, " HT%c0/%cGI ", htmode, gimode);
+               else if (gflags & IEEE80211_TX_RC_VHT_MCS)
+                       p += sprintf(p, "VHT%c0/%cGI ", htmode, gimode);
                else
-                       p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+                       p += sprintf(p, " CCK/%cP   ", j < 4 ? 'L' : 'S');
 
                *(p++) = (idx == mi->max_tp_rate[0]) ? 'A' : ' ';
                *(p++) = (idx == mi->max_tp_rate[1]) ? 'B' : ' ';
@@ -52,11 +58,14 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p)
                *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' ';
                *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
 
-               if (i == max_mcs) {
-                       int r = bitrates[j % 4];
-                       p += sprintf(p, " %2u.%1uM", r / 10, r % 10);
+               if (gflags & IEEE80211_TX_RC_MCS) {
+                       p += sprintf(p, " MCS%-2u ", (mg->streams - 1) * 8 + j);
+               } else if (gflags & IEEE80211_TX_RC_VHT_MCS) {
+                       p += sprintf(p, " MCS%-1u/%1u", j, mg->streams);
                } else {
-                       p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);
+                       int r = bitrates[j % 4];
+
+                       p += sprintf(p, " %2u.%1uM ", r / 10, r % 10);
                }
 
                tp = mr->cur_tp / 10;
@@ -85,7 +94,6 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
        struct minstrel_ht_sta *mi = &msp->ht;
        struct minstrel_debugfs_info *ms;
        unsigned int i;
-       unsigned int max_mcs = MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS;
        char *p;
        int ret;
 
@@ -96,18 +104,19 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
                return ret;
        }
 
-       ms = kmalloc(8192, GFP_KERNEL);
+       ms = kmalloc(32768, GFP_KERNEL);
        if (!ms)
                return -ENOMEM;
 
        file->private_data = ms;
        p = ms->buf;
-       p += sprintf(p, "type           rate     tpt eprob *prob "
+       p += sprintf(p, " type           rate      tpt eprob *prob "
                        "ret  *ok(*cum)        ok(      cum)\n");
 
-
-       p = minstrel_ht_stats_dump(mi, max_mcs, p);
-       for (i = 0; i < max_mcs; i++)
+       p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p);
+       for (i = 0; i < MINSTREL_CCK_GROUP; i++)
+               p = minstrel_ht_stats_dump(mi, i, p);
+       for (i++; i < ARRAY_SIZE(mi->groups); i++)
                p = minstrel_ht_stats_dump(mi, i, p);
 
        p += sprintf(p, "\nTotal packet count::    ideal %d      "
@@ -119,7 +128,7 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file)
                MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
        ms->len = p - ms->buf;
 
-       WARN_ON(ms->len + sizeof(*ms) > 8192);
+       WARN_ON(ms->len + sizeof(*ms) > 32768);
 
        return nonseekable_open(inode, file);
 }
index b04ca4049c95f276aa4627501d5ced01e8a3b878..bc63aa0c5401860105bf9a1db6618327d8b189ed 100644 (file)
@@ -1032,6 +1032,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                      ieee80211_is_pspoll(hdr->frame_control)) &&
                     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
                     rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
+                    rx->sdata->vif.type != NL80211_IFTYPE_OCB &&
                     (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
                /*
                 * accept port control frames from the AP even when it's not
@@ -1272,6 +1273,12 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                                sta->last_rx_rate_vht_nss = status->vht_nss;
                        }
                }
+       } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) {
+               u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
+                                               NL80211_IFTYPE_OCB);
+               /* OCB uses wild-card BSSID */
+               if (is_broadcast_ether_addr(bssid))
+                       sta->last_rx = jiffies;
        } else if (!is_multicast_ether_addr(hdr->addr1)) {
                /*
                 * Mesh beacons will update last_rx when if they are found to
@@ -2820,6 +2827,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 
        if (!ieee80211_vif_is_mesh(&sdata->vif) &&
            sdata->vif.type != NL80211_IFTYPE_ADHOC &&
+           sdata->vif.type != NL80211_IFTYPE_OCB &&
            sdata->vif.type != NL80211_IFTYPE_STATION)
                return RX_DROP_MONITOR;
 
@@ -3130,6 +3138,33 @@ static bool prepare_for_handlers(struct ieee80211_rx_data *rx,
                                                 BIT(rate_idx));
                }
                break;
+       case NL80211_IFTYPE_OCB:
+               if (!bssid)
+                       return false;
+               if (ieee80211_is_beacon(hdr->frame_control)) {
+                       return false;
+               } else if (!is_broadcast_ether_addr(bssid)) {
+                       ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n");
+                       return false;
+               } else if (!multicast &&
+                          !ether_addr_equal(sdata->dev->dev_addr,
+                                            hdr->addr1)) {
+                       /* if we are in promisc mode we also accept
+                        * packets not destined for us
+                        */
+                       if (!(sdata->dev->flags & IFF_PROMISC))
+                               return false;
+                       rx->flags &= ~IEEE80211_RX_RA_MATCH;
+               } else if (!rx->sta) {
+                       int rate_idx;
+                       if (status->flag & RX_FLAG_HT)
+                               rate_idx = 0; /* TODO: HT rates */
+                       else
+                               rate_idx = status->rate_idx;
+                       ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2,
+                                               BIT(rate_idx));
+               }
+               break;
        case NL80211_IFTYPE_MESH_POINT:
                if (!multicast &&
                    !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
index de494df3bab82ce56efabde30790d8a660f6a983..adc25371b171d32ff0847b503ae5ea0fb31ffacc 100644 (file)
@@ -501,7 +501,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        /* make the station visible */
        sta_info_hash_add(local, sta);
 
-       list_add_rcu(&sta->list, &local->sta_list);
+       list_add_tail_rcu(&sta->list, &local->sta_list);
 
        /* notify driver */
        err = sta_info_insert_drv_state(local, sdata, sta);
@@ -1531,7 +1531,7 @@ void ieee80211_sta_ps_deliver_uapsd(struct sta_info *sta)
                break;
        case 0:
                /* XXX: what is a good value? */
-               n_frames = 8;
+               n_frames = 128;
                break;
        }
 
index 89290e33dafe9f72335c907f075b1f784a91e509..9612d89fad56fabea1bc4619e8b86375f30817a7 100644 (file)
@@ -704,7 +704,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
                if ((sta->sdata->vif.type == NL80211_IFTYPE_STATION) &&
                    (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
-                       ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, acked);
+                       ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
+                                               acked, info->status.tx_time);
 
                if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
                        if (info->flags & IEEE80211_TX_STAT_ACK) {
index 4ea25dec06984792234f4a77edc1e26c157b0662..b4f368e2cb3bb7624925157c7e4b5d6610c95ca8 100644 (file)
@@ -562,8 +562,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
        /* infer the initiator if we can, to support old userspace */
        switch (action_code) {
        case WLAN_TDLS_SETUP_REQUEST:
-               if (sta)
+               if (sta) {
                        set_sta_flag(sta, WLAN_STA_TDLS_INITIATOR);
+                       sta->sta.tdls_initiator = false;
+               }
                /* fall-through */
        case WLAN_TDLS_SETUP_CONFIRM:
        case WLAN_TDLS_DISCOVERY_REQUEST:
@@ -575,8 +577,10 @@ ieee80211_tdls_prep_mgmt_packet(struct wiphy *wiphy, struct net_device *dev,
                 * Make the last packet sent take effect for the initiator
                 * value.
                 */
-               if (sta)
+               if (sta) {
                        clear_sta_flag(sta, WLAN_STA_TDLS_INITIATOR);
+                       sta->sta.tdls_initiator = true;
+               }
                /* fall-through */
        case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
                initiator = false;
index 38fae7ebe984a621540328b6bdad28dcd632fccb..809a4983eb4a7e553621d1687f462b6eb5ecd773 100644 (file)
@@ -987,29 +987,34 @@ TRACE_EVENT(drv_flush,
 
 TRACE_EVENT(drv_channel_switch,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_channel_switch *ch_switch),
 
-       TP_ARGS(local, ch_switch),
+       TP_ARGS(local, sdata, ch_switch),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                CHANDEF_ENTRY
                __field(u64, timestamp)
+               __field(u32, device_timestamp)
                __field(bool, block_tx)
                __field(u8, count)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                CHANDEF_ASSIGN(&ch_switch->chandef)
                __entry->timestamp = ch_switch->timestamp;
+               __entry->device_timestamp = ch_switch->device_timestamp;
                __entry->block_tx = ch_switch->block_tx;
                __entry->count = ch_switch->count;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
-               LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
+               LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count
        )
 );
 
@@ -1557,9 +1562,26 @@ DEFINE_EVENT(local_sdata_evt, drv_stop_ap,
        TP_ARGS(local, sdata)
 );
 
-DEFINE_EVENT(local_only_evt, drv_restart_complete,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
+TRACE_EVENT(drv_reconfig_complete,
+       TP_PROTO(struct ieee80211_local *local,
+                enum ieee80211_reconfig_type reconfig_type),
+       TP_ARGS(local, reconfig_type),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u8, reconfig_type)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->reconfig_type = reconfig_type;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  " reconfig_type:%d",
+               LOCAL_PR_ARG, __entry->reconfig_type
+       )
+
 );
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -2106,6 +2128,72 @@ TRACE_EVENT(drv_channel_switch_beacon,
        )
 );
 
+TRACE_EVENT(drv_pre_channel_switch,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_channel_switch *ch_switch),
+
+       TP_ARGS(local, sdata, ch_switch),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               CHANDEF_ENTRY
+               __field(u64, timestamp)
+               __field(bool, block_tx)
+               __field(u8, count)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               CHANDEF_ASSIGN(&ch_switch->chandef)
+               __entry->timestamp = ch_switch->timestamp;
+               __entry->block_tx = ch_switch->block_tx;
+               __entry->count = ch_switch->count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT " prepare channel switch to "
+               CHANDEF_PR_FMT  " count:%d block_tx:%d timestamp:%llu",
+               LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count,
+               __entry->block_tx, __entry->timestamp
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_post_channel_switch,
+            TP_PROTO(struct ieee80211_local *local,
+                     struct ieee80211_sub_if_data *sdata),
+            TP_ARGS(local, sdata)
+);
+
+TRACE_EVENT(drv_get_txpower,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                int dbm, int ret),
+
+       TP_ARGS(local, sdata, dbm, ret),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(int, dbm)
+               __field(int, ret)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->dbm = dbm;
+               __entry->ret = ret;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT VIF_PR_FMT " dbm:%d ret:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->dbm, __entry->ret
+       )
+);
+
 
 #ifdef CONFIG_MAC80211_MESSAGE_TRACING
 #undef TRACE_SYSTEM
index 900632a250ecc7b0f4c57190d68bcdd45169e60e..3ffd91f295a67e2a5f932ac0f90fe05e7a481d1a 100644 (file)
@@ -296,6 +296,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
                 */
                return TX_DROP;
 
+       if (tx->sdata->vif.type == NL80211_IFTYPE_OCB)
+               return TX_CONTINUE;
+
        if (tx->sdata->vif.type == NL80211_IFTYPE_WDS)
                return TX_CONTINUE;
 
@@ -2013,6 +2016,17 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        goto fail_rcu;
                band = chanctx_conf->def.chan->band;
                break;
+       case NL80211_IFTYPE_OCB:
+               /* DA SA BSSID */
+               memcpy(hdr.addr1, skb->data, ETH_ALEN);
+               memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+               eth_broadcast_addr(hdr.addr3);
+               hdrlen = 24;
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (!chanctx_conf)
+                       goto fail_rcu;
+               band = chanctx_conf->def.chan->band;
+               break;
        case NL80211_IFTYPE_ADHOC:
                /* DA SA BSSID */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -2057,6 +2071,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         * EAPOL frames from the local station.
         */
        if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
+                    (sdata->vif.type != NL80211_IFTYPE_OCB) &&
                     !multicast && !authorized &&
                     (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
                      !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
index 3c61060a4d2b75bd89d4a792dde8b4721eb435dc..f9319a5dca642c26a52b465bb2f0657e950c7486 100644 (file)
@@ -693,6 +693,34 @@ void ieee80211_iterate_active_interfaces_rtnl(
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
 
+static void __iterate_stations(struct ieee80211_local *local,
+                              void (*iterator)(void *data,
+                                               struct ieee80211_sta *sta),
+                              void *data)
+{
+       struct sta_info *sta;
+
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (!sta->uploaded)
+                       continue;
+
+               iterator(data, &sta->sta);
+       }
+}
+
+void ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
+                       void (*iterator)(void *data,
+                                        struct ieee80211_sta *sta),
+                       void *data)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+
+       rcu_read_lock();
+       __iterate_stations(local, iterator, data);
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_stations_atomic);
+
 struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
@@ -1073,6 +1101,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_chanctx_conf *chanctx_conf;
        int ac;
        bool use_11b, enable_qos;
+       bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */
        int aCWmin, aCWmax;
 
        if (!local->ops->conf_tx)
@@ -1097,6 +1126,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
         */
        enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
 
+       is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB);
+
        /* Set defaults according to 802.11-2007 Table 7-37 */
        aCWmax = 1023;
        if (use_11b)
@@ -1118,7 +1149,10 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                                qparam.cw_max = aCWmax;
                                qparam.cw_min = aCWmin;
                                qparam.txop = 0;
-                               qparam.aifs = 7;
+                               if (is_ocb)
+                                       qparam.aifs = 9;
+                               else
+                                       qparam.aifs = 7;
                                break;
                        /* never happens but let's not leave undefined */
                        default:
@@ -1126,21 +1160,32 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                                qparam.cw_max = aCWmax;
                                qparam.cw_min = aCWmin;
                                qparam.txop = 0;
-                               qparam.aifs = 3;
+                               if (is_ocb)
+                                       qparam.aifs = 6;
+                               else
+                                       qparam.aifs = 3;
                                break;
                        case IEEE80211_AC_VI:
                                qparam.cw_max = aCWmin;
                                qparam.cw_min = (aCWmin + 1) / 2 - 1;
-                               if (use_11b)
+                               if (is_ocb)
+                                       qparam.txop = 0;
+                               else if (use_11b)
                                        qparam.txop = 6016/32;
                                else
                                        qparam.txop = 3008/32;
-                               qparam.aifs = 2;
+
+                               if (is_ocb)
+                                       qparam.aifs = 3;
+                               else
+                                       qparam.aifs = 2;
                                break;
                        case IEEE80211_AC_VO:
                                qparam.cw_max = (aCWmin + 1) / 2 - 1;
                                qparam.cw_min = (aCWmin + 1) / 4 - 1;
-                               if (use_11b)
+                               if (is_ocb)
+                                       qparam.txop = 0;
+                               else if (use_11b)
                                        qparam.txop = 3264/32;
                                else
                                        qparam.txop = 1504/32;
@@ -1813,6 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        ieee80211_bss_info_change_notify(sdata, changed);
                        sdata_unlock(sdata);
                        break;
+               case NL80211_IFTYPE_OCB:
+                       changed |= BSS_CHANGED_OCB;
+                       ieee80211_bss_info_change_notify(sdata, changed);
+                       break;
                case NL80211_IFTYPE_ADHOC:
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
@@ -1949,7 +1998,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
         * We may want to change that later, however.
         */
        if (!local->suspended || reconfig_due_to_wowlan)
-               drv_restart_complete(local);
+               drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
 
        if (!local->suspended)
                return 0;
@@ -1960,6 +2009,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mb();
        local->resuming = false;
 
+       if (!reconfig_due_to_wowlan)
+               drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
+
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
                        continue;
@@ -2052,42 +2104,36 @@ static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
        return false;
 }
 
-/**
- * ieee80211_ie_split - split an IE buffer according to ordering
- *
- * @ies: the IE buffer
- * @ielen: the length of the IE buffer
- * @ids: an array with element IDs that are allowed before
- *     the split
- * @n_ids: the size of the element ID array
- * @offset: offset where to start splitting in the buffer
- *
- * This function splits an IE buffer by updating the @offset
- * variable to point to the location where the buffer should be
- * split.
- *
- * It assumes that the given IE buffer is well-formed, this
- * has to be guaranteed by the caller!
- *
- * It also assumes that the IEs in the buffer are ordered
- * correctly, if not the result of using this function will not
- * be ordered correctly either, i.e. it does no reordering.
- *
- * The function returns the offset where the next part of the
- * buffer starts, which may be @ielen if the entire (remainder)
- * of the buffer should be used.
- */
-size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
-                         const u8 *ids, int n_ids, size_t offset)
+size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
+                             const u8 *ids, int n_ids,
+                             const u8 *after_ric, int n_after_ric,
+                             size_t offset)
 {
        size_t pos = offset;
 
-       while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
-               pos += 2 + ies[pos + 1];
+       while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
+               if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
+                       pos += 2 + ies[pos + 1];
+
+                       while (pos < ielen &&
+                              !ieee80211_id_in_list(after_ric, n_after_ric,
+                                                    ies[pos]))
+                               pos += 2 + ies[pos + 1];
+               } else {
+                       pos += 2 + ies[pos + 1];
+               }
+       }
 
        return pos;
 }
 
+size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
+                         const u8 *ids, int n_ids, size_t offset)
+{
+       return ieee80211_ie_split_ric(ies, ielen, ids, n_ids, NULL, 0, offset);
+}
+EXPORT_SYMBOL(ieee80211_ie_split);
+
 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
 {
        size_t pos = offset;
@@ -2526,11 +2572,23 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work)
        struct ieee80211_local *local =
                container_of(work, struct ieee80211_local, radar_detected_work);
        struct cfg80211_chan_def chandef = local->hw.conf.chandef;
+       struct ieee80211_chanctx *ctx;
+       int num_chanctx = 0;
+
+       mutex_lock(&local->chanctx_mtx);
+       list_for_each_entry(ctx, &local->chanctx_list, list) {
+               if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
+                       continue;
+
+               num_chanctx++;
+               chandef = ctx->conf.def;
+       }
+       mutex_unlock(&local->chanctx_mtx);
 
        ieee80211_dfs_cac_cancel(local);
 
-       if (local->use_chanctx)
-               /* currently not handled */
+       if (num_chanctx > 1)
+               /* XXX: multi-channel is not supported yet */
                WARN_ON(1);
        else
                cfg80211_radar_event(local->hw.wiphy, &chandef, GFP_KERNEL);
index 9181fb6d643786788abfed37d3ed3d5130e3cb3e..a4220e92f0cc20c0feb04c307f6ed72097f4fe3a 100644 (file)
@@ -111,8 +111,6 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
            (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
                return newhdr + hdrlen;
 
-       skb_set_network_header(skb, skb_network_offset(skb) +
-                                   IEEE80211_WEP_IV_LEN);
        ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
        return newhdr + hdrlen;
 }
index 3b873989992cbe0d0ae9b09d76d799cb3585add4..fdf52db95b33303d791c638410ebd8591a239ae3 100644 (file)
@@ -54,10 +54,18 @@ static int wme_downgrade_ac(struct sk_buff *skb)
 }
 
 static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata,
-                                    struct sk_buff *skb)
+                                    struct sta_info *sta, struct sk_buff *skb)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
        /* in case we are a client verify acm is not set for this ac */
-       while (unlikely(sdata->wmm_acm & BIT(skb->priority))) {
+       while (sdata->wmm_acm & BIT(skb->priority)) {
+               int ac = ieee802_1d_to_ac[skb->priority];
+
+               if (ifmgd->tx_tspec[ac].admitted_time &&
+                   skb->priority == ifmgd->tx_tspec[ac].up)
+                       return ac;
+
                if (wme_downgrade_ac(skb)) {
                        /*
                         * This should not really happen. The AP has marked all
@@ -96,7 +104,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
        p = ieee80211_get_qos_ctl(hdr);
        skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-       return ieee80211_downgrade_queue(sdata, skb);
+       return ieee80211_downgrade_queue(sdata, NULL, skb);
 }
 
 /* Indicate which queue to use. */
@@ -108,6 +116,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        const u8 *ra = NULL;
        bool qos = false;
        struct mac80211_qos_map *qos_map;
+       u16 ret;
 
        if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
                skb->priority = 0; /* required for correct WPA/11i MIC */
@@ -139,6 +148,10 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_ADHOC:
                ra = skb->data;
                break;
+       case NL80211_IFTYPE_OCB:
+               /* all stations are required to support WME */
+               qos = true;
+               break;
        default:
                break;
        }
@@ -148,27 +161,29 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                if (sta)
                        qos = sta->sta.wme;
        }
-       rcu_read_unlock();
 
        if (!qos) {
                skb->priority = 0; /* required for correct WPA/11i MIC */
-               return IEEE80211_AC_BE;
+               ret = IEEE80211_AC_BE;
+               goto out;
        }
 
        if (skb->protocol == sdata->control_port_protocol) {
                skb->priority = 7;
-               return ieee80211_downgrade_queue(sdata, skb);
+               goto downgrade;
        }
 
        /* use the data classifier to determine what 802.1d tag the
         * data frame has */
-       rcu_read_lock();
        qos_map = rcu_dereference(sdata->qos_map);
        skb->priority = cfg80211_classify8021d(skb, qos_map ?
                                               &qos_map->qos_map : NULL);
-       rcu_read_unlock();
 
-       return ieee80211_downgrade_queue(sdata, skb);
+ downgrade:
+       ret = ieee80211_downgrade_queue(sdata, sta, skb);
+ out:
+       rcu_read_unlock();
+       return ret;
 }
 
 /**
index 7fea4bb8acbc4985934ee265ade2546ab8e950ef..80151edc51955d913ef2b00608f29960557d73c7 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/netdevice.h>
 #include "ieee80211_i.h"
 
-extern const int ieee802_1d_to_ac[8];
-
 u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
                                 struct sk_buff *skb,
                                 struct ieee80211_hdr *hdr);
index 983527a4c1aba22c4ae6dc43c113ed1df9f1eb9c..12398fde02e87e7c7eb0eba1430e72287c6bb6f8 100644 (file)
@@ -209,8 +209,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        pos = skb_push(skb, IEEE80211_TKIP_IV_LEN);
        memmove(pos, pos + IEEE80211_TKIP_IV_LEN, hdrlen);
-       skb_set_network_header(skb, skb_network_offset(skb) +
-                                   IEEE80211_TKIP_IV_LEN);
        pos += hdrlen;
 
        /* the HW only needs room for the IV, but not the actual IV */
@@ -434,8 +432,6 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        pos = skb_push(skb, IEEE80211_CCMP_HDR_LEN);
        memmove(pos, pos + IEEE80211_CCMP_HDR_LEN, hdrlen);
-       skb_set_network_header(skb, skb_network_offset(skb) +
-                                   IEEE80211_CCMP_HDR_LEN);
 
        /* the HW only needs room for the IV, but not the actual IV */
        if (info->control.hw_key &&
@@ -575,7 +571,6 @@ ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
 
        pos = skb_push(skb, cs->hdr_len);
        memmove(pos, pos + cs->hdr_len, hdrlen);
-       skb_set_network_header(skb, skb_network_offset(skb) + cs->hdr_len);
 
        return TX_CONTINUE;
 }
index 1818a99b3081e5a87a5c1ed72e6dba1760f2c1bc..aa462b480a394b0081ba73e2441d9cb4619e519b 100644 (file)
@@ -16,5 +16,5 @@ config MAC802154
          been tested yet!
 
          If you plan to use HardMAC IEEE 802.15.4 devices, you can
-         say N here. Alternatievly you can say M to compile it as
+         say N here. Alternatively you can say M to compile it as
          module.
index 9723d6f3f3e5b742e1d105b2667627949f1d7c7d..2e497d0c829ad7d09e4091f5d42b792d65fba63a 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_MAC802154)        += mac802154.o
-mac802154-objs         := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o \
-                          monitor.o wpan.o llsec.o
+mac802154-objs         := main.o rx.o tx.o mac_cmd.o mib.o \
+                          iface.o llsec.o util.o
 
 ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h
new file mode 100644 (file)
index 0000000..dfd29ff
--- /dev/null
@@ -0,0 +1,226 @@
+#ifndef __MAC802154_DRVIER_OPS
+#define __MAC802154_DRIVER_OPS
+
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+
+#include <net/mac802154.h>
+
+#include "ieee802154_i.h"
+
+static inline int
+drv_xmit_async(struct ieee802154_local *local, struct sk_buff *skb)
+{
+       return local->ops->xmit_async(&local->hw, skb);
+}
+
+static inline int
+drv_xmit_sync(struct ieee802154_local *local, struct sk_buff *skb)
+{
+       /* don't allow other operations while sync xmit */
+       ASSERT_RTNL();
+
+       might_sleep();
+
+       return local->ops->xmit_sync(&local->hw, skb);
+}
+
+static inline int drv_start(struct ieee802154_local *local)
+{
+       might_sleep();
+
+       local->started = true;
+       smp_mb();
+
+       return local->ops->start(&local->hw);
+}
+
+static inline void drv_stop(struct ieee802154_local *local)
+{
+       might_sleep();
+
+       local->ops->stop(&local->hw);
+
+       /* sync away all work on the tasklet before clearing started */
+       tasklet_disable(&local->tasklet);
+       tasklet_enable(&local->tasklet);
+
+       barrier();
+
+       local->started = false;
+}
+
+static inline int drv_set_channel(struct ieee802154_local *local,
+                                 const u8 page, const u8 channel)
+{
+       might_sleep();
+
+       return local->ops->set_channel(&local->hw, page, channel);
+}
+
+static inline int drv_set_tx_power(struct ieee802154_local *local,
+                                  const s8 dbm)
+{
+       might_sleep();
+
+       if (!local->ops->set_txpower) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_txpower(&local->hw, dbm);
+}
+
+static inline int drv_set_cca_mode(struct ieee802154_local *local,
+                                  const u8 cca_mode)
+{
+       might_sleep();
+
+       if (!local->ops->set_cca_mode) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_cca_mode(&local->hw, cca_mode);
+}
+
+static inline int drv_set_lbt_mode(struct ieee802154_local *local,
+                                  const bool mode)
+{
+       might_sleep();
+
+       if (!local->ops->set_lbt) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_lbt(&local->hw, mode);
+}
+
+static inline int drv_set_cca_ed_level(struct ieee802154_local *local,
+                                      const s32 ed_level)
+{
+       might_sleep();
+
+       if (!local->ops->set_cca_ed_level) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_cca_ed_level(&local->hw, ed_level);
+}
+
+static inline int drv_set_pan_id(struct ieee802154_local *local,
+                                const __le16 pan_id)
+{
+       struct ieee802154_hw_addr_filt filt;
+
+       might_sleep();
+
+       if (!local->ops->set_hw_addr_filt) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       filt.pan_id = pan_id;
+
+       return local->ops->set_hw_addr_filt(&local->hw, &filt,
+                                           IEEE802154_AFILT_PANID_CHANGED);
+}
+
+static inline int drv_set_extended_addr(struct ieee802154_local *local,
+                                       const __le64 extended_addr)
+{
+       struct ieee802154_hw_addr_filt filt;
+
+       might_sleep();
+
+       if (!local->ops->set_hw_addr_filt) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       filt.ieee_addr = extended_addr;
+
+       return local->ops->set_hw_addr_filt(&local->hw, &filt,
+                                           IEEE802154_AFILT_IEEEADDR_CHANGED);
+}
+
+static inline int drv_set_short_addr(struct ieee802154_local *local,
+                                    const __le16 short_addr)
+{
+       struct ieee802154_hw_addr_filt filt;
+
+       might_sleep();
+
+       if (!local->ops->set_hw_addr_filt) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       filt.short_addr = short_addr;
+
+       return local->ops->set_hw_addr_filt(&local->hw, &filt,
+                                           IEEE802154_AFILT_SADDR_CHANGED);
+}
+
+static inline int drv_set_pan_coord(struct ieee802154_local *local,
+                                   const bool is_coord)
+{
+       struct ieee802154_hw_addr_filt filt;
+
+       might_sleep();
+
+       if (!local->ops->set_hw_addr_filt) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       filt.pan_coord = is_coord;
+
+       return local->ops->set_hw_addr_filt(&local->hw, &filt,
+                                           IEEE802154_AFILT_PANC_CHANGED);
+}
+
+static inline int drv_set_csma_params(struct ieee802154_local *local,
+                                     u8 min_be, u8 max_be,
+                                     u8 max_csma_backoffs)
+{
+       might_sleep();
+
+       if (!local->ops->set_csma_params) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_csma_params(&local->hw, min_be, max_be,
+                                          max_csma_backoffs);
+}
+
+static inline int drv_set_max_frame_retries(struct ieee802154_local *local,
+                                           s8 max_frame_retries)
+{
+       might_sleep();
+
+       if (!local->ops->set_frame_retries) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_frame_retries(&local->hw, max_frame_retries);
+}
+
+static inline int drv_set_promiscuous_mode(struct ieee802154_local *local,
+                                          const bool on)
+{
+       might_sleep();
+
+       if (!local->ops->set_promiscuous_mode) {
+               WARN_ON(1);
+               return -EOPNOTSUPP;
+       }
+
+       return local->ops->set_promiscuous_mode(&local->hw, on);
+}
+
+#endif /* __MAC802154_DRVIER_OPS */
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c
deleted file mode 100644 (file)
index b36b2b9..0000000
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Siemens AG
- *
- * Written by:
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- *
- * Based on the code from 'linux-zigbee.sourceforge.net' project.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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-1301 USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-
-#include <net/netlink.h>
-#include <linux/nl802154.h>
-#include <net/mac802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/route.h>
-#include <net/wpan-phy.h>
-
-#include "mac802154.h"
-
-int mac802154_slave_open(struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct mac802154_sub_if_data *subif;
-       struct mac802154_priv *ipriv = priv->hw;
-       int res = 0;
-
-       ASSERT_RTNL();
-
-       if (priv->type == IEEE802154_DEV_WPAN) {
-               mutex_lock(&priv->hw->slaves_mtx);
-               list_for_each_entry(subif, &priv->hw->slaves, list) {
-                       if (subif != priv && subif->type == priv->type &&
-                           subif->running) {
-                               mutex_unlock(&priv->hw->slaves_mtx);
-                               return -EBUSY;
-                       }
-               }
-               mutex_unlock(&priv->hw->slaves_mtx);
-       }
-
-       mutex_lock(&priv->hw->slaves_mtx);
-       priv->running = true;
-       mutex_unlock(&priv->hw->slaves_mtx);
-
-       if (ipriv->open_count++ == 0) {
-               res = ipriv->ops->start(&ipriv->hw);
-               WARN_ON(res);
-               if (res)
-                       goto err;
-       }
-
-       if (ipriv->ops->ieee_addr) {
-               __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr);
-
-               res = ipriv->ops->ieee_addr(&ipriv->hw, addr);
-               WARN_ON(res);
-               if (res)
-                       goto err;
-               mac802154_dev_set_ieee_addr(dev);
-       }
-
-       netif_start_queue(dev);
-       return 0;
-err:
-       priv->hw->open_count--;
-
-       return res;
-}
-
-int mac802154_slave_close(struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct mac802154_priv *ipriv = priv->hw;
-
-       ASSERT_RTNL();
-
-       netif_stop_queue(dev);
-
-       mutex_lock(&priv->hw->slaves_mtx);
-       priv->running = false;
-       mutex_unlock(&priv->hw->slaves_mtx);
-
-       if (!--ipriv->open_count)
-               ipriv->ops->stop(&ipriv->hw);
-
-       return 0;
-}
-
-static int
-mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv;
-       struct mac802154_priv *ipriv;
-       int err;
-
-       ipriv = wpan_phy_priv(phy);
-
-       priv = netdev_priv(dev);
-       priv->dev = dev;
-       priv->hw = ipriv;
-
-       dev->needed_headroom = ipriv->hw.extra_tx_headroom;
-
-       SET_NETDEV_DEV(dev, &ipriv->phy->dev);
-
-       mutex_lock(&ipriv->slaves_mtx);
-       if (!ipriv->running) {
-               mutex_unlock(&ipriv->slaves_mtx);
-               return -ENODEV;
-       }
-       mutex_unlock(&ipriv->slaves_mtx);
-
-       err = register_netdev(dev);
-       if (err < 0)
-               return err;
-
-       rtnl_lock();
-       mutex_lock(&ipriv->slaves_mtx);
-       list_add_tail_rcu(&priv->list, &ipriv->slaves);
-       mutex_unlock(&ipriv->slaves_mtx);
-       rtnl_unlock();
-
-       return 0;
-}
-
-static void
-mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
-{
-       struct mac802154_sub_if_data *sdata;
-
-       ASSERT_RTNL();
-
-       sdata = netdev_priv(dev);
-
-       BUG_ON(sdata->hw->phy != phy);
-
-       mutex_lock(&sdata->hw->slaves_mtx);
-       list_del_rcu(&sdata->list);
-       mutex_unlock(&sdata->hw->slaves_mtx);
-
-       synchronize_rcu();
-       unregister_netdevice(sdata->dev);
-}
-
-static struct net_device *
-mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
-{
-       struct net_device *dev;
-       int err = -ENOMEM;
-
-       switch (type) {
-       case IEEE802154_DEV_MONITOR:
-               dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
-                                  name, NET_NAME_UNKNOWN,
-                                  mac802154_monitor_setup);
-               break;
-       case IEEE802154_DEV_WPAN:
-               dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
-                                  name, NET_NAME_UNKNOWN,
-                                  mac802154_wpan_setup);
-               break;
-       default:
-               dev = NULL;
-               err = -EINVAL;
-               break;
-       }
-       if (!dev)
-               goto err;
-
-       err = mac802154_netdev_register(phy, dev);
-       if (err)
-               goto err_free;
-
-       dev_hold(dev); /* we return an incremented device refcount */
-       return dev;
-
-err_free:
-       free_netdev(dev);
-err:
-       return ERR_PTR(err);
-}
-
-static int mac802154_set_txpower(struct wpan_phy *phy, int db)
-{
-       struct mac802154_priv *priv = wpan_phy_priv(phy);
-
-       return priv->ops->set_txpower(&priv->hw, db);
-}
-
-static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
-{
-       struct mac802154_priv *priv = wpan_phy_priv(phy);
-
-       return priv->ops->set_lbt(&priv->hw, on);
-}
-
-static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
-{
-       struct mac802154_priv *priv = wpan_phy_priv(phy);
-
-       return priv->ops->set_cca_mode(&priv->hw, mode);
-}
-
-static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
-{
-       struct mac802154_priv *priv = wpan_phy_priv(phy);
-
-       return priv->ops->set_cca_ed_level(&priv->hw, level);
-}
-
-static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be,
-                                    u8 max_be, u8 retries)
-{
-       struct mac802154_priv *priv = wpan_phy_priv(phy);
-
-       return priv->ops->set_csma_params(&priv->hw, min_be, max_be, retries);
-}
-
-static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
-{
-       struct mac802154_priv *priv = wpan_phy_priv(phy);
-
-       return priv->ops->set_frame_retries(&priv->hw, retries);
-}
-
-struct ieee802154_dev *
-ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
-{
-       struct wpan_phy *phy;
-       struct mac802154_priv *priv;
-       size_t priv_size;
-
-       if (!ops || !ops->xmit || !ops->ed || !ops->start ||
-           !ops->stop || !ops->set_channel) {
-               pr_err("undefined IEEE802.15.4 device operations\n");
-               return NULL;
-       }
-
-       /* Ensure 32-byte alignment of our private data and hw private data.
-        * We use the wpan_phy priv data for both our mac802154_priv and for
-        * the driver's private data
-        *
-        * in memory it'll be like this:
-        *
-        * +-----------------------+
-        * | struct wpan_phy       |
-        * +-----------------------+
-        * | struct mac802154_priv |
-        * +-----------------------+
-        * | driver's private data |
-        * +-----------------------+
-        *
-        * Due to ieee802154 layer isn't aware of driver and MAC structures,
-        * so lets allign them here.
-        */
-
-       priv_size = ALIGN(sizeof(*priv), NETDEV_ALIGN) + priv_data_len;
-
-       phy = wpan_phy_alloc(priv_size);
-       if (!phy) {
-               pr_err("failure to allocate master IEEE802.15.4 device\n");
-               return NULL;
-       }
-
-       priv = wpan_phy_priv(phy);
-       priv->phy = phy;
-       priv->hw.phy = priv->phy;
-       priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN);
-       priv->ops = ops;
-
-       INIT_LIST_HEAD(&priv->slaves);
-       mutex_init(&priv->slaves_mtx);
-
-       return &priv->hw;
-}
-EXPORT_SYMBOL(ieee802154_alloc_device);
-
-void ieee802154_free_device(struct ieee802154_dev *hw)
-{
-       struct mac802154_priv *priv = mac802154_to_priv(hw);
-
-       BUG_ON(!list_empty(&priv->slaves));
-
-       mutex_destroy(&priv->slaves_mtx);
-
-       wpan_phy_free(priv->phy);
-}
-EXPORT_SYMBOL(ieee802154_free_device);
-
-int ieee802154_register_device(struct ieee802154_dev *dev)
-{
-       struct mac802154_priv *priv = mac802154_to_priv(dev);
-       int rc = -ENOSYS;
-
-       if (dev->flags & IEEE802154_HW_TXPOWER) {
-               if (!priv->ops->set_txpower)
-                       goto out;
-
-               priv->phy->set_txpower = mac802154_set_txpower;
-       }
-
-       if (dev->flags & IEEE802154_HW_LBT) {
-               if (!priv->ops->set_lbt)
-                       goto out;
-
-               priv->phy->set_lbt = mac802154_set_lbt;
-       }
-
-       if (dev->flags & IEEE802154_HW_CCA_MODE) {
-               if (!priv->ops->set_cca_mode)
-                       goto out;
-
-               priv->phy->set_cca_mode = mac802154_set_cca_mode;
-       }
-
-       if (dev->flags & IEEE802154_HW_CCA_ED_LEVEL) {
-               if (!priv->ops->set_cca_ed_level)
-                       goto out;
-
-               priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
-       }
-
-       if (dev->flags & IEEE802154_HW_CSMA_PARAMS) {
-               if (!priv->ops->set_csma_params)
-                       goto out;
-
-               priv->phy->set_csma_params = mac802154_set_csma_params;
-       }
-
-       if (dev->flags & IEEE802154_HW_FRAME_RETRIES) {
-               if (!priv->ops->set_frame_retries)
-                       goto out;
-
-               priv->phy->set_frame_retries = mac802154_set_frame_retries;
-       }
-
-       priv->dev_workqueue =
-               create_singlethread_workqueue(wpan_phy_name(priv->phy));
-       if (!priv->dev_workqueue) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       wpan_phy_set_dev(priv->phy, priv->hw.parent);
-
-       priv->phy->add_iface = mac802154_add_iface;
-       priv->phy->del_iface = mac802154_del_iface;
-
-       rc = wpan_phy_register(priv->phy);
-       if (rc < 0)
-               goto out_wq;
-
-       rtnl_lock();
-
-       mutex_lock(&priv->slaves_mtx);
-       priv->running = MAC802154_DEVICE_RUN;
-       mutex_unlock(&priv->slaves_mtx);
-
-       rtnl_unlock();
-
-       return 0;
-
-out_wq:
-       destroy_workqueue(priv->dev_workqueue);
-out:
-       return rc;
-}
-EXPORT_SYMBOL(ieee802154_register_device);
-
-void ieee802154_unregister_device(struct ieee802154_dev *dev)
-{
-       struct mac802154_priv *priv = mac802154_to_priv(dev);
-       struct mac802154_sub_if_data *sdata, *next;
-
-       flush_workqueue(priv->dev_workqueue);
-       destroy_workqueue(priv->dev_workqueue);
-
-       rtnl_lock();
-
-       mutex_lock(&priv->slaves_mtx);
-       priv->running = MAC802154_DEVICE_STOPPED;
-       mutex_unlock(&priv->slaves_mtx);
-
-       list_for_each_entry_safe(sdata, next, &priv->slaves, list) {
-               mutex_lock(&sdata->hw->slaves_mtx);
-               list_del(&sdata->list);
-               mutex_unlock(&sdata->hw->slaves_mtx);
-
-               unregister_netdevice(sdata->dev);
-       }
-
-       rtnl_unlock();
-
-       wpan_phy_unregister(priv->phy);
-}
-EXPORT_SYMBOL(ieee802154_unregister_device);
-
-MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
-MODULE_LICENSE("GPL v2");
similarity index 73%
rename from net/mac802154/mac802154.h
rename to net/mac802154/ieee802154_i.h
index 762a6f849c6b7d3edf3e8677ee6f2081c10c8fac..1086a9d96f8f6d94bc321b579ffe9b4a194dc94e 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  */
-#ifndef MAC802154_H
-#define MAC802154_H
+#ifndef __IEEE802154_I_H
+#define __IEEE802154_I_H
 
 #include <linux/mutex.h>
 #include <net/mac802154.h>
@@ -30,9 +26,9 @@
 #include "llsec.h"
 
 /* mac802154 device private data */
-struct mac802154_priv {
-       struct ieee802154_dev hw;
-       struct ieee802154_ops *ops;
+struct ieee802154_local {
+       struct ieee802154_hw hw;
+       const struct ieee802154_ops *ops;
 
        /* ieee802154 phy */
        struct wpan_phy *phy;
@@ -46,23 +42,27 @@ struct mac802154_priv {
         *
         * So atomic readers can use any of this protection methods.
         */
-       struct list_head        slaves;
-       struct mutex            slaves_mtx;
+       struct list_head        interfaces;
+       struct mutex            iflist_mtx;
 
        /* This one is used for scanning and other jobs not to be interfered
         * with serial driver.
         */
-       struct workqueue_struct *dev_workqueue;
+       struct workqueue_struct *workqueue;
 
-       /* SoftMAC device is registered and running. One can add subinterfaces.
-        * This flag should be modified under slaves_mtx and RTNL, so you can
-        * read them using any of protection methods.
-        */
-       bool running;
+       bool started;
+
+       struct tasklet_struct tasklet;
+       struct sk_buff_head skb_queue;
 };
 
-#define        MAC802154_DEVICE_STOPPED        0x00
-#define MAC802154_DEVICE_RUN           0x01
+enum {
+       IEEE802154_RX_MSG        = 1,
+};
+
+enum ieee802154_sdata_state_bits {
+       SDATA_STATE_RUNNING,
+};
 
 /* Slave interface definition.
  *
@@ -70,23 +70,21 @@ struct mac802154_priv {
  * Each ieee802154 device/transceiver may have several slaves and able
  * to be associated with several networks at the same time.
  */
-struct mac802154_sub_if_data {
+struct ieee802154_sub_if_data {
        struct list_head list; /* the ieee802154_priv->slaves list */
 
-       struct mac802154_priv *hw;
+       struct ieee802154_local *local;
        struct net_device *dev;
 
        int type;
-       bool running;
+       unsigned long state;
 
        spinlock_t mib_lock;
 
        __le16 pan_id;
        __le16 short_addr;
        __le64 extended_addr;
-
-       u8 chan;
-       u8 page;
+       bool promisuous_mode;
 
        struct ieee802154_mac_params mac_params;
 
@@ -103,24 +101,36 @@ struct mac802154_sub_if_data {
        struct mac802154_llsec sec;
 };
 
-#define mac802154_to_priv(_hw) container_of(_hw, struct mac802154_priv, hw)
-
 #define MAC802154_CHAN_NONE            0xff /* No channel is assigned */
 
+static inline struct ieee802154_local *
+hw_to_local(struct ieee802154_hw *hw)
+{
+       return container_of(hw, struct ieee802154_local, hw);
+}
+
+static inline struct ieee802154_sub_if_data *
+IEEE802154_DEV_TO_SUB_IF(const struct net_device *dev)
+{
+       return netdev_priv(dev);
+}
+
+static inline bool
+ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
+{
+       return test_bit(SDATA_STATE_RUNNING, &sdata->state);
+}
+
 extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced;
 extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
 
-int mac802154_slave_open(struct net_device *dev);
-int mac802154_slave_close(struct net_device *dev);
-
-void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb);
 void mac802154_monitor_setup(struct net_device *dev);
+netdev_tx_t
+ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
-void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb);
 void mac802154_wpan_setup(struct net_device *dev);
-
-netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
-                        u8 page, u8 chan);
+netdev_tx_t
+ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* MIB callbacks */
 void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
@@ -131,11 +141,6 @@ void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
 u8 mac802154_dev_get_dsn(const struct net_device *dev);
 
-int mac802154_set_mac_params(struct net_device *dev,
-                            const struct ieee802154_mac_params *params);
-void mac802154_get_mac_params(struct net_device *dev,
-                             struct ieee802154_mac_params *params);
-
 int mac802154_get_params(struct net_device *dev,
                         struct ieee802154_llsec_params *params);
 int mac802154_set_params(struct net_device *dev,
@@ -169,4 +174,4 @@ void mac802154_get_table(struct net_device *dev,
                         struct ieee802154_llsec_table **t);
 void mac802154_unlock_table(struct net_device *dev);
 
-#endif /* MAC802154_H */
+#endif /* __IEEE802154_I_H */
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
new file mode 100644 (file)
index 0000000..f7a6f83
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2007-2012 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ *
+ * Written by:
+ * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Sergey Lapin <slapin@ossfans.org>
+ * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/ieee802154.h>
+
+#include <net/rtnetlink.h>
+#include <linux/nl802154.h>
+#include <net/af_ieee802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/cfg802154.h>
+
+#include "ieee802154_i.h"
+#include "driver-ops.h"
+
+static int mac802154_wpan_update_llsec(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
+       int rc = 0;
+
+       if (ops->llsec) {
+               struct ieee802154_llsec_params params;
+               int changed = 0;
+
+               params.pan_id = sdata->pan_id;
+               changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
+
+               params.hwaddr = sdata->extended_addr;
+               changed |= IEEE802154_LLSEC_PARAM_HWADDR;
+
+               rc = ops->llsec->set_params(dev, &params, changed);
+       }
+
+       return rc;
+}
+
+static int
+mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct sockaddr_ieee802154 *sa =
+               (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
+       int err = -ENOIOCTLCMD;
+
+       spin_lock_bh(&sdata->mib_lock);
+
+       switch (cmd) {
+       case SIOCGIFADDR:
+       {
+               u16 pan_id, short_addr;
+
+               pan_id = le16_to_cpu(sdata->pan_id);
+               short_addr = le16_to_cpu(sdata->short_addr);
+               if (pan_id == IEEE802154_PANID_BROADCAST ||
+                   short_addr == IEEE802154_ADDR_BROADCAST) {
+                       err = -EADDRNOTAVAIL;
+                       break;
+               }
+
+               sa->family = AF_IEEE802154;
+               sa->addr.addr_type = IEEE802154_ADDR_SHORT;
+               sa->addr.pan_id = pan_id;
+               sa->addr.short_addr = short_addr;
+
+               err = 0;
+               break;
+       }
+       case SIOCSIFADDR:
+               dev_warn(&dev->dev,
+                        "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
+               if (sa->family != AF_IEEE802154 ||
+                   sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
+                   sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
+                   sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
+                   sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sdata->pan_id = cpu_to_le16(sa->addr.pan_id);
+               sdata->short_addr = cpu_to_le16(sa->addr.short_addr);
+
+               err = mac802154_wpan_update_llsec(dev);
+               break;
+       }
+
+       spin_unlock_bh(&sdata->mib_lock);
+       return err;
+}
+
+static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       /* FIXME: validate addr */
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       mac802154_dev_set_ieee_addr(dev);
+       return mac802154_wpan_update_llsec(dev);
+}
+
+int mac802154_set_mac_params(struct net_device *dev,
+                            const struct ieee802154_mac_params *params)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       sdata->mac_params = *params;
+       mutex_unlock(&sdata->local->iflist_mtx);
+
+       return 0;
+}
+
+void mac802154_get_mac_params(struct net_device *dev,
+                             struct ieee802154_mac_params *params)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       *params = sdata->mac_params;
+       mutex_unlock(&sdata->local->iflist_mtx);
+}
+
+static int mac802154_slave_open(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_sub_if_data *subif;
+       struct ieee802154_local *local = sdata->local;
+       int res = 0;
+
+       ASSERT_RTNL();
+
+       if (sdata->type == IEEE802154_DEV_WPAN) {
+               mutex_lock(&sdata->local->iflist_mtx);
+               list_for_each_entry(subif, &sdata->local->interfaces, list) {
+                       if (subif != sdata && subif->type == sdata->type &&
+                           ieee802154_sdata_running(subif)) {
+                               mutex_unlock(&sdata->local->iflist_mtx);
+                               return -EBUSY;
+                       }
+               }
+               mutex_unlock(&sdata->local->iflist_mtx);
+       }
+
+       set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+       if (!local->open_count) {
+               res = drv_start(local);
+               WARN_ON(res);
+               if (res)
+                       goto err;
+       }
+
+       local->open_count++;
+       netif_start_queue(dev);
+       return 0;
+err:
+       /* might already be clear but that doesn't matter */
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+       return res;
+}
+
+static int mac802154_wpan_open(struct net_device *dev)
+{
+       int rc;
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local = sdata->local;
+       struct wpan_phy *phy = sdata->local->phy;
+
+       rc = mac802154_slave_open(dev);
+       if (rc < 0)
+               return rc;
+
+       mutex_lock(&phy->pib_lock);
+
+       if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
+               rc = drv_set_promiscuous_mode(local, sdata->promisuous_mode);
+               if (rc < 0)
+                       goto out;
+       }
+
+       if (local->hw.flags & IEEE802154_HW_TXPOWER) {
+               rc = drv_set_tx_power(local, sdata->mac_params.transmit_power);
+               if (rc < 0)
+                       goto out;
+       }
+
+       if (local->hw.flags & IEEE802154_HW_LBT) {
+               rc = drv_set_lbt_mode(local, sdata->mac_params.lbt);
+               if (rc < 0)
+                       goto out;
+       }
+
+       if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
+               rc = drv_set_cca_mode(local, sdata->mac_params.cca_mode);
+               if (rc < 0)
+                       goto out;
+       }
+
+       if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) {
+               rc = drv_set_cca_ed_level(local,
+                                         sdata->mac_params.cca_ed_level);
+               if (rc < 0)
+                       goto out;
+       }
+
+       if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
+               rc = drv_set_csma_params(local, sdata->mac_params.min_be,
+                                        sdata->mac_params.max_be,
+                                        sdata->mac_params.csma_retries);
+               if (rc < 0)
+                       goto out;
+       }
+
+       if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
+               rc = drv_set_max_frame_retries(local,
+                                              sdata->mac_params.frame_retries);
+               if (rc < 0)
+                       goto out;
+       }
+
+       mutex_unlock(&phy->pib_lock);
+       return 0;
+
+out:
+       mutex_unlock(&phy->pib_lock);
+       return rc;
+}
+
+static int mac802154_slave_close(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local = sdata->local;
+
+       ASSERT_RTNL();
+
+       netif_stop_queue(dev);
+       local->open_count--;
+
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+       if (!local->open_count)
+               drv_stop(local);
+
+       return 0;
+}
+
+static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
+                                        struct ieee802154_hdr *hdr,
+                                        const struct ieee802154_mac_cb *cb)
+{
+       struct ieee802154_llsec_params params;
+       u8 level;
+
+       mac802154_llsec_get_params(&sdata->sec, &params);
+
+       if (!params.enabled && cb->secen_override && cb->secen)
+               return -EINVAL;
+       if (!params.enabled ||
+           (cb->secen_override && !cb->secen) ||
+           !params.out_level)
+               return 0;
+       if (cb->seclevel_override && !cb->seclevel)
+               return -EINVAL;
+
+       level = cb->seclevel_override ? cb->seclevel : params.out_level;
+
+       hdr->fc.security_enabled = 1;
+       hdr->sec.level = level;
+       hdr->sec.key_id_mode = params.out_key.mode;
+       if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
+               hdr->sec.short_src = params.out_key.short_source;
+       else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
+               hdr->sec.extended_src = params.out_key.extended_source;
+       hdr->sec.key_id = params.out_key.id;
+
+       return 0;
+}
+
+static int mac802154_header_create(struct sk_buff *skb,
+                                  struct net_device *dev,
+                                  unsigned short type,
+                                  const void *daddr,
+                                  const void *saddr,
+                                  unsigned len)
+{
+       struct ieee802154_hdr hdr;
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_mac_cb *cb = mac_cb(skb);
+       int hlen;
+
+       if (!daddr)
+               return -EINVAL;
+
+       memset(&hdr.fc, 0, sizeof(hdr.fc));
+       hdr.fc.type = cb->type;
+       hdr.fc.security_enabled = cb->secen;
+       hdr.fc.ack_request = cb->ackreq;
+       hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+
+       if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
+               return -EINVAL;
+
+       if (!saddr) {
+               spin_lock_bh(&sdata->mib_lock);
+
+               if (sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
+                   sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+                   sdata->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+                       hdr.source.mode = IEEE802154_ADDR_LONG;
+                       hdr.source.extended_addr = sdata->extended_addr;
+               } else {
+                       hdr.source.mode = IEEE802154_ADDR_SHORT;
+                       hdr.source.short_addr = sdata->short_addr;
+               }
+
+               hdr.source.pan_id = sdata->pan_id;
+
+               spin_unlock_bh(&sdata->mib_lock);
+       } else {
+               hdr.source = *(const struct ieee802154_addr *)saddr;
+       }
+
+       hdr.dest = *(const struct ieee802154_addr *)daddr;
+
+       hlen = ieee802154_hdr_push(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
+
+       skb_reset_mac_header(skb);
+       skb->mac_len = hlen;
+
+       if (len > ieee802154_max_payload(&hdr))
+               return -EMSGSIZE;
+
+       return hlen;
+}
+
+static int
+mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+       struct ieee802154_hdr hdr;
+       struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
+
+       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
+               pr_debug("malformed packet\n");
+               return 0;
+       }
+
+       *addr = hdr.source;
+       return sizeof(*addr);
+}
+
+static struct header_ops mac802154_header_ops = {
+       .create         = mac802154_header_create,
+       .parse          = mac802154_header_parse,
+};
+
+static const struct net_device_ops mac802154_wpan_ops = {
+       .ndo_open               = mac802154_wpan_open,
+       .ndo_stop               = mac802154_slave_close,
+       .ndo_start_xmit         = ieee802154_subif_start_xmit,
+       .ndo_do_ioctl           = mac802154_wpan_ioctl,
+       .ndo_set_mac_address    = mac802154_wpan_mac_addr,
+};
+
+static const struct net_device_ops mac802154_monitor_ops = {
+       .ndo_open               = mac802154_wpan_open,
+       .ndo_stop               = mac802154_slave_close,
+       .ndo_start_xmit         = ieee802154_monitor_start_xmit,
+};
+
+static void mac802154_wpan_free(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       mac802154_llsec_destroy(&sdata->sec);
+
+       free_netdev(dev);
+}
+
+void mac802154_wpan_setup(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata;
+
+       dev->addr_len           = IEEE802154_ADDR_LEN;
+       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+
+       dev->hard_header_len    = MAC802154_FRAME_HARD_HEADER_LEN;
+       dev->header_ops         = &mac802154_header_ops;
+       dev->needed_tailroom    = 2 + 16; /* FCS + MIC */
+       dev->mtu                = IEEE802154_MTU;
+       dev->tx_queue_len       = 300;
+       dev->type               = ARPHRD_IEEE802154;
+       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+
+       dev->destructor         = mac802154_wpan_free;
+       dev->netdev_ops         = &mac802154_wpan_ops;
+       dev->ml_priv            = &mac802154_mlme_wpan;
+
+       sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       sdata->type = IEEE802154_DEV_WPAN;
+
+       spin_lock_init(&sdata->mib_lock);
+       mutex_init(&sdata->sec_mtx);
+
+       get_random_bytes(&sdata->bsn, 1);
+       get_random_bytes(&sdata->dsn, 1);
+
+       /* defaults per 802.15.4-2011 */
+       sdata->mac_params.min_be = 3;
+       sdata->mac_params.max_be = 5;
+       sdata->mac_params.csma_retries = 4;
+       /* for compatibility, actual default is 3 */
+       sdata->mac_params.frame_retries = -1;
+
+       sdata->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+       sdata->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+
+       sdata->promisuous_mode = false;
+
+       mac802154_llsec_init(&sdata->sec);
+}
+
+void mac802154_monitor_setup(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata;
+
+       dev->needed_tailroom    = 2; /* room for FCS */
+       dev->mtu                = IEEE802154_MTU;
+       dev->tx_queue_len       = 10;
+       dev->type               = ARPHRD_IEEE802154_MONITOR;
+       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+
+       dev->destructor         = free_netdev;
+       dev->netdev_ops         = &mac802154_monitor_ops;
+       dev->ml_priv            = &mac802154_mlme_reduced;
+
+       sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       sdata->type = IEEE802154_DEV_MONITOR;
+
+       sdata->promisuous_mode = true;
+}
index 457058142098376bb9731600a9c162aaf4247b64..fa0d5237c2e08ba35cf4229b4527dbdb3030062c 100644 (file)
 #include <linux/err.h>
 #include <linux/bug.h>
 #include <linux/completion.h>
-#include <net/ieee802154.h>
+#include <linux/ieee802154.h>
 #include <crypto/algapi.h>
 
-#include "mac802154.h"
+#include "ieee802154_i.h"
 #include "llsec.h"
 
 static void llsec_key_put(struct mac802154_llsec_key *key);
index bf809131eef776209040a8496ed1e2214e6bdebe..fc261ab333477d167f972d5a8120db9366dd1862 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Sergey Lapin <slapin@ossfans.org>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
+#include <linux/ieee802154.h>
 
-#include <net/ieee802154.h>
 #include <net/ieee802154_netdev.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 #include <net/mac802154.h>
 #include <net/nl802154.h>
 
-#include "mac802154.h"
+#include "ieee802154_i.h"
 
 static int mac802154_mlme_start_req(struct net_device *dev,
                                    struct ieee802154_addr *addr,
@@ -79,11 +75,33 @@ static int mac802154_mlme_start_req(struct net_device *dev,
 
 static struct wpan_phy *mac802154_get_phy(const struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return to_phy(get_device(&priv->hw->phy->dev));
+       return to_phy(get_device(&sdata->local->phy->dev));
+}
+
+static int mac802154_set_mac_params(struct net_device *dev,
+                                   const struct ieee802154_mac_params *params)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       sdata->mac_params = *params;
+       mutex_unlock(&sdata->local->iflist_mtx);
+
+       return 0;
+}
+
+static void mac802154_get_mac_params(struct net_device *dev,
+                                    struct ieee802154_mac_params *params)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       *params = sdata->mac_params;
+       mutex_unlock(&sdata->local->iflist_mtx);
 }
 
 static struct ieee802154_llsec_ops mac802154_llsec_ops = {
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
new file mode 100644 (file)
index 0000000..86e533e
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2007-2012 Siemens AG
+ *
+ * Written by:
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ *
+ * Based on the code from 'linux-zigbee.sourceforge.net' project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include <net/netlink.h>
+#include <linux/nl802154.h>
+#include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/route.h>
+#include <net/cfg802154.h>
+
+#include "ieee802154_i.h"
+
+static int
+mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local;
+       int err;
+
+       local = wpan_phy_priv(phy);
+
+       sdata->dev = dev;
+       sdata->local = local;
+
+       dev->needed_headroom = local->hw.extra_tx_headroom;
+
+       SET_NETDEV_DEV(dev, &local->phy->dev);
+
+       err = register_netdev(dev);
+       if (err < 0)
+               return err;
+
+       rtnl_lock();
+       mutex_lock(&local->iflist_mtx);
+       list_add_tail_rcu(&sdata->list, &local->interfaces);
+       mutex_unlock(&local->iflist_mtx);
+       rtnl_unlock();
+
+       return 0;
+}
+
+static void
+mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       ASSERT_RTNL();
+
+       BUG_ON(sdata->local->phy != phy);
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       list_del_rcu(&sdata->list);
+       mutex_unlock(&sdata->local->iflist_mtx);
+
+       synchronize_rcu();
+       unregister_netdevice(sdata->dev);
+}
+
+static struct net_device *
+mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
+{
+       struct net_device *dev;
+       int err = -ENOMEM;
+
+       switch (type) {
+       case IEEE802154_DEV_MONITOR:
+               dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
+                                  name, NET_NAME_UNKNOWN,
+                                  mac802154_monitor_setup);
+               break;
+       case IEEE802154_DEV_WPAN:
+               dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
+                                  name, NET_NAME_UNKNOWN,
+                                  mac802154_wpan_setup);
+               break;
+       default:
+               dev = NULL;
+               err = -EINVAL;
+               break;
+       }
+       if (!dev)
+               goto err;
+
+       err = mac802154_netdev_register(phy, dev);
+       if (err)
+               goto err_free;
+
+       dev_hold(dev); /* we return an incremented device refcount */
+       return dev;
+
+err_free:
+       free_netdev(dev);
+err:
+       return ERR_PTR(err);
+}
+
+static void ieee802154_tasklet_handler(unsigned long data)
+{
+       struct ieee802154_local *local = (struct ieee802154_local *)data;
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&local->skb_queue))) {
+               switch (skb->pkt_type) {
+               case IEEE802154_RX_MSG:
+                       /* Clear skb->pkt_type in order to not confuse kernel
+                        * netstack.
+                        */
+                       skb->pkt_type = 0;
+                       ieee802154_rx(&local->hw, skb);
+                       break;
+               default:
+                       WARN(1, "mac802154: Packet is of unknown type %d\n",
+                            skb->pkt_type);
+                       kfree_skb(skb);
+                       break;
+               }
+       }
+}
+
+struct ieee802154_hw *
+ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
+{
+       struct wpan_phy *phy;
+       struct ieee802154_local *local;
+       size_t priv_size;
+
+       if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
+           !ops->start || !ops->stop || !ops->set_channel) {
+               pr_err("undefined IEEE802.15.4 device operations\n");
+               return NULL;
+       }
+
+       /* Ensure 32-byte alignment of our private data and hw private data.
+        * We use the wpan_phy priv data for both our ieee802154_local and for
+        * the driver's private data
+        *
+        * in memory it'll be like this:
+        *
+        * +-------------------------+
+        * | struct wpan_phy         |
+        * +-------------------------+
+        * | struct ieee802154_local |
+        * +-------------------------+
+        * | driver's private data   |
+        * +-------------------------+
+        *
+        * Due to ieee802154 layer isn't aware of driver and MAC structures,
+        * so lets align them here.
+        */
+
+       priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
+
+       phy = wpan_phy_alloc(priv_size);
+       if (!phy) {
+               pr_err("failure to allocate master IEEE802.15.4 device\n");
+               return NULL;
+       }
+
+       local = wpan_phy_priv(phy);
+       local->phy = phy;
+       local->hw.phy = local->phy;
+       local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
+       local->ops = ops;
+
+       INIT_LIST_HEAD(&local->interfaces);
+       mutex_init(&local->iflist_mtx);
+
+       tasklet_init(&local->tasklet,
+                    ieee802154_tasklet_handler,
+                    (unsigned long)local);
+
+       skb_queue_head_init(&local->skb_queue);
+
+       return &local->hw;
+}
+EXPORT_SYMBOL(ieee802154_alloc_hw);
+
+void ieee802154_free_hw(struct ieee802154_hw *hw)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+
+       BUG_ON(!list_empty(&local->interfaces));
+
+       mutex_destroy(&local->iflist_mtx);
+
+       wpan_phy_free(local->phy);
+}
+EXPORT_SYMBOL(ieee802154_free_hw);
+
+int ieee802154_register_hw(struct ieee802154_hw *hw)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+       int rc = -ENOSYS;
+
+       local->workqueue =
+               create_singlethread_workqueue(wpan_phy_name(local->phy));
+       if (!local->workqueue) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       wpan_phy_set_dev(local->phy, local->hw.parent);
+
+       local->phy->add_iface = mac802154_add_iface;
+       local->phy->del_iface = mac802154_del_iface;
+
+       rc = wpan_phy_register(local->phy);
+       if (rc < 0)
+               goto out_wq;
+
+       return 0;
+
+out_wq:
+       destroy_workqueue(local->workqueue);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(ieee802154_register_hw);
+
+void ieee802154_unregister_hw(struct ieee802154_hw *hw)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+       struct ieee802154_sub_if_data *sdata, *next;
+
+       tasklet_kill(&local->tasklet);
+       flush_workqueue(local->workqueue);
+       destroy_workqueue(local->workqueue);
+
+       rtnl_lock();
+
+       list_for_each_entry_safe(sdata, next, &local->interfaces, list) {
+               mutex_lock(&sdata->local->iflist_mtx);
+               list_del(&sdata->list);
+               mutex_unlock(&sdata->local->iflist_mtx);
+
+               unregister_netdevice(sdata->dev);
+       }
+
+       rtnl_unlock();
+
+       wpan_phy_unregister(local->phy);
+}
+EXPORT_SYMBOL(ieee802154_unregister_hw);
+
+MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
+MODULE_LICENSE("GPL v2");
index 868a040fd422ea6e877cc7df036b425f8b62008e..0184fced2f62372aed120c8e248dfefa6079a53e 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  * Sergey Lapin <slapin@ossfans.org>
 
 #include <net/mac802154.h>
 #include <net/ieee802154_netdev.h>
-#include <net/wpan-phy.h>
-
-#include "mac802154.h"
+#include <net/cfg802154.h>
 
-struct phy_chan_notify_work {
-       struct work_struct work;
-       struct net_device *dev;
-};
+#include "ieee802154_i.h"
+#include "driver-ops.h"
 
 struct hw_addr_filt_notify_work {
        struct work_struct work;
@@ -40,25 +32,24 @@ struct hw_addr_filt_notify_work {
        unsigned long changed;
 };
 
-static struct mac802154_priv *mac802154_slave_get_priv(struct net_device *dev)
+static struct ieee802154_local *mac802154_slave_get_priv(struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return priv->hw;
+       return sdata->local;
 }
 
 static void hw_addr_notify(struct work_struct *work)
 {
        struct hw_addr_filt_notify_work *nw = container_of(work,
                        struct hw_addr_filt_notify_work, work);
-       struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev);
+       struct ieee802154_local *local = mac802154_slave_get_priv(nw->dev);
        int res;
 
-       res = hw->ops->set_hw_addr_filt(&hw->hw,
-                                       &hw->hw.hw_filt,
-                                       nw->changed);
+       res = local->ops->set_hw_addr_filt(&local->hw, &local->hw.hw_filt,
+                                          nw->changed);
        if (res)
                pr_debug("failed changed mask %lx\n", nw->changed);
 
@@ -67,7 +58,7 @@ static void hw_addr_notify(struct work_struct *work)
 
 static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct hw_addr_filt_notify_work *work;
 
        work = kzalloc(sizeof(*work), GFP_ATOMIC);
@@ -77,141 +68,110 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
        INIT_WORK(&work->work, hw_addr_notify);
        work->dev = dev;
        work->changed = changed;
-       queue_work(priv->hw->dev_workqueue, &work->work);
+       queue_work(sdata->local->workqueue, &work->work);
 }
 
 void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       spin_lock_bh(&priv->mib_lock);
-       priv->short_addr = val;
-       spin_unlock_bh(&priv->mib_lock);
+       spin_lock_bh(&sdata->mib_lock);
+       sdata->short_addr = val;
+       spin_unlock_bh(&sdata->mib_lock);
 
-       if ((priv->hw->ops->set_hw_addr_filt) &&
-           (priv->hw->hw.hw_filt.short_addr != priv->short_addr)) {
-               priv->hw->hw.hw_filt.short_addr = priv->short_addr;
-               set_hw_addr_filt(dev, IEEE802515_AFILT_SADDR_CHANGED);
+       if ((sdata->local->ops->set_hw_addr_filt) &&
+           (sdata->local->hw.hw_filt.short_addr != sdata->short_addr)) {
+               sdata->local->hw.hw_filt.short_addr = sdata->short_addr;
+               set_hw_addr_filt(dev, IEEE802154_AFILT_SADDR_CHANGED);
        }
 }
 
 __le16 mac802154_dev_get_short_addr(const struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        __le16 ret;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       spin_lock_bh(&priv->mib_lock);
-       ret = priv->short_addr;
-       spin_unlock_bh(&priv->mib_lock);
+       spin_lock_bh(&sdata->mib_lock);
+       ret = sdata->short_addr;
+       spin_unlock_bh(&sdata->mib_lock);
 
        return ret;
 }
 
 void mac802154_dev_set_ieee_addr(struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct mac802154_priv *mac = priv->hw;
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local = sdata->local;
 
-       priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+       sdata->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
 
-       if (mac->ops->set_hw_addr_filt &&
-           mac->hw.hw_filt.ieee_addr != priv->extended_addr) {
-               mac->hw.hw_filt.ieee_addr = priv->extended_addr;
-               set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED);
+       if (local->ops->set_hw_addr_filt &&
+           local->hw.hw_filt.ieee_addr != sdata->extended_addr) {
+               local->hw.hw_filt.ieee_addr = sdata->extended_addr;
+               set_hw_addr_filt(dev, IEEE802154_AFILT_IEEEADDR_CHANGED);
        }
 }
 
 __le16 mac802154_dev_get_pan_id(const struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        __le16 ret;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       spin_lock_bh(&priv->mib_lock);
-       ret = priv->pan_id;
-       spin_unlock_bh(&priv->mib_lock);
+       spin_lock_bh(&sdata->mib_lock);
+       ret = sdata->pan_id;
+       spin_unlock_bh(&sdata->mib_lock);
 
        return ret;
 }
 
 void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       spin_lock_bh(&priv->mib_lock);
-       priv->pan_id = val;
-       spin_unlock_bh(&priv->mib_lock);
+       spin_lock_bh(&sdata->mib_lock);
+       sdata->pan_id = val;
+       spin_unlock_bh(&sdata->mib_lock);
 
-       if ((priv->hw->ops->set_hw_addr_filt) &&
-           (priv->hw->hw.hw_filt.pan_id != priv->pan_id)) {
-               priv->hw->hw.hw_filt.pan_id = priv->pan_id;
-               set_hw_addr_filt(dev, IEEE802515_AFILT_PANID_CHANGED);
+       if ((sdata->local->ops->set_hw_addr_filt) &&
+           (sdata->local->hw.hw_filt.pan_id != sdata->pan_id)) {
+               sdata->local->hw.hw_filt.pan_id = sdata->pan_id;
+               set_hw_addr_filt(dev, IEEE802154_AFILT_PANID_CHANGED);
        }
 }
 
 u8 mac802154_dev_get_dsn(const struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return priv->dsn++;
-}
-
-static void phy_chan_notify(struct work_struct *work)
-{
-       struct phy_chan_notify_work *nw = container_of(work,
-                                         struct phy_chan_notify_work, work);
-       struct mac802154_priv *hw = mac802154_slave_get_priv(nw->dev);
-       struct mac802154_sub_if_data *priv = netdev_priv(nw->dev);
-       int res;
-
-       mutex_lock(&priv->hw->phy->pib_lock);
-       res = hw->ops->set_channel(&hw->hw, priv->page, priv->chan);
-       if (res) {
-               pr_debug("set_channel failed\n");
-       } else {
-               priv->hw->phy->current_channel = priv->chan;
-               priv->hw->phy->current_page = priv->page;
-       }
-       mutex_unlock(&priv->hw->phy->pib_lock);
-
-       kfree(nw);
+       return sdata->dsn++;
 }
 
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct phy_chan_notify_work *work;
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local = sdata->local;
+       int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       spin_lock_bh(&priv->mib_lock);
-       priv->page = page;
-       priv->chan = chan;
-       spin_unlock_bh(&priv->mib_lock);
-
-       mutex_lock(&priv->hw->phy->pib_lock);
-       if (priv->hw->phy->current_channel != priv->chan ||
-           priv->hw->phy->current_page != priv->page) {
-               mutex_unlock(&priv->hw->phy->pib_lock);
-
-               work = kzalloc(sizeof(*work), GFP_ATOMIC);
-               if (!work)
-                       return;
-
-               INIT_WORK(&work->work, phy_chan_notify);
-               work->dev = dev;
-               queue_work(priv->hw->dev_workqueue, &work->work);
+       res = drv_set_channel(local, page, chan);
+       if (res) {
+               pr_debug("set_channel failed\n");
        } else {
-               mutex_unlock(&priv->hw->phy->pib_lock);
+               mutex_lock(&local->phy->pib_lock);
+               local->phy->current_channel = chan;
+               local->phy->current_page = page;
+               mutex_unlock(&local->phy->pib_lock);
        }
 }
 
@@ -219,14 +179,14 @@ void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan)
 int mac802154_get_params(struct net_device *dev,
                         struct ieee802154_llsec_params *params)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_get_params(&priv->sec, params);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_get_params(&sdata->sec, params);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -235,14 +195,14 @@ int mac802154_set_params(struct net_device *dev,
                         const struct ieee802154_llsec_params *params,
                         int changed)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_set_params(&priv->sec, params, changed);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_set_params(&sdata->sec, params, changed);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -252,14 +212,14 @@ int mac802154_add_key(struct net_device *dev,
                      const struct ieee802154_llsec_key_id *id,
                      const struct ieee802154_llsec_key *key)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_key_add(&priv->sec, id, key);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_key_add(&sdata->sec, id, key);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -267,14 +227,14 @@ int mac802154_add_key(struct net_device *dev,
 int mac802154_del_key(struct net_device *dev,
                      const struct ieee802154_llsec_key_id *id)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_key_del(&priv->sec, id);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_key_del(&sdata->sec, id);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -283,28 +243,28 @@ int mac802154_del_key(struct net_device *dev,
 int mac802154_add_dev(struct net_device *dev,
                      const struct ieee802154_llsec_device *llsec_dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_dev_add(&priv->sec, llsec_dev);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_dev_add(&sdata->sec, llsec_dev);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
 
 int mac802154_del_dev(struct net_device *dev, __le64 dev_addr)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_dev_del(&priv->sec, dev_addr);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_dev_del(&sdata->sec, dev_addr);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -314,14 +274,14 @@ int mac802154_add_devkey(struct net_device *dev,
                         __le64 device_addr,
                         const struct ieee802154_llsec_device_key *key)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_devkey_add(&priv->sec, device_addr, key);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_devkey_add(&sdata->sec, device_addr, key);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -330,14 +290,14 @@ int mac802154_del_devkey(struct net_device *dev,
                         __le64 device_addr,
                         const struct ieee802154_llsec_device_key *key)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_devkey_del(&priv->sec, device_addr, key);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_devkey_del(&sdata->sec, device_addr, key);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -346,14 +306,14 @@ int mac802154_del_devkey(struct net_device *dev,
 int mac802154_add_seclevel(struct net_device *dev,
                           const struct ieee802154_llsec_seclevel *sl)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_seclevel_add(&priv->sec, sl);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_seclevel_add(&sdata->sec, sl);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -361,14 +321,14 @@ int mac802154_add_seclevel(struct net_device *dev,
 int mac802154_del_seclevel(struct net_device *dev,
                           const struct ieee802154_llsec_seclevel *sl)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        int res;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
-       res = mac802154_llsec_seclevel_del(&priv->sec, sl);
-       mutex_unlock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
+       res = mac802154_llsec_seclevel_del(&sdata->sec, sl);
+       mutex_unlock(&sdata->sec_mtx);
 
        return res;
 }
@@ -376,28 +336,28 @@ int mac802154_del_seclevel(struct net_device *dev,
 
 void mac802154_lock_table(struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_lock(&priv->sec_mtx);
+       mutex_lock(&sdata->sec_mtx);
 }
 
 void mac802154_get_table(struct net_device *dev,
                         struct ieee802154_llsec_table **t)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       *t = &priv->sec.table;
+       *t = &sdata->sec.table;
 }
 
 void mac802154_unlock_table(struct net_device *dev)
 {
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       mutex_unlock(&priv->sec_mtx);
+       mutex_unlock(&sdata->sec_mtx);
 }
diff --git a/net/mac802154/monitor.c b/net/mac802154/monitor.c
deleted file mode 100644 (file)
index a68230e..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2007, 2008, 2009 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Sergey Lapin <slapin@ossfans.org>
- * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/crc-ccitt.h>
-
-#include <net/ieee802154.h>
-#include <net/mac802154.h>
-#include <net/netlink.h>
-#include <net/wpan-phy.h>
-#include <linux/nl802154.h>
-
-#include "mac802154.h"
-
-static netdev_tx_t mac802154_monitor_xmit(struct sk_buff *skb,
-                                         struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv;
-       u8 chan, page;
-
-       priv = netdev_priv(dev);
-
-       /* FIXME: locking */
-       chan = priv->hw->phy->current_channel;
-       page = priv->hw->phy->current_page;
-
-       if (chan == MAC802154_CHAN_NONE) /* not initialized */
-               return NETDEV_TX_OK;
-
-       if (WARN_ON(page >= WPAN_NUM_PAGES) ||
-           WARN_ON(chan >= WPAN_NUM_CHANNELS))
-               return NETDEV_TX_OK;
-
-       skb->skb_iif = dev->ifindex;
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       return mac802154_tx(priv->hw, skb, page, chan);
-}
-
-
-void mac802154_monitors_rx(struct mac802154_priv *priv, struct sk_buff *skb)
-{
-       struct sk_buff *skb2;
-       struct mac802154_sub_if_data *sdata;
-       u16 crc = crc_ccitt(0, skb->data, skb->len);
-       u8 *data;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &priv->slaves, list) {
-               if (sdata->type != IEEE802154_DEV_MONITOR ||
-                   !netif_running(sdata->dev))
-                       continue;
-
-               skb2 = skb_clone(skb, GFP_ATOMIC);
-               skb2->dev = sdata->dev;
-               skb2->pkt_type = PACKET_HOST;
-               data = skb_put(skb2, 2);
-               data[0] = crc & 0xff;
-               data[1] = crc >> 8;
-
-               netif_rx_ni(skb2);
-       }
-       rcu_read_unlock();
-}
-
-static const struct net_device_ops mac802154_monitor_ops = {
-       .ndo_open               = mac802154_slave_open,
-       .ndo_stop               = mac802154_slave_close,
-       .ndo_start_xmit         = mac802154_monitor_xmit,
-};
-
-void mac802154_monitor_setup(struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv;
-
-       dev->addr_len           = 0;
-       dev->hard_header_len    = 0;
-       dev->needed_tailroom    = 2; /* room for FCS */
-       dev->mtu                = IEEE802154_MTU;
-       dev->tx_queue_len       = 10;
-       dev->type               = ARPHRD_IEEE802154_MONITOR;
-       dev->flags              = IFF_NOARP | IFF_BROADCAST;
-       dev->watchdog_timeo     = 0;
-
-       dev->destructor         = free_netdev;
-       dev->netdev_ops         = &mac802154_monitor_ops;
-       dev->ml_priv            = &mac802154_mlme_reduced;
-
-       priv = netdev_priv(dev);
-       priv->type = IEEE802154_DEV_MONITOR;
-
-       priv->chan = MAC802154_CHAN_NONE; /* not initialized */
-       priv->page = 0;
-}
index a14cf9ede171e7bcc2c1373931e5e7754b36bab4..95961cccc253a3e6da82195c7e4ad8421088bd29 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/workqueue.h>
 #include <linux/netdevice.h>
 #include <linux/crc-ccitt.h>
+#include <asm/unaligned.h>
 
 #include <net/mac802154.h>
 #include <net/ieee802154_netdev.h>
+#include <net/rtnetlink.h>
+#include <linux/nl802154.h>
 
-#include "mac802154.h"
+#include "ieee802154_i.h"
 
-/* The IEEE 802.15.4 standard defines 4 MAC packet types:
- * - beacon frame
- * - MAC command frame
- * - acknowledgement frame
- * - data frame
- *
- * and only the data frame should be pushed to the upper layers, other types
- * are just internal MAC layer management information. So only data packets
- * are going to be sent to the networking queue, all other will be processed
- * right here by using the device workqueue.
- */
-struct rx_work {
-       struct sk_buff *skb;
-       struct work_struct work;
-       struct ieee802154_dev *dev;
-       u8 lqi;
-};
+static int ieee802154_deliver_skb(struct sk_buff *skb)
+{
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->protocol = htons(ETH_P_IEEE802154);
 
-static void
-mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi)
+       return netif_receive_skb(skb);
+}
+
+static int
+ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
+                      struct sk_buff *skb, const struct ieee802154_hdr *hdr)
 {
-       struct mac802154_priv *priv = mac802154_to_priv(hw);
+       __le16 span, sshort;
+       int rc;
 
-       mac_cb(skb)->lqi = lqi;
-       skb->protocol = htons(ETH_P_IEEE802154);
-       skb_reset_mac_header(skb);
+       pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
 
-       if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
-               u16 crc;
+       spin_lock_bh(&sdata->mib_lock);
 
-               if (skb->len < 2) {
-                       pr_debug("got invalid frame\n");
-                       goto fail;
-               }
-               crc = crc_ccitt(0, skb->data, skb->len);
-               if (crc) {
-                       pr_debug("CRC mismatch\n");
-                       goto fail;
-               }
-               skb_trim(skb, skb->len - 2); /* CRC */
+       span = sdata->pan_id;
+       sshort = sdata->short_addr;
+
+       switch (mac_cb(skb)->dest.mode) {
+       case IEEE802154_ADDR_NONE:
+               if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
+                       /* FIXME: check if we are PAN coordinator */
+                       skb->pkt_type = PACKET_OTHERHOST;
+               else
+                       /* ACK comes with both addresses empty */
+                       skb->pkt_type = PACKET_HOST;
+               break;
+       case IEEE802154_ADDR_LONG:
+               if (mac_cb(skb)->dest.pan_id != span &&
+                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
+                       skb->pkt_type = PACKET_OTHERHOST;
+               else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
+                       skb->pkt_type = PACKET_HOST;
+               else
+                       skb->pkt_type = PACKET_OTHERHOST;
+               break;
+       case IEEE802154_ADDR_SHORT:
+               if (mac_cb(skb)->dest.pan_id != span &&
+                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
+                       skb->pkt_type = PACKET_OTHERHOST;
+               else if (mac_cb(skb)->dest.short_addr == sshort)
+                       skb->pkt_type = PACKET_HOST;
+               else if (mac_cb(skb)->dest.short_addr ==
+                         cpu_to_le16(IEEE802154_ADDR_BROADCAST))
+                       skb->pkt_type = PACKET_BROADCAST;
+               else
+                       skb->pkt_type = PACKET_OTHERHOST;
+               break;
+       default:
+               spin_unlock_bh(&sdata->mib_lock);
+               pr_debug("invalid dest mode\n");
+               kfree_skb(skb);
+               return NET_RX_DROP;
        }
 
-       mac802154_monitors_rx(priv, skb);
-       mac802154_wpans_rx(priv, skb);
+       spin_unlock_bh(&sdata->mib_lock);
 
-       return;
+       skb->dev = sdata->dev;
+
+       rc = mac802154_llsec_decrypt(&sdata->sec, skb);
+       if (rc) {
+               pr_debug("decryption failed: %i\n", rc);
+               goto fail;
+       }
+
+       sdata->dev->stats.rx_packets++;
+       sdata->dev->stats.rx_bytes += skb->len;
+
+       switch (mac_cb(skb)->type) {
+       case IEEE802154_FC_TYPE_DATA:
+               return ieee802154_deliver_skb(skb);
+       default:
+               pr_warn("ieee802154: bad frame received (type = %d)\n",
+                       mac_cb(skb)->type);
+               goto fail;
+       }
 
 fail:
        kfree_skb(skb);
+       return NET_RX_DROP;
 }
 
-static void mac802154_rx_worker(struct work_struct *work)
+static void
+ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
 {
-       struct rx_work *rw = container_of(work, struct rx_work, work);
+       if (addr->mode == IEEE802154_ADDR_NONE)
+               pr_debug("%s not present\n", name);
+
+       pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
+       if (addr->mode == IEEE802154_ADDR_SHORT) {
+               pr_debug("%s is short: %04x\n", name,
+                        le16_to_cpu(addr->short_addr));
+       } else {
+               u64 hw = swab64((__force u64)addr->extended_addr);
 
-       mac802154_subif_rx(rw->dev, rw->skb, rw->lqi);
-       kfree(rw);
+               pr_debug("%s is hardware: %8phC\n", name, &hw);
+       }
 }
 
-void
-ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
+static int
+ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
 {
-       struct mac802154_priv *priv = mac802154_to_priv(dev);
-       struct rx_work *work;
+       int hlen;
+       struct ieee802154_mac_cb *cb = mac_cb_init(skb);
 
-       if (!skb)
-               return;
+       skb_reset_mac_header(skb);
+
+       hlen = ieee802154_hdr_pull(skb, hdr);
+       if (hlen < 0)
+               return -EINVAL;
+
+       skb->mac_len = hlen;
+
+       pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
+                hdr->seq);
+
+       cb->type = hdr->fc.type;
+       cb->ackreq = hdr->fc.ack_request;
+       cb->secen = hdr->fc.security_enabled;
+
+       ieee802154_print_addr("destination", &hdr->dest);
+       ieee802154_print_addr("source", &hdr->source);
+
+       cb->source = hdr->source;
+       cb->dest = hdr->dest;
+
+       if (hdr->fc.security_enabled) {
+               u64 key;
+
+               pr_debug("seclevel %i\n", hdr->sec.level);
+
+               switch (hdr->sec.key_id_mode) {
+               case IEEE802154_SCF_KEY_IMPLICIT:
+                       pr_debug("implicit key\n");
+                       break;
+
+               case IEEE802154_SCF_KEY_INDEX:
+                       pr_debug("key %02x\n", hdr->sec.key_id);
+                       break;
+
+               case IEEE802154_SCF_KEY_SHORT_INDEX:
+                       pr_debug("key %04x:%04x %02x\n",
+                                le32_to_cpu(hdr->sec.short_src) >> 16,
+                                le32_to_cpu(hdr->sec.short_src) & 0xffff,
+                                hdr->sec.key_id);
+                       break;
+
+               case IEEE802154_SCF_KEY_HW_INDEX:
+                       key = swab64((__force u64)hdr->sec.extended_src);
+                       pr_debug("key source %8phC %02x\n", &key,
+                                hdr->sec.key_id);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void
+__ieee802154_rx_handle_packet(struct ieee802154_local *local,
+                             struct sk_buff *skb)
+{
+       int ret;
+       struct ieee802154_sub_if_data *sdata;
+       struct ieee802154_hdr hdr;
 
-       work = kzalloc(sizeof(*work), GFP_ATOMIC);
-       if (!work)
+       ret = ieee802154_parse_frame_start(skb, &hdr);
+       if (ret) {
+               pr_debug("got invalid frame\n");
+               kfree_skb(skb);
                return;
+       }
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (sdata->type != IEEE802154_DEV_WPAN ||
+                   !netif_running(sdata->dev))
+                       continue;
+
+               ieee802154_subif_frame(sdata, skb, &hdr);
+               skb = NULL;
+               break;
+       }
+
+       if (skb)
+               kfree_skb(skb);
+}
+
+static void
+ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
+{
+       struct sk_buff *skb2;
+       struct ieee802154_sub_if_data *sdata;
+
+       skb_reset_mac_header(skb);
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       skb->pkt_type = PACKET_OTHERHOST;
+       skb->protocol = htons(ETH_P_IEEE802154);
+
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (sdata->type != IEEE802154_DEV_MONITOR)
+                       continue;
+
+               if (!ieee802154_sdata_running(sdata))
+                       continue;
+
+               skb2 = skb_clone(skb, GFP_ATOMIC);
+               if (skb2) {
+                       skb2->dev = sdata->dev;
+                       ieee802154_deliver_skb(skb2);
+
+                       sdata->dev->stats.rx_packets++;
+                       sdata->dev->stats.rx_bytes += skb->len;
+               }
+       }
+}
+
+void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+       u16 crc;
 
-       INIT_WORK(&work->work, mac802154_rx_worker);
-       work->skb = skb;
-       work->dev = dev;
-       work->lqi = lqi;
+       WARN_ON_ONCE(softirq_count() == 0);
 
-       queue_work(priv->dev_workqueue, &work->work);
+       /* TODO: When a transceiver omits the checksum here, we
+        * add an own calculated one. This is currently an ugly
+        * solution because the monitor needs a crc here.
+        */
+       if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
+               crc = crc_ccitt(0, skb->data, skb->len);
+               put_unaligned_le16(crc, skb_put(skb, 2));
+       }
+
+       rcu_read_lock();
+
+       ieee802154_monitors_rx(local, skb);
+
+       /* Check if transceiver doesn't validate the checksum.
+        * If not we validate the checksum here.
+        */
+       if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM) {
+               crc = crc_ccitt(0, skb->data, skb->len);
+               if (crc) {
+                       rcu_read_unlock();
+                       kfree_skb(skb);
+                       return;
+               }
+       }
+       /* remove crc */
+       skb_trim(skb, skb->len - 2);
+
+       __ieee802154_rx_handle_packet(local, skb);
+
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee802154_rx);
+
+void
+ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+
+       mac_cb(skb)->lqi = lqi;
+       skb->pkt_type = IEEE802154_RX_MSG;
+       skb_queue_tail(&local->skb_queue, skb);
+       tasklet_schedule(&local->tasklet);
 }
 EXPORT_SYMBOL(ieee802154_rx_irqsafe);
index fdf4c0e67259ecceacc0b06b9060405ded6f63cc..cc37b77f26321ca9a5f4f960a0f72608d48c1013 100644 (file)
  * 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-1301 USA.
- *
  * Written by:
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  * Sergey Lapin <slapin@ossfans.org>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/crc-ccitt.h>
+#include <asm/unaligned.h>
 
+#include <net/rtnetlink.h>
 #include <net/ieee802154_netdev.h>
 #include <net/mac802154.h>
-#include <net/wpan-phy.h>
+#include <net/cfg802154.h>
 
-#include "mac802154.h"
+#include "ieee802154_i.h"
+#include "driver-ops.h"
 
 /* IEEE 802.15.4 transceivers can sleep during the xmit session, so process
  * packets through the workqueue.
  */
-struct xmit_work {
+struct ieee802154_xmit_cb {
        struct sk_buff *skb;
        struct work_struct work;
-       struct mac802154_priv *priv;
-       u8 chan;
-       u8 page;
+       struct ieee802154_local *local;
 };
 
-static void mac802154_xmit_worker(struct work_struct *work)
+static struct ieee802154_xmit_cb ieee802154_xmit_cb;
+
+static void ieee802154_xmit_worker(struct work_struct *work)
 {
-       struct xmit_work *xw = container_of(work, struct xmit_work, work);
-       struct mac802154_sub_if_data *sdata;
+       struct ieee802154_xmit_cb *cb =
+               container_of(work, struct ieee802154_xmit_cb, work);
+       struct ieee802154_local *local = cb->local;
+       struct sk_buff *skb = cb->skb;
+       struct net_device *dev = skb->dev;
        int res;
 
-       mutex_lock(&xw->priv->phy->pib_lock);
-       if (xw->priv->phy->current_channel != xw->chan ||
-           xw->priv->phy->current_page != xw->page) {
-               res = xw->priv->ops->set_channel(&xw->priv->hw,
-                                                 xw->page,
-                                                 xw->chan);
-               if (res) {
-                       pr_debug("set_channel failed\n");
-                       goto out;
-               }
+       rtnl_lock();
 
-               xw->priv->phy->current_channel = xw->chan;
-               xw->priv->phy->current_page = xw->page;
-       }
+       /* check if ifdown occurred while schedule */
+       if (!netif_running(dev))
+               goto err_tx;
 
-       res = xw->priv->ops->xmit(&xw->priv->hw, xw->skb);
+       res = drv_xmit_sync(local, skb);
        if (res)
-               pr_debug("transmission failed\n");
+               goto err_tx;
 
-out:
-       mutex_unlock(&xw->priv->phy->pib_lock);
+       ieee802154_xmit_complete(&local->hw, skb);
 
-       /* Restart the netif queue on each sub_if_data object. */
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &xw->priv->slaves, list)
-               netif_wake_queue(sdata->dev);
-       rcu_read_unlock();
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
 
-       dev_kfree_skb(xw->skb);
+       rtnl_unlock();
 
-       kfree(xw);
+       return;
+
+err_tx:
+       /* Restart the netif queue on each sub_if_data object. */
+       ieee802154_wake_queue(&local->hw);
+       rtnl_unlock();
+       kfree_skb(skb);
+       netdev_dbg(dev, "transmission failed\n");
 }
 
-netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
-                        u8 page, u8 chan)
+static netdev_tx_t
+ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
 {
-       struct xmit_work *work;
-       struct mac802154_sub_if_data *sdata;
-
-       if (!(priv->phy->channels_supported[page] & (1 << chan))) {
-               WARN_ON(1);
-               goto err_tx;
-       }
-
-       mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb);
+       struct net_device *dev = skb->dev;
+       int ret;
 
-       if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) {
+       if (!(local->hw.flags & IEEE802154_HW_TX_OMIT_CKSUM)) {
                u16 crc = crc_ccitt(0, skb->data, skb->len);
-               u8 *data = skb_put(skb, 2);
 
-               data[0] = crc & 0xff;
-               data[1] = crc >> 8;
+               put_unaligned_le16(crc, skb_put(skb, 2));
        }
 
-       if (skb_cow_head(skb, priv->hw.extra_tx_headroom))
+       if (skb_cow_head(skb, local->hw.extra_tx_headroom))
                goto err_tx;
 
-       work = kzalloc(sizeof(*work), GFP_ATOMIC);
-       if (!work) {
-               kfree_skb(skb);
-               return NETDEV_TX_BUSY;
-       }
-
        /* Stop the netif queue on each sub_if_data object. */
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &priv->slaves, list)
-               netif_stop_queue(sdata->dev);
-       rcu_read_unlock();
+       ieee802154_stop_queue(&local->hw);
+
+       /* async is priority, otherwise sync is fallback */
+       if (local->ops->xmit_async) {
+               ret = drv_xmit_async(local, skb);
+               if (ret) {
+                       ieee802154_wake_queue(&local->hw);
+                       goto err_tx;
+               }
 
-       INIT_WORK(&work->work, mac802154_xmit_worker);
-       work->skb = skb;
-       work->priv = priv;
-       work->page = page;
-       work->chan = chan;
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += skb->len;
+       } else {
+               INIT_WORK(&ieee802154_xmit_cb.work, ieee802154_xmit_worker);
+               ieee802154_xmit_cb.skb = skb;
+               ieee802154_xmit_cb.local = local;
 
-       queue_work(priv->dev_workqueue, &work->work);
+               queue_work(local->workqueue, &ieee802154_xmit_cb.work);
+       }
 
        return NETDEV_TX_OK;
 
@@ -131,3 +119,31 @@ err_tx:
        kfree_skb(skb);
        return NETDEV_TX_OK;
 }
+
+netdev_tx_t
+ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+
+       skb->skb_iif = dev->ifindex;
+
+       return ieee802154_tx(sdata->local, skb);
+}
+
+netdev_tx_t
+ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       int rc;
+
+       rc = mac802154_llsec_encrypt(&sdata->sec, skb);
+       if (rc) {
+               netdev_warn(dev, "encryption failed: %i\n", rc);
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       skb->skb_iif = dev->ifindex;
+
+       return ieee802154_tx(sdata->local, skb);
+}
diff --git a/net/mac802154/util.c b/net/mac802154/util.c
new file mode 100644 (file)
index 0000000..117e4ef
--- /dev/null
@@ -0,0 +1,55 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * 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.
+ *
+ * Authors:
+ * Alexander Aring <aar@pengutronix.de>
+ *
+ * Based on: net/mac80211/util.c
+ */
+
+#include "ieee802154_i.h"
+
+void ieee802154_wake_queue(struct ieee802154_hw *hw)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+       struct ieee802154_sub_if_data *sdata;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!sdata->dev)
+                       continue;
+
+               netif_wake_queue(sdata->dev);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee802154_wake_queue);
+
+void ieee802154_stop_queue(struct ieee802154_hw *hw)
+{
+       struct ieee802154_local *local = hw_to_local(hw);
+       struct ieee802154_sub_if_data *sdata;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!sdata->dev)
+                       continue;
+
+               netif_stop_queue(sdata->dev);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee802154_stop_queue);
+
+void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+       ieee802154_wake_queue(hw);
+       consume_skb(skb);
+}
+EXPORT_SYMBOL(ieee802154_xmit_complete);
diff --git a/net/mac802154/wpan.c b/net/mac802154/wpan.c
deleted file mode 100644 (file)
index 4ab86a5..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * Copyright 2007-2012 Siemens AG
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * 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-1301 USA.
- *
- * Written by:
- * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
- * Sergey Lapin <slapin@ossfans.org>
- * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
- * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-#include <linux/netdevice.h>
-#include <linux/module.h>
-#include <linux/if_arp.h>
-
-#include <net/rtnetlink.h>
-#include <linux/nl802154.h>
-#include <net/af_ieee802154.h>
-#include <net/mac802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/ieee802154.h>
-#include <net/wpan-phy.h>
-
-#include "mac802154.h"
-
-static int mac802154_wpan_update_llsec(struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
-       int rc = 0;
-
-       if (ops->llsec) {
-               struct ieee802154_llsec_params params;
-               int changed = 0;
-
-               params.pan_id = priv->pan_id;
-               changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
-
-               params.hwaddr = priv->extended_addr;
-               changed |= IEEE802154_LLSEC_PARAM_HWADDR;
-
-               rc = ops->llsec->set_params(dev, &params, changed);
-       }
-
-       return rc;
-}
-
-static int
-mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct sockaddr_ieee802154 *sa =
-               (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
-       int err = -ENOIOCTLCMD;
-
-       spin_lock_bh(&priv->mib_lock);
-
-       switch (cmd) {
-       case SIOCGIFADDR:
-       {
-               u16 pan_id, short_addr;
-
-               pan_id = le16_to_cpu(priv->pan_id);
-               short_addr = le16_to_cpu(priv->short_addr);
-               if (pan_id == IEEE802154_PANID_BROADCAST ||
-                   short_addr == IEEE802154_ADDR_BROADCAST) {
-                       err = -EADDRNOTAVAIL;
-                       break;
-               }
-
-               sa->family = AF_IEEE802154;
-               sa->addr.addr_type = IEEE802154_ADDR_SHORT;
-               sa->addr.pan_id = pan_id;
-               sa->addr.short_addr = short_addr;
-
-               err = 0;
-               break;
-       }
-       case SIOCSIFADDR:
-               dev_warn(&dev->dev,
-                        "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
-               if (sa->family != AF_IEEE802154 ||
-                   sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
-                   sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
-                   sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
-                   sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
-                       err = -EINVAL;
-                       break;
-               }
-
-               priv->pan_id = cpu_to_le16(sa->addr.pan_id);
-               priv->short_addr = cpu_to_le16(sa->addr.short_addr);
-
-               err = mac802154_wpan_update_llsec(dev);
-               break;
-       }
-
-       spin_unlock_bh(&priv->mib_lock);
-       return err;
-}
-
-static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
-{
-       struct sockaddr *addr = p;
-
-       if (netif_running(dev))
-               return -EBUSY;
-
-       /* FIXME: validate addr */
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       mac802154_dev_set_ieee_addr(dev);
-       return mac802154_wpan_update_llsec(dev);
-}
-
-int mac802154_set_mac_params(struct net_device *dev,
-                            const struct ieee802154_mac_params *params)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-
-       mutex_lock(&priv->hw->slaves_mtx);
-       priv->mac_params = *params;
-       mutex_unlock(&priv->hw->slaves_mtx);
-
-       return 0;
-}
-
-void mac802154_get_mac_params(struct net_device *dev,
-                             struct ieee802154_mac_params *params)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-
-       mutex_lock(&priv->hw->slaves_mtx);
-       *params = priv->mac_params;
-       mutex_unlock(&priv->hw->slaves_mtx);
-}
-
-static int mac802154_wpan_open(struct net_device *dev)
-{
-       int rc;
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct wpan_phy *phy = priv->hw->phy;
-
-       rc = mac802154_slave_open(dev);
-       if (rc < 0)
-               return rc;
-
-       mutex_lock(&phy->pib_lock);
-
-       if (phy->set_txpower) {
-               rc = phy->set_txpower(phy, priv->mac_params.transmit_power);
-               if (rc < 0)
-                       goto out;
-       }
-
-       if (phy->set_lbt) {
-               rc = phy->set_lbt(phy, priv->mac_params.lbt);
-               if (rc < 0)
-                       goto out;
-       }
-
-       if (phy->set_cca_mode) {
-               rc = phy->set_cca_mode(phy, priv->mac_params.cca_mode);
-               if (rc < 0)
-                       goto out;
-       }
-
-       if (phy->set_cca_ed_level) {
-               rc = phy->set_cca_ed_level(phy, priv->mac_params.cca_ed_level);
-               if (rc < 0)
-                       goto out;
-       }
-
-       if (phy->set_csma_params) {
-               rc = phy->set_csma_params(phy, priv->mac_params.min_be,
-                                         priv->mac_params.max_be,
-                                         priv->mac_params.csma_retries);
-               if (rc < 0)
-                       goto out;
-       }
-
-       if (phy->set_frame_retries) {
-               rc = phy->set_frame_retries(phy,
-                                           priv->mac_params.frame_retries);
-               if (rc < 0)
-                       goto out;
-       }
-
-       mutex_unlock(&phy->pib_lock);
-       return 0;
-
-out:
-       mutex_unlock(&phy->pib_lock);
-       return rc;
-}
-
-static int mac802154_set_header_security(struct mac802154_sub_if_data *priv,
-                                        struct ieee802154_hdr *hdr,
-                                        const struct ieee802154_mac_cb *cb)
-{
-       struct ieee802154_llsec_params params;
-       u8 level;
-
-       mac802154_llsec_get_params(&priv->sec, &params);
-
-       if (!params.enabled && cb->secen_override && cb->secen)
-               return -EINVAL;
-       if (!params.enabled ||
-           (cb->secen_override && !cb->secen) ||
-           !params.out_level)
-               return 0;
-       if (cb->seclevel_override && !cb->seclevel)
-               return -EINVAL;
-
-       level = cb->seclevel_override ? cb->seclevel : params.out_level;
-
-       hdr->fc.security_enabled = 1;
-       hdr->sec.level = level;
-       hdr->sec.key_id_mode = params.out_key.mode;
-       if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
-               hdr->sec.short_src = params.out_key.short_source;
-       else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
-               hdr->sec.extended_src = params.out_key.extended_source;
-       hdr->sec.key_id = params.out_key.id;
-
-       return 0;
-}
-
-static int mac802154_header_create(struct sk_buff *skb,
-                                  struct net_device *dev,
-                                  unsigned short type,
-                                  const void *daddr,
-                                  const void *saddr,
-                                  unsigned len)
-{
-       struct ieee802154_hdr hdr;
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       struct ieee802154_mac_cb *cb = mac_cb(skb);
-       int hlen;
-
-       if (!daddr)
-               return -EINVAL;
-
-       memset(&hdr.fc, 0, sizeof(hdr.fc));
-       hdr.fc.type = cb->type;
-       hdr.fc.security_enabled = cb->secen;
-       hdr.fc.ack_request = cb->ackreq;
-       hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
-
-       if (mac802154_set_header_security(priv, &hdr, cb) < 0)
-               return -EINVAL;
-
-       if (!saddr) {
-               spin_lock_bh(&priv->mib_lock);
-
-               if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
-                   priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
-                   priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
-                       hdr.source.mode = IEEE802154_ADDR_LONG;
-                       hdr.source.extended_addr = priv->extended_addr;
-               } else {
-                       hdr.source.mode = IEEE802154_ADDR_SHORT;
-                       hdr.source.short_addr = priv->short_addr;
-               }
-
-               hdr.source.pan_id = priv->pan_id;
-
-               spin_unlock_bh(&priv->mib_lock);
-       } else {
-               hdr.source = *(const struct ieee802154_addr *)saddr;
-       }
-
-       hdr.dest = *(const struct ieee802154_addr *)daddr;
-
-       hlen = ieee802154_hdr_push(skb, &hdr);
-       if (hlen < 0)
-               return -EINVAL;
-
-       skb_reset_mac_header(skb);
-       skb->mac_len = hlen;
-
-       if (len > ieee802154_max_payload(&hdr))
-               return -EMSGSIZE;
-
-       return hlen;
-}
-
-static int
-mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
-{
-       struct ieee802154_hdr hdr;
-       struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
-
-       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
-               pr_debug("malformed packet\n");
-               return 0;
-       }
-
-       *addr = hdr.source;
-       return sizeof(*addr);
-}
-
-static netdev_tx_t
-mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv;
-       u8 chan, page;
-       int rc;
-
-       priv = netdev_priv(dev);
-
-       spin_lock_bh(&priv->mib_lock);
-       chan = priv->chan;
-       page = priv->page;
-       spin_unlock_bh(&priv->mib_lock);
-
-       if (chan == MAC802154_CHAN_NONE ||
-           page >= WPAN_NUM_PAGES ||
-           chan >= WPAN_NUM_CHANNELS) {
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       rc = mac802154_llsec_encrypt(&priv->sec, skb);
-       if (rc) {
-               pr_warn("encryption failed: %i\n", rc);
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       skb->skb_iif = dev->ifindex;
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       return mac802154_tx(priv->hw, skb, page, chan);
-}
-
-static struct header_ops mac802154_header_ops = {
-       .create         = mac802154_header_create,
-       .parse          = mac802154_header_parse,
-};
-
-static const struct net_device_ops mac802154_wpan_ops = {
-       .ndo_open               = mac802154_wpan_open,
-       .ndo_stop               = mac802154_slave_close,
-       .ndo_start_xmit         = mac802154_wpan_xmit,
-       .ndo_do_ioctl           = mac802154_wpan_ioctl,
-       .ndo_set_mac_address    = mac802154_wpan_mac_addr,
-};
-
-static void mac802154_wpan_free(struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv = netdev_priv(dev);
-
-       mac802154_llsec_destroy(&priv->sec);
-
-       free_netdev(dev);
-}
-
-void mac802154_wpan_setup(struct net_device *dev)
-{
-       struct mac802154_sub_if_data *priv;
-
-       dev->addr_len           = IEEE802154_ADDR_LEN;
-       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
-
-       dev->hard_header_len    = MAC802154_FRAME_HARD_HEADER_LEN;
-       dev->header_ops         = &mac802154_header_ops;
-       dev->needed_tailroom    = 2 + 16; /* FCS + MIC */
-       dev->mtu                = IEEE802154_MTU;
-       dev->tx_queue_len       = 300;
-       dev->type               = ARPHRD_IEEE802154;
-       dev->flags              = IFF_NOARP | IFF_BROADCAST;
-       dev->watchdog_timeo     = 0;
-
-       dev->destructor         = mac802154_wpan_free;
-       dev->netdev_ops         = &mac802154_wpan_ops;
-       dev->ml_priv            = &mac802154_mlme_wpan;
-
-       priv = netdev_priv(dev);
-       priv->type = IEEE802154_DEV_WPAN;
-
-       priv->chan = MAC802154_CHAN_NONE;
-       priv->page = 0;
-
-       spin_lock_init(&priv->mib_lock);
-       mutex_init(&priv->sec_mtx);
-
-       get_random_bytes(&priv->bsn, 1);
-       get_random_bytes(&priv->dsn, 1);
-
-       /* defaults per 802.15.4-2011 */
-       priv->mac_params.min_be = 3;
-       priv->mac_params.max_be = 5;
-       priv->mac_params.csma_retries = 4;
-       priv->mac_params.frame_retries = -1; /* for compatibility, actual default is 3 */
-
-       priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
-       priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
-
-       mac802154_llsec_init(&priv->sec);
-}
-
-static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
-{
-       return netif_rx_ni(skb);
-}
-
-static int
-mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
-                     const struct ieee802154_hdr *hdr)
-{
-       __le16 span, sshort;
-       int rc;
-
-       pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
-
-       spin_lock_bh(&sdata->mib_lock);
-
-       span = sdata->pan_id;
-       sshort = sdata->short_addr;
-
-       switch (mac_cb(skb)->dest.mode) {
-       case IEEE802154_ADDR_NONE:
-               if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
-                       /* FIXME: check if we are PAN coordinator */
-                       skb->pkt_type = PACKET_OTHERHOST;
-               else
-                       /* ACK comes with both addresses empty */
-                       skb->pkt_type = PACKET_HOST;
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (mac_cb(skb)->dest.pan_id != span &&
-                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
-                       skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
-                       skb->pkt_type = PACKET_HOST;
-               else
-                       skb->pkt_type = PACKET_OTHERHOST;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (mac_cb(skb)->dest.pan_id != span &&
-                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
-                       skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->dest.short_addr == sshort)
-                       skb->pkt_type = PACKET_HOST;
-               else if (mac_cb(skb)->dest.short_addr ==
-                         cpu_to_le16(IEEE802154_ADDR_BROADCAST))
-                       skb->pkt_type = PACKET_BROADCAST;
-               else
-                       skb->pkt_type = PACKET_OTHERHOST;
-               break;
-       default:
-               spin_unlock_bh(&sdata->mib_lock);
-               pr_debug("invalid dest mode\n");
-               kfree_skb(skb);
-               return NET_RX_DROP;
-       }
-
-       spin_unlock_bh(&sdata->mib_lock);
-
-       skb->dev = sdata->dev;
-
-       rc = mac802154_llsec_decrypt(&sdata->sec, skb);
-       if (rc) {
-               pr_debug("decryption failed: %i\n", rc);
-               goto fail;
-       }
-
-       sdata->dev->stats.rx_packets++;
-       sdata->dev->stats.rx_bytes += skb->len;
-
-       switch (mac_cb(skb)->type) {
-       case IEEE802154_FC_TYPE_DATA:
-               return mac802154_process_data(sdata->dev, skb);
-       default:
-               pr_warn("ieee802154: bad frame received (type = %d)\n",
-                       mac_cb(skb)->type);
-               goto fail;
-       }
-
-fail:
-       kfree_skb(skb);
-       return NET_RX_DROP;
-}
-
-static void mac802154_print_addr(const char *name,
-                                const struct ieee802154_addr *addr)
-{
-       if (addr->mode == IEEE802154_ADDR_NONE)
-               pr_debug("%s not present\n", name);
-
-       pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
-       if (addr->mode == IEEE802154_ADDR_SHORT) {
-               pr_debug("%s is short: %04x\n", name,
-                        le16_to_cpu(addr->short_addr));
-       } else {
-               u64 hw = swab64((__force u64) addr->extended_addr);
-
-               pr_debug("%s is hardware: %8phC\n", name, &hw);
-       }
-}
-
-static int mac802154_parse_frame_start(struct sk_buff *skb,
-                                      struct ieee802154_hdr *hdr)
-{
-       int hlen;
-       struct ieee802154_mac_cb *cb = mac_cb_init(skb);
-
-       hlen = ieee802154_hdr_pull(skb, hdr);
-       if (hlen < 0)
-               return -EINVAL;
-
-       skb->mac_len = hlen;
-
-       pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
-                hdr->seq);
-
-       cb->type = hdr->fc.type;
-       cb->ackreq = hdr->fc.ack_request;
-       cb->secen = hdr->fc.security_enabled;
-
-       mac802154_print_addr("destination", &hdr->dest);
-       mac802154_print_addr("source", &hdr->source);
-
-       cb->source = hdr->source;
-       cb->dest = hdr->dest;
-
-       if (hdr->fc.security_enabled) {
-               u64 key;
-
-               pr_debug("seclevel %i\n", hdr->sec.level);
-
-               switch (hdr->sec.key_id_mode) {
-               case IEEE802154_SCF_KEY_IMPLICIT:
-                       pr_debug("implicit key\n");
-                       break;
-
-               case IEEE802154_SCF_KEY_INDEX:
-                       pr_debug("key %02x\n", hdr->sec.key_id);
-                       break;
-
-               case IEEE802154_SCF_KEY_SHORT_INDEX:
-                       pr_debug("key %04x:%04x %02x\n",
-                                le32_to_cpu(hdr->sec.short_src) >> 16,
-                                le32_to_cpu(hdr->sec.short_src) & 0xffff,
-                                hdr->sec.key_id);
-                       break;
-
-               case IEEE802154_SCF_KEY_HW_INDEX:
-                       key = swab64((__force u64) hdr->sec.extended_src);
-                       pr_debug("key source %8phC %02x\n", &key,
-                                hdr->sec.key_id);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
-{
-       int ret;
-       struct mac802154_sub_if_data *sdata;
-       struct ieee802154_hdr hdr;
-
-       ret = mac802154_parse_frame_start(skb, &hdr);
-       if (ret) {
-               pr_debug("got invalid frame\n");
-               kfree_skb(skb);
-               return;
-       }
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &priv->slaves, list) {
-               if (sdata->type != IEEE802154_DEV_WPAN ||
-                   !netif_running(sdata->dev))
-                       continue;
-
-               mac802154_subif_frame(sdata, skb, &hdr);
-               skb = NULL;
-               break;
-       }
-       rcu_read_unlock();
-
-       if (skb)
-               kfree_skb(skb);
-}
index d49dc2ed30adb97a809eb37902b9956c366a2862..ce469d648ffbe166f9ae1c5650f481256f31a7f8 100644 (file)
@@ -205,9 +205,10 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
        if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN))
                goto out_free;
 
-       if (!sctp_ulpevent_is_notification(event))
+       if (!sctp_ulpevent_is_notification(event)) {
                sk_mark_napi_id(sk, skb);
-
+               sk_incoming_cpu_update(sk);
+       }
        /* Check if the user wishes to receive this event.  */
        if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe))
                goto out_free;
index a761670af31dd7076b32e7f61f26bb4b94b22728..4c9e39f04ef8fae38e21070fddbb89bb5a150863 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
index 72d81e2154d590dbba26bf2d1e0868c5c4940e26..85506f1d078920117b1030abc1e50a0ec70fdc6b 100644 (file)
@@ -115,7 +115,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
 EXPORT_SYMBOL(cfg80211_chandef_valid);
 
 static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
-                                 int *pri40, int *pri80)
+                                 u32 *pri40, u32 *pri80)
 {
        int tmp;
 
@@ -366,6 +366,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
 
                break;
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_AP_VLAN:
@@ -892,6 +893,13 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                                *radar_detect |= BIT(wdev->chandef.width);
                }
                return;
+       case NL80211_IFTYPE_OCB:
+               if (wdev->chandef.chan) {
+                       *chan = wdev->chandef.chan;
+                       *chanmode = CHAN_MODE_SHARED;
+                       return;
+               }
+               break;
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_AP_VLAN:
        case NL80211_IFTYPE_WDS:
index f52a4cd7017c855c1c64f9ee2bbe2b0b44b625cc..a4d27927aba25930870630c0927d425b51bd6ee9 100644 (file)
@@ -86,11 +86,11 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
        return &rdev->wiphy;
 }
 
-int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
-                       char *newname)
+static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev,
+                                  const char *newname)
 {
        struct cfg80211_registered_device *rdev2;
-       int wiphy_idx, taken = -1, result, digits;
+       int wiphy_idx, taken = -1, digits;
 
        ASSERT_RTNL();
 
@@ -109,15 +109,28 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        return -EINVAL;
        }
 
+       /* Ensure another device does not already have this name. */
+       list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
+               if (strcmp(newname, wiphy_name(&rdev2->wiphy)) == 0)
+                       return -EINVAL;
+
+       return 0;
+}
+
+int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
+                       char *newname)
+{
+       int result;
+
+       ASSERT_RTNL();
 
        /* Ignore nop renames */
-       if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0)
+       if (strcmp(newname, wiphy_name(&rdev->wiphy)) == 0)
                return 0;
 
-       /* Ensure another device does not already have this name. */
-       list_for_each_entry(rdev2, &cfg80211_rdev_list, list)
-               if (strcmp(newname, dev_name(&rdev2->wiphy.dev)) == 0)
-                       return -EINVAL;
+       result = cfg80211_dev_check_name(rdev, newname);
+       if (result < 0)
+               return result;
 
        result = device_rename(&rdev->wiphy.dev, newname);
        if (result)
@@ -309,7 +322,8 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
 
 /* exported functions */
 
-struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
+struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+                          const char *requested_name)
 {
        static atomic_t wiphy_counter = ATOMIC_INIT(0);
 
@@ -346,7 +360,31 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        rdev->wiphy_idx--;
 
        /* give it a proper name */
-       dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       if (requested_name && requested_name[0]) {
+               int rv;
+
+               rtnl_lock();
+               rv = cfg80211_dev_check_name(rdev, requested_name);
+
+               if (rv < 0) {
+                       rtnl_unlock();
+                       goto use_default_name;
+               }
+
+               rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name);
+               rtnl_unlock();
+               if (rv)
+                       goto use_default_name;
+       } else {
+use_default_name:
+               /* NOTE:  This is *probably* safe w/out holding rtnl because of
+                * the restrictions on phy names.  Probably this call could
+                * fail if some other part of the kernel (re)named a device
+                * phyX.  But, might should add some locking and check return
+                * value, and use a different name if this one exists?
+                */
+               dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
+       }
 
        INIT_LIST_HEAD(&rdev->wdev_list);
        INIT_LIST_HEAD(&rdev->beacon_registrations);
@@ -406,7 +444,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
 
        return &rdev->wiphy;
 }
-EXPORT_SYMBOL(wiphy_new);
+EXPORT_SYMBOL(wiphy_new_nm);
 
 static int wiphy_verify_combinations(struct wiphy *wiphy)
 {
@@ -831,7 +869,22 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
        case NL80211_IFTYPE_P2P_GO:
                __cfg80211_stop_ap(rdev, dev, true);
                break;
-       default:
+       case NL80211_IFTYPE_OCB:
+               __cfg80211_leave_ocb(rdev, dev);
+               break;
+       case NL80211_IFTYPE_WDS:
+               /* must be handled by mac80211/driver, has no APIs */
+               break;
+       case NL80211_IFTYPE_P2P_DEVICE:
+               /* cannot happen, has no netdev */
+               break;
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_MONITOR:
+               /* nothing to do */
+               break;
+       case NL80211_IFTYPE_UNSPECIFIED:
+       case NUM_NL80211_IFTYPES:
+               /* invalid */
                break;
        }
 }
index 7e3a3cef7df93b4c6936515f05f91d2ec14446ea..61ee664cf2bd94a3183eaa1398b84777b4790828 100644 (file)
@@ -290,6 +290,18 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
                              struct wireless_dev *wdev,
                              struct cfg80211_chan_def *chandef);
 
+/* OCB */
+int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       struct ocb_setup *setup);
+int cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+                     struct ocb_setup *setup);
+int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev);
+int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev);
+
 /* AP */
 int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, bool notify);
index 5839c85075f15407e86d84526cfb29087c70aa81..1a31736914e5ca9a9ac2cd2083deb43bfb7e6fc3 100644 (file)
@@ -884,7 +884,12 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
                if (!wdev->current_bss)
                        return -ENOLINK;
                break;
-       default:
+       case NL80211_IFTYPE_UNSPECIFIED:
+       case NL80211_IFTYPE_OCB:
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_P2P_DEVICE:
+       case NL80211_IFTYPE_WDS:
+       case NUM_NL80211_IFTYPES:
                return -EINVAL;
        }
 
@@ -1514,8 +1519,8 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                        if (rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
                                CMD(channel_switch, CHANNEL_SWITCH);
                        CMD(set_qos_map, SET_QOS_MAP);
-                       if (rdev->wiphy.flags &
-                                       WIPHY_FLAG_SUPPORTS_WMM_ADMISSION)
+                       if (rdev->wiphy.features &
+                                       NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
                                CMD(add_tx_ts, ADD_TX_TS);
                }
                /* add into the if now */
@@ -2605,7 +2610,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
            !(rdev->wiphy.interface_modes & (1 << type)))
                return -EOPNOTSUPP;
 
-       if (type == NL80211_IFTYPE_P2P_DEVICE && info->attrs[NL80211_ATTR_MAC]) {
+       if ((type == NL80211_IFTYPE_P2P_DEVICE ||
+            rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
+           info->attrs[NL80211_ATTR_MAC]) {
                nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
                           ETH_ALEN);
                if (!is_valid_ether_addr(params.macaddr))
@@ -4398,10 +4405,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
-       u8 *mac_addr = NULL;
+       struct station_del_parameters params;
+
+       memset(&params, 0, sizeof(params));
 
        if (info->attrs[NL80211_ATTR_MAC])
-               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+               params.mac = nla_data(info->attrs[NL80211_ATTR_MAC]);
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
@@ -4412,7 +4421,28 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->del_station)
                return -EOPNOTSUPP;
 
-       return rdev_del_station(rdev, dev, mac_addr);
+       if (info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) {
+               params.subtype =
+                       nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]);
+               if (params.subtype != IEEE80211_STYPE_DISASSOC >> 4 &&
+                   params.subtype != IEEE80211_STYPE_DEAUTH >> 4)
+                       return -EINVAL;
+       } else {
+               /* Default to Deauthentication frame */
+               params.subtype = IEEE80211_STYPE_DEAUTH >> 4;
+       }
+
+       if (info->attrs[NL80211_ATTR_REASON_CODE]) {
+               params.reason_code =
+                       nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+               if (params.reason_code == 0)
+                       return -EINVAL; /* 0 is reserved */
+       } else {
+               /* Default to reason code 2 */
+               params.reason_code = WLAN_REASON_PREV_AUTH_NOT_VALID;
+       }
+
+       return rdev_del_station(rdev, dev, &params);
 }
 
 static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
@@ -4624,6 +4654,96 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
        return rdev_del_mpath(rdev, dev, dst);
 }
 
+static int nl80211_get_mpp(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       int err;
+       struct net_device *dev = info->user_ptr[1];
+       struct mpath_info pinfo;
+       struct sk_buff *msg;
+       u8 *dst = NULL;
+       u8 mpp[ETH_ALEN];
+
+       memset(&pinfo, 0, sizeof(pinfo));
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       if (!rdev->ops->get_mpp)
+               return -EOPNOTSUPP;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
+
+       err = rdev_get_mpp(rdev, dev, dst, mpp, &pinfo);
+       if (err)
+               return err;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       if (nl80211_send_mpath(msg, info->snd_portid, info->snd_seq, 0,
+                              dev, dst, mpp, &pinfo) < 0) {
+               nlmsg_free(msg);
+               return -ENOBUFS;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int nl80211_dump_mpp(struct sk_buff *skb,
+                           struct netlink_callback *cb)
+{
+       struct mpath_info pinfo;
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       u8 dst[ETH_ALEN];
+       u8 mpp[ETH_ALEN];
+       int path_idx = cb->args[2];
+       int err;
+
+       err = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
+       if (err)
+               return err;
+
+       if (!rdev->ops->dump_mpp) {
+               err = -EOPNOTSUPP;
+               goto out_err;
+       }
+
+       if (wdev->iftype != NL80211_IFTYPE_MESH_POINT) {
+               err = -EOPNOTSUPP;
+               goto out_err;
+       }
+
+       while (1) {
+               err = rdev_dump_mpp(rdev, wdev->netdev, path_idx, dst,
+                                   mpp, &pinfo);
+               if (err == -ENOENT)
+                       break;
+               if (err)
+                       goto out_err;
+
+               if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).portid,
+                                      cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                      wdev->netdev, dst, mpp,
+                                      &pinfo) < 0)
+                       goto out;
+
+               path_idx++;
+       }
+
+ out:
+       cb->args[2] = path_idx;
+       err = skb->len;
+ out_err:
+       nl80211_finish_wdev_dump(rdev);
+       return err;
+}
+
 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -5923,7 +6043,6 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
         * function is called under RTNL lock, so this should not be a problem.
         */
        static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
-       u8 radar_detect_width = 0;
        int err;
        bool need_new_beacon = false;
        int len, i;
@@ -6059,10 +6178,8 @@ skip_beacons:
        if (err < 0)
                return err;
 
-       if (err > 0) {
-               radar_detect_width = BIT(params.chandef.width);
+       if (err > 0)
                params.radar_required = true;
-       }
 
        if (info->attrs[NL80211_ATTR_CH_SWITCH_BLOCK_TX])
                params.block_tx = true;
@@ -8159,6 +8276,28 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
        return -EINVAL;
 }
 
+static int nl80211_join_ocb(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct ocb_setup setup = {};
+       int err;
+
+       err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+       if (err)
+               return err;
+
+       return cfg80211_join_ocb(rdev, dev, &setup);
+}
+
+static int nl80211_leave_ocb(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+
+       return cfg80211_leave_ocb(rdev, dev);
+}
+
 static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -9444,7 +9583,7 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
        u16 admitted_time = 0;
        int err;
 
-       if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
+       if (!(rdev->wiphy.features & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION))
                return -EOPNOTSUPP;
 
        if (!info->attrs[NL80211_ATTR_TSID] || !info->attrs[NL80211_ATTR_MAC] ||
@@ -9460,12 +9599,10 @@ static int nl80211_add_tx_ts(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        /* WMM uses TIDs 0-7 even for TSPEC */
-       if (tsid < IEEE80211_FIRST_TSPEC_TSID) {
-               if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_WMM_ADMISSION))
-                       return -EINVAL;
-       } else {
+       if (tsid >= IEEE80211_FIRST_TSPEC_TSID) {
                /* TODO: handle 802.11 TSPEC/admission control
-                * need more attributes for that (e.g. BA session requirement)
+                * need more attributes for that (e.g. BA session requirement);
+                * change the WMM adminssion test above to allow both then
                 */
                return -EINVAL;
        }
@@ -9781,6 +9918,15 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_GET_MPP,
+               .doit = nl80211_get_mpp,
+               .dumpit = nl80211_dump_mpp,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
        {
                .cmd = NL80211_CMD_SET_MPATH,
                .doit = nl80211_set_mpath,
@@ -10095,6 +10241,22 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_JOIN_OCB,
+               .doit = nl80211_join_ocb,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_LEAVE_OCB,
+               .doit = nl80211_leave_ocb,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 #ifdef CONFIG_PM
        {
                .cmd = NL80211_CMD_GET_WOWLAN,
diff --git a/net/wireless/ocb.c b/net/wireless/ocb.c
new file mode 100644 (file)
index 0000000..c00d4a7
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * OCB mode implementation
+ *
+ * Copyright: (c) 2014 Czech Technical University in Prague
+ *            (c) 2014 Volkswagen Group Research
+ * Author:    Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
+ * Funded by: Volkswagen Group Research
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "nl80211.h"
+#include "core.h"
+#include "rdev-ops.h"
+
+int __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                       struct net_device *dev,
+                       struct ocb_setup *setup)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
+               return -EOPNOTSUPP;
+
+       if (WARN_ON(!setup->chandef.chan))
+               return -EINVAL;
+
+       err = rdev_join_ocb(rdev, dev, setup);
+       if (!err)
+               wdev->chandef = setup->chandef;
+
+       return err;
+}
+
+int cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
+                     struct net_device *dev,
+                     struct ocb_setup *setup)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_join_ocb(rdev, dev, setup);
+       wdev_unlock(wdev);
+
+       return err;
+}
+
+int __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
+               return -EOPNOTSUPP;
+
+       if (!rdev->ops->leave_ocb)
+               return -EOPNOTSUPP;
+
+       err = rdev_leave_ocb(rdev, dev);
+       if (!err)
+               memset(&wdev->chandef, 0, sizeof(wdev->chandef));
+
+       return err;
+}
+
+int cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
+                      struct net_device *dev)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       wdev_lock(wdev);
+       err = __cfg80211_leave_ocb(rdev, dev);
+       wdev_unlock(wdev);
+
+       return err;
+}
index f6d457d6a558a63cea2787b921af8c2ec66e9843..1b3864cd50cadb714ca16afbb660ffeab4703c0b 100644 (file)
@@ -178,11 +178,12 @@ static inline int rdev_add_station(struct cfg80211_registered_device *rdev,
 }
 
 static inline int rdev_del_station(struct cfg80211_registered_device *rdev,
-                                  struct net_device *dev, u8 *mac)
+                                  struct net_device *dev,
+                                  struct station_del_parameters *params)
 {
        int ret;
-       trace_rdev_del_station(&rdev->wiphy, dev, mac);
-       ret = rdev->ops->del_station(&rdev->wiphy, dev, mac);
+       trace_rdev_del_station(&rdev->wiphy, dev, params);
+       ret = rdev->ops->del_station(&rdev->wiphy, dev, params);
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
@@ -263,6 +264,18 @@ static inline int rdev_get_mpath(struct cfg80211_registered_device *rdev,
 
 }
 
+static inline int rdev_get_mpp(struct cfg80211_registered_device *rdev,
+                              struct net_device *dev, u8 *dst, u8 *mpp,
+                              struct mpath_info *pinfo)
+{
+       int ret;
+
+       trace_rdev_get_mpp(&rdev->wiphy, dev, dst, mpp);
+       ret = rdev->ops->get_mpp(&rdev->wiphy, dev, dst, mpp, pinfo);
+       trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+       return ret;
+}
+
 static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
                                  struct net_device *dev, int idx, u8 *dst,
                                  u8 *next_hop, struct mpath_info *pinfo)
@@ -271,7 +284,20 @@ static inline int rdev_dump_mpath(struct cfg80211_registered_device *rdev,
        int ret;
        trace_rdev_dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop);
        ret = rdev->ops->dump_mpath(&rdev->wiphy, dev, idx, dst, next_hop,
-                                    pinfo);
+                                   pinfo);
+       trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
+       return ret;
+}
+
+static inline int rdev_dump_mpp(struct cfg80211_registered_device *rdev,
+                               struct net_device *dev, int idx, u8 *dst,
+                               u8 *mpp, struct mpath_info *pinfo)
+
+{
+       int ret;
+
+       trace_rdev_dump_mpp(&rdev->wiphy, dev, idx, dst, mpp);
+       ret = rdev->ops->dump_mpp(&rdev->wiphy, dev, idx, dst, mpp, pinfo);
        trace_rdev_return_int_mpath_info(&rdev->wiphy, ret, pinfo);
        return ret;
 }
@@ -322,6 +348,27 @@ static inline int rdev_leave_mesh(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static inline int rdev_join_ocb(struct cfg80211_registered_device *rdev,
+                               struct net_device *dev,
+                               struct ocb_setup *setup)
+{
+       int ret;
+       trace_rdev_join_ocb(&rdev->wiphy, dev, setup);
+       ret = rdev->ops->join_ocb(&rdev->wiphy, dev, setup);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
+static inline int rdev_leave_ocb(struct cfg80211_registered_device *rdev,
+                                struct net_device *dev)
+{
+       int ret;
+       trace_rdev_leave_ocb(&rdev->wiphy, dev);
+       ret = rdev->ops->leave_ocb(&rdev->wiphy, dev);
+       trace_rdev_return_int(&rdev->wiphy, ret);
+       return ret;
+}
+
 static inline int rdev_change_bss(struct cfg80211_registered_device *rdev,
                                  struct net_device *dev,
                                  struct bss_parameters *params)
index dc1668ff543b90927d9cb4e08b38897ac8e97f6c..0ab3711c79a01ae98cdaaafa64bf12ac94e80271 100644 (file)
@@ -80,9 +80,18 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
        if (!request)
                return -ENOMEM;
 
-       if (wdev->conn->params.channel)
+       if (wdev->conn->params.channel) {
+               enum ieee80211_band band = wdev->conn->params.channel->band;
+               struct ieee80211_supported_band *sband =
+                       wdev->wiphy->bands[band];
+
+               if (!sband) {
+                       kfree(request);
+                       return -EINVAL;
+               }
                request->channels[0] = wdev->conn->params.channel;
-       else {
+               request->rates[band] = (1 << sband->n_bitrates) - 1;
+       } else {
                int i = 0, j;
                enum ieee80211_band band;
                struct ieee80211_supported_band *bands;
index 625a6e6d1168376e7d5b3f55d09729ebc786f1f6..277a85df910eef03fe9c0354addf28fe3f2e4adc 100644 (file)
@@ -600,6 +600,11 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ibss,
        TP_ARGS(wiphy, netdev)
 );
 
+DEFINE_EVENT(wiphy_netdev_evt, rdev_leave_ocb,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+       TP_ARGS(wiphy, netdev)
+);
+
 DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa,
        TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
        TP_ARGS(wiphy, netdev)
@@ -680,9 +685,34 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac))
 );
 
-DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_del_station,
-       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *mac),
-       TP_ARGS(wiphy, netdev, mac)
+DECLARE_EVENT_CLASS(station_del,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct station_del_parameters *params),
+       TP_ARGS(wiphy, netdev, params),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(sta_mac)
+               __field(u8, subtype)
+               __field(u16, reason_code)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(sta_mac, params->mac);
+               __entry->subtype = params->subtype;
+               __entry->reason_code = params->reason_code;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+                 ", subtype: %u, reason_code: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
+                 __entry->subtype, __entry->reason_code)
+);
+
+DEFINE_EVENT(station_del, rdev_del_station,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct station_del_parameters *params),
+       TP_ARGS(wiphy, netdev, params)
 );
 
 DEFINE_EVENT(wiphy_netdev_mac_evt, rdev_get_station,
@@ -801,6 +831,51 @@ TRACE_EVENT(rdev_dump_mpath,
                  MAC_PR_ARG(next_hop))
 );
 
+TRACE_EVENT(rdev_get_mpp,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                u8 *dst, u8 *mpp),
+       TP_ARGS(wiphy, netdev, dst, mpp),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(dst)
+               MAC_ENTRY(mpp)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(dst, dst);
+               MAC_ASSIGN(mpp, mpp);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT
+                 ", mpp: " MAC_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG,
+                 MAC_PR_ARG(dst), MAC_PR_ARG(mpp))
+);
+
+TRACE_EVENT(rdev_dump_mpp,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, int idx,
+                u8 *dst, u8 *mpp),
+       TP_ARGS(wiphy, netdev, idx, mpp, dst),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(dst)
+               MAC_ENTRY(mpp)
+               __field(int, idx)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(dst, dst);
+               MAC_ASSIGN(mpp, mpp);
+               __entry->idx = idx;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
+                 MAC_PR_FMT ", mpp: " MAC_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
+                 MAC_PR_ARG(mpp))
+);
+
 TRACE_EVENT(rdev_return_int_mpath_info,
        TP_PROTO(struct wiphy *wiphy, int ret, struct mpath_info *pinfo),
        TP_ARGS(wiphy, ret, pinfo),
@@ -1246,6 +1321,22 @@ TRACE_EVENT(rdev_join_ibss,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid)
 );
 
+TRACE_EVENT(rdev_join_ocb,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                const struct ocb_setup *setup),
+       TP_ARGS(wiphy, netdev, setup),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG)
+);
+
 TRACE_EVENT(rdev_set_wiphy_params,
        TP_PROTO(struct wiphy *wiphy, u32 changed),
        TP_ARGS(wiphy, changed),
index 5e233a577d0fcd15e39b5eebc5678598c37637df..d0ac795445b7e40dc92ebb1e0bd9095fc4bab048 100644 (file)
@@ -442,7 +442,8 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                break;
        case cpu_to_le16(0):
                if (iftype != NL80211_IFTYPE_ADHOC &&
-                   iftype != NL80211_IFTYPE_STATION)
+                   iftype != NL80211_IFTYPE_STATION &&
+                   iftype != NL80211_IFTYPE_OCB)
                                return -1;
                break;
        }
@@ -519,6 +520,7 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                hdrlen = 24;
                break;
+       case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_ADHOC:
                /* DA SA BSSID */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
@@ -937,6 +939,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                        if (dev->ieee80211_ptr->use_4addr)
                                break;
                        /* fall through */
+               case NL80211_IFTYPE_OCB:
                case NL80211_IFTYPE_P2P_CLIENT:
                case NL80211_IFTYPE_ADHOC:
                        dev->priv_flags |= IFF_DONT_BRIDGE;