Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
authorDavid S. Miller <davem@davemloft.net>
Mon, 21 Nov 2011 18:50:33 +0000 (13:50 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 21 Nov 2011 18:50:33 +0000 (13:50 -0500)
The forcedeth changes had a conflict with the conversion over
to atomic u64 statistics in net-next.

The libertas cfg.c code had a conflict with the bss reference
counting fix by John Linville in net-next.

Conflicts:
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/wireless/libertas/cfg.c

454 files changed:
Documentation/networking/ieee802154.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/team.txt [new file with mode: 0644]
MAINTAINERS
arch/alpha/include/asm/socket.h
arch/arm/include/asm/socket.h
arch/avr32/include/asm/socket.h
arch/cris/include/asm/socket.h
arch/frv/include/asm/socket.h
arch/h8300/include/asm/socket.h
arch/ia64/include/asm/socket.h
arch/m32r/include/asm/socket.h
arch/m68k/include/asm/socket.h
arch/mips/include/asm/socket.h
arch/mn10300/include/asm/socket.h
arch/parisc/include/asm/socket.h
arch/powerpc/include/asm/socket.h
arch/s390/include/asm/socket.h
arch/sparc/include/asm/socket.h
arch/xtensa/include/asm/socket.h
drivers/bluetooth/ath3k.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_vhci.c
drivers/ieee802154/fakehard.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/lguest/lguest_device.c
drivers/misc/sgi-xp/xpnet.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/bonding/bond_main.c
drivers/net/can/dev.c
drivers/net/can/mscan/mscan.c
drivers/net/can/slcan.c
drivers/net/dummy.c
drivers/net/ethernet/3com/3c589_cs.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/3com/typhoon.c
drivers/net/ethernet/8390/8390.h
drivers/net/ethernet/8390/apne.c
drivers/net/ethernet/8390/ax88796.c
drivers/net/ethernet/8390/es3210.c
drivers/net/ethernet/8390/hp-plus.c
drivers/net/ethernet/8390/hp.c
drivers/net/ethernet/8390/hydra.c
drivers/net/ethernet/8390/lne390.c
drivers/net/ethernet/8390/ne-h8300.c
drivers/net/ethernet/8390/ne.c
drivers/net/ethernet/8390/ne2.c
drivers/net/ethernet/8390/ne2k-pci.c
drivers/net/ethernet/8390/ne3210.c
drivers/net/ethernet/8390/stnic.c
drivers/net/ethernet/8390/zorro8390.c
drivers/net/ethernet/adaptec/starfire.c
drivers/net/ethernet/amd/amd8111e.c
drivers/net/ethernet/amd/amd8111e.h
drivers/net/ethernet/amd/nmclan_cs.c
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/atheros/atlx/atl2.c
drivers/net/ethernet/atheros/atlx/atlx.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/sb1250-mac.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/brocade/bna/bnad_ethtool.c
drivers/net/ethernet/brocade/bna/cna.h
drivers/net/ethernet/chelsio/cxgb/cxgb2.c
drivers/net/ethernet/chelsio/cxgb/sge.c
drivers/net/ethernet/chelsio/cxgb/sge.h
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/dec/tulip/de2104x.c
drivers/net/ethernet/dec/tulip/dmfe.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/dec/tulip/uli526x.c
drivers/net/ethernet/dec/tulip/winbond-840.c
drivers/net/ethernet/dlink/sundance.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/fealnx.c
drivers/net/ethernet/freescale/fsl_pq_mdio.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/freescale/ucc_geth.h
drivers/net/ethernet/fujitsu/fmvj18x_cs.c
drivers/net/ethernet/i825xx/eepro.c
drivers/net/ethernet/ibm/emac/core.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/e1000/e1000_ethtool.c
drivers/net/ethernet/intel/e1000/e1000_hw.h
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/ethtool.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
drivers/net/ethernet/intel/ixgbevf/defines.h
drivers/net/ethernet/intel/ixgbevf/ethtool.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/intel/ixgbevf/vf.c
drivers/net/ethernet/jme.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/natsemi/ns83820.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/neterion/vxge/vxge-main.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_ethtool.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlge/qlge_ethtool.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sis/sis190.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/smsc/epic100.c
drivers/net/ethernet/smsc/smc91c92_cs.c
drivers/net/ethernet/smsc/smsc9420.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/sun/cassini.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/sun/sunhme.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/via/via-velocity.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xircom/xirc2ps_cs.c
drivers/net/ifb.c
drivers/net/loopback.c
drivers/net/mii.c
drivers/net/phy/mdio-bitbang.c
drivers/net/phy/mdio-gpio.c
drivers/net/phy/phy_device.c
drivers/net/team/Kconfig [new file with mode: 0644]
drivers/net/team/Makefile [new file with mode: 0644]
drivers/net/team/team.c [new file with mode: 0644]
drivers/net/team/team_mode_activebackup.c [new file with mode: 0644]
drivers/net/team/team_mode_roundrobin.c [new file with mode: 0644]
drivers/net/tun.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/wireless/Makefile
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/gpio.c
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/main.c
drivers/net/wireless/ath/ath9k/mci.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/mci.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/dma.h
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
drivers/net/wireless/brcm80211/brcmsmac/pmu.c
drivers/net/wireless/brcm80211/brcmsmac/pub.h
drivers/net/wireless/brcm80211/brcmsmac/rate.h
drivers/net/wireless/brcm80211/brcmsmac/srom.c
drivers/net/wireless/brcm80211/brcmsmac/srom.h
drivers/net/wireless/brcm80211/brcmutil/utils.c
drivers/net/wireless/brcm80211/include/brcmu_utils.h
drivers/net/wireless/brcm80211/include/defs.h
drivers/net/wireless/brcm80211/include/soc.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-cfg.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-mac80211.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/xen-netback/interface.c
drivers/net/xen-netfront.c
drivers/s390/kvm/kvm_virtio.c
drivers/s390/net/qeth_l3_main.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci.c
include/asm-generic/socket.h
include/linux/Kbuild
include/linux/errqueue.h
include/linux/ethtool.h
include/linux/ieee80211.h
include/linux/if.h
include/linux/if_team.h [new file with mode: 0644]
include/linux/mdio-bitbang.h
include/linux/mdio-gpio.h
include/linux/mii.h
include/linux/neighbour.h
include/linux/netdev_features.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/nl80211.h
include/linux/phonet.h
include/linux/skbuff.h
include/linux/virtio_config.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/cfg80211.h
include/net/icmp.h
include/net/ieee80211_radiotap.h
include/net/ieee802154.h
include/net/inet_connection_sock.h
include/net/ip.h
include/net/ipv6.h
include/net/mac80211.h
include/net/neighbour.h
include/net/netns/mib.h
include/net/nfc/nci.h
include/net/nfc/nci_core.h
include/net/protocol.h
include/net/sctp/structs.h
include/net/snmp.h
include/net/sock.h
include/net/tcp.h
include/net/udp.h
lib/vsprintf.c
net/8021q/vlan_dev.c
net/atm/clip.c
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/smp.c
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_if.c
net/bridge/br_private.h
net/core/dev.c
net/core/ethtool.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dccp/minisocks.c
net/decnet/dn_neigh.c
net/econet/af_econet.c
net/ieee802154/6lowpan.c
net/ieee802154/6lowpan.h
net/ieee802154/dgram.c
net/ieee802154/raw.c
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/ip_gre.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/ipip.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_minisocks.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/ipv6/datagram.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/udp.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/work.c
net/mac80211/wpa.c
net/nfc/nci/core.c
net/nfc/nci/data.c
net/nfc/nci/lib.c
net/nfc/nci/ntf.c
net/nfc/nci/rsp.c
net/packet/af_packet.c
net/phonet/pep.c
net/rfkill/core.c
net/sched/sch_choke.c
net/sched/sch_generic.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/transport.c
net/socket.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/scan.c
net/wireless/wext-compat.c

index f41ea24052206d7657ee8c10b90d857bdb1e373a..1dc1c24a7547019c1ade5232eb88780abf358c11 100644 (file)
@@ -78,3 +78,30 @@ in software. This is currently WIP.
 
 See header include/net/mac802154.h and several drivers in drivers/ieee802154/.
 
+6LoWPAN Linux implementation
+============================
+
+The IEEE 802.15.4 standard specifies an MTU of 128 bytes, yielding about 80
+octets of actual MAC payload once security is turned on, on a wireless link
+with a link throughput of 250 kbps or less.  The 6LoWPAN adaptation format
+[RFC4944] was specified to carry IPv6 datagrams over such constrained links,
+taking into account limited bandwidth, memory, or energy resources that are
+expected in applications such as wireless Sensor Networks.  [RFC4944] defines
+a Mesh Addressing header to support sub-IP forwarding, a Fragmentation header
+to support the IPv6 minimum MTU requirement [RFC2460], and stateless header
+compression for IPv6 datagrams (LOWPAN_HC1 and LOWPAN_HC2) to reduce the
+relatively large IPv6 and UDP headers down to (in the best case) several bytes.
+
+In Semptember 2011 the standard update was published - [RFC6282].
+It deprecates HC1 and HC2 compression and defines IPHC encoding format which is
+used in this Linux implementation.
+
+All the code related to 6lowpan you may find in files: net/ieee802154/6lowpan.*
+
+To setup 6lowpan interface you need (busybox release > 1.17.0):
+1. Add IEEE802.15.4 interface and initialize PANid;
+2. Add 6lowpan interface by command like:
+   # ip link add link wpan0 name lowpan0 type lowpan
+3. Set MAC (if needs):
+   # ip link set lowpan0 address de:ad:be:ef:ca:fe:ba:be
+4. Bring up 'lowpan0' interface
index f049a1ca186fbf6eb5e55ed9eb3a65bb8601b1f8..b8867061fce4019b88e55b5fad5496044f0d682d 100644 (file)
@@ -31,6 +31,16 @@ neigh/default/gc_thresh3 - INTEGER
        when using large numbers of interfaces and when communicating
        with large numbers of directly-connected peers.
 
+neigh/default/unres_qlen_bytes - INTEGER
+       The maximum number of bytes which may be used by packets
+       queued for each unresolved address by other network layers.
+       (added in linux 3.3)
+
+neigh/default/unres_qlen - INTEGER
+       The maximum number of packets which may be queued for each
+       unresolved address by other network layers.
+       (deprecated in linux 3.3) : use unres_qlen_bytes instead.
+
 mtu_expires - INTEGER
        Time, in seconds, that cached PMTU information is kept.
 
diff --git a/Documentation/networking/team.txt b/Documentation/networking/team.txt
new file mode 100644 (file)
index 0000000..5a01368
--- /dev/null
@@ -0,0 +1,2 @@
+Team devices are driven from userspace via libteam library which is here:
+       https://github.com/jpirko/libteam
index 29f9948b2cc0665582d1e32da78178387f793596..717d9e959b1598bb3640b790920001d06f74b861 100644 (file)
@@ -6495,6 +6495,13 @@ W:       http://tcp-lp-mod.sourceforge.net/
 S:     Maintained
 F:     net/ipv4/tcp_lp.c
 
+TEAM DRIVER
+M:     Jiri Pirko <jpirko@redhat.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/team/
+F:     include/linux/if_team.h
+
 TEGRA SUPPORT
 M:     Colin Cross <ccross@android.com>
 M:     Olof Johansson <olof@lixom.net>
index 06edfefc337332915833c7141fac17f2b1a60bba..082355f159e67930c284b76d33a4bb7f9a090b3a 100644 (file)
@@ -69,6 +69,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
index 90ffd04b8e74fb191a47ab79211cf1e128ad7b87..dec6f9afb3cf949de01bb4928dc9ba1429bc9b59 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index c8d1fae494763c2459279afd824dc576b7471795..247b88c760bef0615b9b470defb29e8b7645bd1d 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* __ASM_AVR32_SOCKET_H */
index 1a4a61909ca8705b3d0f11f186c717ba3b5141f1..e269264df7c4f38b35c8aafa07579a935afd1a23 100644 (file)
@@ -64,6 +64,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
 
index a6b26880c1ec2e79e316ff5a0f32bbc7fe09a79e..ce80fdadcce57ad1975c9daab73c823721a21f10 100644 (file)
@@ -62,5 +62,8 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
index 04c0f4596eb5b8ae072109677a35069a7c15d4a4..cf1daab6f27efb11007af681ee93fb29f64bb63c 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 51427eaa51ba996031aa40bf6800f35917a430b3..4b03664e3fb50534b27d9429c951f8b78a272210 100644 (file)
@@ -71,4 +71,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_IA64_SOCKET_H */
index 469787c30098aea921ddc988087162749840b3de..e8b8c5bb053c12135328d43fbc00fbe12b7db1b9 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_M32R_SOCKET_H */
index 9bf49c87d954a6c5ecf89cc2779ae8642dbe4f34..d4708ce466e068d6bc8935cc222eb923fc27b1a7 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 9de5190f248743a5c8a3926993ad88e5025d4437..ad5c0a7a02a7e34eaff203cf40d0d4b2f235c795 100644 (file)
@@ -82,6 +82,9 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #ifdef __KERNEL__
 
 /** sock_type - Socket types
index 4e60c42812880b8e3dcc05ddaf90e1815cfc198c..876356d7852248898968f012c8f70c22ad474e1d 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 225b7d6a1a0af44447521de4b133efa6be591bf8..d28c51b61067edab8da863ef0bd76861e2a0b4ff 100644 (file)
@@ -61,6 +61,9 @@
 
 #define SO_RXQ_OVFL             0x4021
 
+#define SO_WIFI_STATUS         0x4022
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
index 866f7606da6803924f17d71f74ac4ed70309f8f3..2fc2af8fbf59b892598844db7a254da4f4251b57 100644 (file)
@@ -69,4 +69,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index fdff1e995c73d45145ceb56afcf0f26a948636e6..67b5c1b14b51177851efca5e6d86f5a2729e61ea 100644 (file)
@@ -70,4 +70,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 9d3fefcff2f576b277ebc776c3bd7ddcada49272..8af1b64168b3abb17ddcf2711b9de2ca07b5ce58 100644 (file)
@@ -58,6 +58,9 @@
 
 #define SO_RXQ_OVFL             0x0024
 
+#define SO_WIFI_STATUS         0x0025
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index cbdf2ffaacff9cdc82afb41be8723a55b141c390..bb06968be227b0337ab7d77dbee537204fa898c4 100644 (file)
@@ -73,4 +73,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _XTENSA_SOCKET_H */
index 106beb194f3c8d438e105dab8d12aaecb8716103..1622772f802d9b4c2a94ad48ae62f16e3518a44b 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/bluetooth/bluetooth.h>
 
 #define VERSION "1.0"
+#define ATH3K_FIRMWARE "ath3k-1.fw"
 
 #define ATH3K_DNLOAD                           0x01
 #define ATH3K_GETSTATE                         0x05
@@ -400,9 +401,15 @@ static int ath3k_probe(struct usb_interface *intf,
                return 0;
        }
 
-       if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
-               BT_ERR("Error loading firmware");
-               return -EIO;
+       ret = request_firmware(&firmware, ATH3K_FIRMWARE, &udev->dev);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       BT_ERR("Firmware file \"%s\" not found",
+                                                       ATH3K_FIRMWARE);
+               else
+                       BT_ERR("Firmware file \"%s\" request failed (err=%d)",
+                                                       ATH3K_FIRMWARE, ret);
+               return ret;
        }
 
        ret = ath3k_load_firmware(udev, firmware);
@@ -441,4 +448,4 @@ MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Atheros AR30xx firmware driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ath3k-1.fw");
+MODULE_FIRMWARE(ATH3K_FIRMWARE);
index 61b591470a90827280005b50b000907a7e7c2ac2..a936763b8c3d97885baa577daa547b822c30ee79 100644 (file)
@@ -751,9 +751,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
        bfusb_close(hdev);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 }
 
index aed1904ea67b54f54d1c033073a6af281f3b0070..c6a0c6103743838fef1dd30157681e9d916115c7 100644 (file)
@@ -844,9 +844,7 @@ static int bluecard_close(bluecard_info_t *info)
        /* Turn FPGA off */
        outb(0x80, iobase + 0x30);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 4fc01949d39981a77b6e9dca90606ab94ae259b8..0c97e5d514b635b0574d3832d6b593263146f56e 100644 (file)
@@ -636,9 +636,7 @@ static int bt3c_close(bt3c_info_t *info)
 
        bt3c_hci_close(hdev);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 526b61807d945dda8a6983758b348fe7ea0bd233..200b3a2877d69c43754d6210bc0ad2feb5be81c4 100644 (file)
@@ -565,9 +565,7 @@ static int btuart_close(btuart_info_t *info)
 
        spin_unlock_irqrestore(&(info->lock), flags);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index fe4ebc375b3dafd274da41c803cbb9ac37754146..2bd87d45f1c2313be3efc5a3728a8fcbe687b0d7 100644 (file)
@@ -315,7 +315,8 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -400,7 +401,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -523,7 +525,8 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -727,6 +730,9 @@ static int btusb_send_frame(struct sk_buff *skb)
                usb_fill_bulk_urb(urb, data->udev, pipe,
                                skb->data, skb->len, btusb_tx_complete, skb);
 
+               if (skb->priority >= HCI_PRIO_MAX - 1)
+                       urb->transfer_flags  = URB_ISO_ASAP;
+
                hdev->stat.acl_tx++;
                break;
 
@@ -770,7 +776,9 @@ skip_waking:
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
                kfree(urb->setup_packet);
                usb_unanchor_urb(urb);
        } else {
index 5e4c2de9fc3f778bf71c71c89d9222edce4bcd36..969bb22e493f530977ab1c5258f55067963a6cac 100644 (file)
@@ -551,9 +551,7 @@ static int dtl1_close(dtl1_info_t *info)
 
        spin_unlock_irqrestore(&(info->lock), flags);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 67c180c2c1e0fbf27951862e30a0787deba4d4a0..2e302a11ab5528ccd078f41f9439c1067fd9704f 100644 (file)
@@ -264,10 +264,7 @@ static int vhci_release(struct inode *inode, struct file *file)
        struct vhci_data *data = file->private_data;
        struct hci_dev *hdev = data->hdev;
 
-       if (hci_unregister_dev(hdev) < 0) {
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-       }
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        file->private_data = NULL;
index eb0e2ccc79ae6c3098cdb065511b047218b0c6a0..73d453159408d62725e81317001889071211f094 100644 (file)
@@ -343,7 +343,7 @@ 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_NO_CSUM;
+       dev->features           = NETIF_F_HW_CSUM;
        dev->needed_tailroom    = 2; /* FCS */
        dev->mtu                = 127;
        dev->tx_queue_len       = 10;
index c00d2f3f8966b5084ec5b5875845884b6b294789..4b3fa711a2470edc4485f286a3ae4ced7adec74b 100644 (file)
@@ -1589,7 +1589,7 @@ static const struct ethtool_ops nes_ethtool_ops = {
        .set_pauseparam = nes_netdev_set_pauseparam,
 };
 
-static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, u32 features)
+static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, netdev_features_t features)
 {
        struct nes_adapter *nesadapter = nesdev->nesadapter;
        u32 u32temp;
@@ -1610,7 +1610,7 @@ static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev,
        spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
 }
 
-static u32 nes_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t nes_fix_features(struct net_device *netdev, netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -1624,7 +1624,7 @@ static u32 nes_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int nes_set_features(struct net_device *netdev, u32 features)
+static int nes_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct nes_vnic *nesvnic = netdev_priv(netdev);
        struct nes_device *nesdev = nesvnic->nesdev;
index 7567b60002309a19a2d0a4cc13da855a46042be4..efd7a9636aff893b4a73e803a5b147a951a0fcb6 100644 (file)
@@ -171,7 +171,7 @@ static int ipoib_stop(struct net_device *dev)
        return 0;
 }
 
-static u32 ipoib_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
index 0dc30ffde5ad7a8defc591c42a251bb9e59c35a9..595d7319701680d9360e9f252d9f0273e7de8726 100644 (file)
@@ -381,6 +381,11 @@ error:
        return PTR_ERR(vqs[i]);
 }
 
+static const char *lg_bus_name(struct virtio_device *vdev)
+{
+       return "";
+}
+
 /* The ops structure which hooks everything together. */
 static struct virtio_config_ops lguest_config_ops = {
        .get_features = lg_get_features,
@@ -392,6 +397,7 @@ static struct virtio_config_ops lguest_config_ops = {
        .reset = lg_reset,
        .find_vqs = lg_find_vqs,
        .del_vqs = lg_del_vqs,
+       .bus_name = lg_bus_name,
 };
 
 /*
index 42f067347bc70fd8f24466ed4384408191812611..3fac67a5204cfa768717a00b6628079fd37f939d 100644 (file)
@@ -576,7 +576,7 @@ xpnet_init(void)
         * report an error if the data is not retrievable and the
         * packet will be dropped.
         */
-       xpnet_device->features = NETIF_F_NO_CSUM;
+       xpnet_device->features = NETIF_F_HW_CSUM;
 
        result = register_netdev(xpnet_device);
        if (result != 0) {
index 654a5e94e0e7c4f227c93b75a7791c406c586d38..debdf1c07c5b8b8c484e020507d902cbc60246b2 100644 (file)
@@ -125,6 +125,8 @@ config IFB
          'ifb1' etc.
          Look at the iproute2 documentation directory for usage etc
 
+source "drivers/net/team/Kconfig"
+
 config MACVLAN
        tristate "MAC-VLAN support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index fa877cd2b1393cfd09d107355dc5c4f4526008dc..4e4ebfe1aa535367b15b3e480c657215b163a5d2 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_NET) += Space.o loopback.o
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
 obj-$(CONFIG_PHYLIB) += phy/
 obj-$(CONFIG_RIONET) += rionet.o
+obj-$(CONFIG_NET_TEAM) += team/
 obj-$(CONFIG_TUN) += tun.o
 obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
index b0c577256487b4b7c35d690da3a2ca619d2deb4c..25a44d94be172ec9a3c64cdcdd4efdc931f99682 100644 (file)
@@ -1325,11 +1325,12 @@ static int bond_sethwaddr(struct net_device *bond_dev,
        return 0;
 }
 
-static u32 bond_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t bond_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct slave *slave;
        struct bonding *bond = netdev_priv(dev);
-       u32 mask;
+       netdev_features_t mask;
        int i;
 
        read_lock(&bond->lock);
@@ -1363,7 +1364,7 @@ static void bond_compute_features(struct bonding *bond)
 {
        struct slave *slave;
        struct net_device *bond_dev = bond->dev;
-       u32 vlan_features = BOND_VLAN_FEATURES;
+       netdev_features_t vlan_features = BOND_VLAN_FEATURES;
        unsigned short max_hard_header_len = ETH_HLEN;
        int i;
 
@@ -1897,7 +1898,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        struct bonding *bond = netdev_priv(bond_dev);
        struct slave *slave, *oldcurrent;
        struct sockaddr addr;
-       u32 old_features = bond_dev->features;
+       netdev_features_t old_features = bond_dev->features;
 
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -4360,7 +4361,7 @@ static void bond_setup(struct net_device *bond_dev)
                                NETIF_F_HW_VLAN_RX |
                                NETIF_F_HW_VLAN_FILTER;
 
-       bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
+       bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
        bond_dev->features |= bond_dev->hw_features;
 }
 
index 25695bde0549138a572f2eeb414f686af869051f..120f1ab5a2ce0d945ba76878afcc0b2352a11f18 100644 (file)
@@ -454,7 +454,7 @@ static void can_setup(struct net_device *dev)
 
        /* New-style flags. */
        dev->flags = IFF_NOARP;
-       dev->features = NETIF_F_NO_CSUM;
+       dev->features = NETIF_F_HW_CSUM;
 }
 
 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
index ec4a3119e2c93d9b6ee0c157a6c13c939d612a16..1c82dd8b896e773ec38fc4177ddb6e77db559f9a 100644 (file)
@@ -581,7 +581,10 @@ static int mscan_open(struct net_device *dev)
 
        priv->open_time = jiffies;
 
-       clrbits8(&regs->canctl1, MSCAN_LISTEN);
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               setbits8(&regs->canctl1, MSCAN_LISTEN);
+       else
+               clrbits8(&regs->canctl1, MSCAN_LISTEN);
 
        ret = mscan_start(dev);
        if (ret)
@@ -690,7 +693,8 @@ struct net_device *alloc_mscandev(void)
        priv->can.bittiming_const = &mscan_bittiming_const;
        priv->can.do_set_bittiming = mscan_do_set_bittiming;
        priv->can.do_set_mode = mscan_do_set_mode;
-       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+               CAN_CTRLMODE_LISTENONLY;
 
        for (i = 0; i < TX_QUEUE_SIZE; i++) {
                priv->tx_queue[i].id = i;
index a979b006f4591fe68773dbe5db84dcc160439792..3f1ebcc2cb831af2f09add75d793fd9b1d67f57b 100644 (file)
@@ -387,7 +387,7 @@ static void slc_setup(struct net_device *dev)
 
        /* New-style flags. */
        dev->flags              = IFF_NOARP;
-       dev->features           = NETIF_F_NO_CSUM;
+       dev->features           = NETIF_F_HW_CSUM;
 }
 
 /******************************************
index a7c5e8831e8c0f3a5a01e5adc53b29b2bc85129d..087648ea1edb0ff015ce8abce33ef7ea7a71e0d2 100644 (file)
@@ -134,7 +134,7 @@ static void dummy_setup(struct net_device *dev)
        dev->flags |= IFF_NOARP;
        dev->flags &= ~IFF_MULTICAST;
        dev->features   |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO;
-       dev->features   |= NETIF_F_NO_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
+       dev->features   |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
        random_ether_addr(dev->dev_addr);
 }
 
index 972f80ecc510a7346c5ca364535faed2a8e1bbea..da410f036869cd4cb4f9368acfc4441c027f2278 100644 (file)
@@ -468,9 +468,10 @@ static void tc589_reset(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info),
+               "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
index b42c06baba8983bbf1b78c1115d7a72f1a262864..8153a3e0a1a4457a5c156508d7c605362bc76e37 100644 (file)
@@ -2929,15 +2929,17 @@ static void vortex_get_drvinfo(struct net_device *dev,
 {
        struct vortex_private *vp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        if (VORTEX_PCI(vp)) {
-               strcpy(info->bus_info, pci_name(VORTEX_PCI(vp)));
+               strlcpy(info->bus_info, pci_name(VORTEX_PCI(vp)),
+                       sizeof(info->bus_info));
        } else {
                if (VORTEX_EISA(vp))
-                       strcpy(info->bus_info, dev_name(vp->gendev));
+                       strlcpy(info->bus_info, dev_name(vp->gendev),
+                               sizeof(info->bus_info));
                else
-                       sprintf(info->bus_info, "EISA 0x%lx %d",
-                                       dev->base_addr, dev->irq);
+                       snprintf(info->bus_info, sizeof(info->bus_info),
+                               "EISA 0x%lx %d", dev->base_addr, dev->irq);
        }
 }
 
index 20ea07508ac747304dd1448da1e7deb4d9a67041..6d6bc754b1a8e9f3fd49255aaadfe5620c49d567 100644 (file)
@@ -988,21 +988,23 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 
        smp_rmb();
        if(tp->card_state == Sleeping) {
-               strcpy(info->fw_version, "Sleep image");
+               strlcpy(info->fw_version, "Sleep image",
+                       sizeof(info->fw_version));
        } else {
                INIT_COMMAND_WITH_RESPONSE(&xp_cmd, TYPHOON_CMD_READ_VERSIONS);
                if(typhoon_issue_command(tp, 1, &xp_cmd, 3, xp_resp) < 0) {
-                       strcpy(info->fw_version, "Unknown runtime");
+                       strlcpy(info->fw_version, "Unknown runtime",
+                               sizeof(info->fw_version));
                } else {
                        u32 sleep_ver = le32_to_cpu(xp_resp[0].parm2);
-                       snprintf(info->fw_version, 32, "%02x.%03x.%03x",
-                                sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
-                                sleep_ver & 0xfff);
+                       snprintf(info->fw_version, sizeof(info->fw_version),
+                               "%02x.%03x.%03x", sleep_ver >> 24,
+                               (sleep_ver >> 12) & 0xfff, sleep_ver & 0xfff);
                }
        }
 
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->bus_info, pci_name(pci_dev));
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
 }
 
 static int
index 58a12e4c78f953da62b043550dcc89093ff1cbc5..ef325ffa1b5ac63dd61dd0c0230c8a63a1a4a6cf 100644 (file)
@@ -14,8 +14,6 @@
 
 #define TX_PAGES 12    /* Two Tx slots */
 
-#define ETHER_ADDR_LEN 6
-
 /* The 8390 specific per-packet-header format. */
 struct e8390_pkt_hdr {
   unsigned char status; /* status */
index 547737340cbba774c158e613857a58d27d282d7c..3ad5d2f9a49cc42622038ff1986ac8505952f66a 100644 (file)
@@ -318,7 +318,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
     if (i) return i;
 
-    for(i = 0; i < ETHER_ADDR_LEN; i++)
+    for (i = 0; i < ETH_ALEN; i++)
        dev->dev_addr[i] = SA_prom[i];
 
     printk(" %pM\n", dev->dev_addr);
index e9f8432f55b461f388be8643386b948a5b08ca45..2a3b8c2676bd5a12833db60c2c429bfef329c2cf 100644 (file)
@@ -735,15 +735,14 @@ static int ax_init_dev(struct net_device *dev)
        if (ax->plat->flags & AXFLG_MAC_FROMDEV) {
                ei_outb(E8390_NODMA + E8390_PAGE1 + E8390_STOP,
                        ei_local->mem + E8390_CMD); /* 0x61 */
-               for (i = 0; i < ETHER_ADDR_LEN; i++)
+               for (i = 0; i < ETH_ALEN; i++)
                        dev->dev_addr[i] =
                                ei_inb(ioaddr + EN1_PHYS_SHIFT(i));
        }
 
        if ((ax->plat->flags & AXFLG_MAC_FROMPLATFORM) &&
            ax->plat->mac_addr)
-               memcpy(dev->dev_addr, ax->plat->mac_addr,
-                      ETHER_ADDR_LEN);
+               memcpy(dev->dev_addr, ax->plat->mac_addr, ETH_ALEN);
 
        ax_reset_8390(dev);
 
index 7a09575ecff05c3f8f48afb68eb5da4ddbbc2326..6428f9e7a554d7b994da4a9f982b44cc01359421 100644 (file)
@@ -195,7 +195,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
                goto out;
        }
 
-       for (i = 0; i < ETHER_ADDR_LEN ; i++)
+       for (i = 0; i < ETH_ALEN ; i++)
                dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
 
 /*     Check the Racal vendor ID as well. */
index eeac843dcd2df9f6298ca12e6e60aecfdff18975..d42938b6b596e32b6a00b6c562fa129cc3600d60 100644 (file)
@@ -202,7 +202,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
        /* Retrieve and checksum the station address. */
        outw(MAC_Page, ioaddr + HP_PAGING);
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++) {
+       for(i = 0; i < ETH_ALEN; i++) {
                unsigned char inval = inb(ioaddr + 8 + i);
                dev->dev_addr[i] = inval;
                checksum += inval;
index 18564d4a7c04d0c9fc1f6050f78bd67c2532f90f..113f1e075a2644bdab095bf087d02799f3c82238 100644 (file)
@@ -156,7 +156,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
 
        printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for(i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = inb(ioaddr + i);
 
        printk(" %pM", dev->dev_addr);
index 3dac937a67c4d0c184fb434b26e973d432f34518..5370c884620b1503a6526bb305ee6c7f495b031f 100644 (file)
@@ -129,7 +129,7 @@ static int __devinit hydra_init(struct zorro_dev *z)
     if (!dev)
        return -ENOMEM;
 
-    for(j = 0; j < ETHER_ADDR_LEN; j++)
+    for (j = 0; j < ETH_ALEN; j++)
        dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j));
 
     /* We must set the 8390 for word mode. */
index f9888d20177ba9d03af278a1b8eefc8bc3ced33f..69490ae018ea5e8a9cfbb25d06287a6280492319 100644 (file)
@@ -191,14 +191,14 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
                || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1
                || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) {
                printk("lne390.c: card not found");
-               for(i = 0; i < ETHER_ADDR_LEN; i++)
+               for (i = 0; i < ETH_ALEN; i++)
                        printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i));
                printk(" (invalid prefix).\n");
                return -ENODEV;
        }
 #endif
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
        printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n",
               0xa+revision, ioaddr/0x1000, dev->dev_addr);
index cd36a6a5f4081390fc6a5af810e864f93a55ec67..9b9c77d5a65cca2858d4a35c6210500363c54dfd 100644 (file)
@@ -312,7 +312,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
 
        dev->base_addr = ioaddr;
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = SA_prom[i];
        printk(" %pM\n", dev->dev_addr);
 
index 1063093b3afc5cfd9cd1545b73cbbdd64db0ec12..f92ea2a65a576d20f5732975794421cfc142ad28 100644 (file)
@@ -503,12 +503,12 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
 #ifdef CONFIG_PLAT_MAPPI
        outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP,
                ioaddr + E8390_CMD); /* 0x61 */
-       for (i = 0 ; i < ETHER_ADDR_LEN ; i++) {
+       for (i = 0; i < ETH_ALEN; i++) {
                dev->dev_addr[i] = SA_prom[i]
                        = inb_p(ioaddr + EN1_PHYS_SHIFT(i));
        }
 #else
-       for(i = 0; i < ETHER_ADDR_LEN; i++) {
+       for (i = 0; i < ETH_ALEN; i++) {
                dev->dev_addr[i] = SA_prom[i];
        }
 #endif
index 70cdc6996342f9b6f5ab821593da43521ca6eb44..922b32036c6380d296334a9503e8e334f9f4cc0f 100644 (file)
@@ -460,7 +460,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
 
        dev->base_addr = base_addr;
 
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = SA_prom[i];
 
        printk(" %pM\n", dev->dev_addr);
index 39923425ba2547f56fc4d02306ebac2848030635..3fab04a0034a3aa68ecc45544cf3cdf9e682af31 100644 (file)
@@ -639,9 +639,9 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev,
        struct ei_device *ei = netdev_priv(dev);
        struct pci_dev *pci_dev = (struct pci_dev *) ei->priv;
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops ne2k_pci_ethtool_ops = {
index 243ed2aee88e35e801a2c6582f8a80d4e287ba7b..2a3e8057feaef80341460ecd1854c55d3dfdd61d 100644 (file)
@@ -125,7 +125,7 @@ static int __init ne3210_eisa_probe (struct device *device)
 #endif
 
        port_index = inb(ioaddr + NE3210_CFG2) >> 6;
-       for(i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
        printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n",
                edev->slot, ifmap[port_index], dev->dev_addr);
index d85f0a84bc7bc0c2a993d72a591114a2f43bb29f..3b903759980a01c318ead3411249adec47382e57 100644 (file)
@@ -114,7 +114,7 @@ static int __init stnic_probe(void)
 #ifdef CONFIG_SH_STANDARD_BIOS
   sh_bios_get_node_addr (stnic_eadr);
 #endif
-  for (i = 0; i < ETHER_ADDR_LEN; i++)
+  for (i = 0; i < ETH_ALEN; i++)
     dev->dev_addr[i] = stnic_eadr[i];
 
   /* Set the base address to point to the NIC, not the "real" base! */
index 3aa9fe9999b5c5c6a34639fa8a1768234d75af1c..bcd27323b2030dccb635def78f29dcebc0df4192 100644 (file)
@@ -365,7 +365,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
        if (i)
                return i;
 
-       for (i = 0; i < ETHER_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = SA_prom[i];
 
        pr_debug("Found ethernet address: %pM\n", dev->dev_addr);
index 6d9f6911000ffad9d2b8a299c6ae5fd82ebfcfe6..a446e251908bf714cc0aaab62e39335de1e3114b 100644 (file)
@@ -1842,9 +1842,9 @@ static int check_if_running(struct net_device *dev)
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index a9745f4ddbfe11ad06573f2aa1043f2e6f249a53..33e0a8c20f6b42db39ae423fbed5e30e9c100656 100644 (file)
@@ -499,7 +499,7 @@ static int amd8111e_restart(struct net_device *dev)
        writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2 );
 
        /* Setting the MAC address to the device */
-       for(i = 0; i < ETH_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                writeb( dev->dev_addr[i], mmio + PADR + i );
 
        /* Enable interrupt coalesce */
@@ -1412,10 +1412,11 @@ static void amd8111e_get_drvinfo(struct net_device* dev, struct ethtool_drvinfo
 {
        struct amd8111e_priv *lp = netdev_priv(dev);
        struct pci_dev *pci_dev = lp->pci_dev;
-       strcpy (info->driver, MODULE_NAME);
-       strcpy (info->version, MODULE_VERS);
-       sprintf(info->fw_version,"%u",chip_version);
-       strcpy (info->bus_info, pci_name(pci_dev));
+       strlcpy(info->driver, MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, MODULE_VERS, sizeof(info->version));
+       snprintf(info->fw_version, sizeof(info->fw_version),
+               "%u", chip_version);
+       strlcpy(info->bus_info, pci_name(pci_dev), sizeof(info->bus_info));
 }
 
 static int amd8111e_get_regs_len(struct net_device *dev)
@@ -1549,7 +1550,7 @@ static int amd8111e_set_mac_address(struct net_device *dev, void *p)
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
        spin_lock_irq(&lp->lock);
        /* Setting the MAC address to the device */
-       for(i = 0; i < ETH_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                writeb( dev->dev_addr[i], lp->mmio + PADR + i );
 
        spin_unlock_irq(&lp->lock);
@@ -1885,7 +1886,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
        }
 
        /* Initializing MAC address */
-       for(i = 0; i < ETH_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = readb(lp->mmio + PADR + i);
 
        /* Setting user defined parametrs */
index 2ff2e7a12dd0217764f5c4867151903115720c37..5bbb53a1999cde710cb74a25e04e23b6059de6d2 100644 (file)
@@ -586,7 +586,6 @@ typedef enum {
 
 #define PKT_BUFF_SZ                    1536
 #define MIN_PKT_LEN                    60
-#define ETH_ADDR_LEN                   6
 
 #define  AMD8111E_TX_TIMEOUT           (3 * HZ)/* 3 sec */
 #define SOFT_TIMER_FREQ                0xBEBC  /* 0.5 sec */
index 3accd5d21b08ff1bb5a423485d1bf775273501ce..6be0dd67631a448cdeafb39ce23185ae150c22ed 100644 (file)
@@ -160,8 +160,6 @@ Include Files
 Defines
 ---------------------------------------------------------------------------- */
 
-#define ETHER_ADDR_LEN                 ETH_ALEN
-                                       /* 6 bytes in an Ethernet Address */
 #define MACE_LADRF_LEN                 8
                                        /* 8 bytes in Logical Address Filter */
 
@@ -600,7 +598,7 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
        }
   }
   /* Set PADR register */
-  for (i = 0; i < ETHER_ADDR_LEN; i++)
+  for (i = 0; i < ETH_ALEN; i++)
     mace_write(lp, ioaddr, MACE_PADR, enet_addr[i]);
 
   /* MAC Configuration Control Register should be written last */
@@ -639,11 +637,11 @@ static int nmclan_config(struct pcmcia_device *link)
 
   /* Read the ethernet address from the CIS. */
   len = pcmcia_get_tuple(link, 0x80, &buf);
-  if (!buf || len < ETHER_ADDR_LEN) {
+  if (!buf || len < ETH_ALEN) {
          kfree(buf);
          goto failed;
   }
-  memcpy(dev->dev_addr, buf, ETHER_ADDR_LEN);
+  memcpy(dev->dev_addr, buf, ETH_ALEN);
   kfree(buf);
 
   /* Verify configuration by reading the MACE ID. */
@@ -822,9 +820,10 @@ static int mace_close(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info),
+               "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
@@ -1420,7 +1419,7 @@ Output
 static void set_multicast_list(struct net_device *dev)
 {
   mace_private *lp = netdev_priv(dev);
-  int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */
+  int adr[ETH_ALEN] = {0}; /* Ethernet address */
   struct netdev_hw_addr *ha;
 
 #ifdef PCMCIA_DEBUG
@@ -1442,7 +1441,7 @@ static void set_multicast_list(struct net_device *dev)
     /* Calculate multicast logical address filter */
     memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
     netdev_for_each_mc_addr(ha, dev) {
-      memcpy(adr, ha->addr, ETHER_ADDR_LEN);
+      memcpy(adr, ha->addr, ETH_ALEN);
       BuildLAF(lp->multicast_ladrf, adr);
     }
   }
index f92bc6e348283f2bb026ffcce0f37ddd07eb4359..20e6dab0186c78da49d43e14b5f66370936c7cf3 100644 (file)
@@ -711,12 +711,14 @@ static void pcnet32_get_drvinfo(struct net_device *dev,
 {
        struct pcnet32_private *lp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        if (lp->pci_dev)
-               strcpy(info->bus_info, pci_name(lp->pci_dev));
+               strlcpy(info->bus_info, pci_name(lp->pci_dev),
+                       sizeof(info->bus_info));
        else
-               sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr);
+               snprintf(info->bus_info, sizeof(info->bus_info),
+                       "VLB 0x%lx", dev->base_addr);
 }
 
 static u32 pcnet32_get_link(struct net_device *dev)
index 02c7ed8d9eca01414ef78aaeb84011ee60f38069..b8591246eb4c35b9a12b53254ba4853381238ee7 100644 (file)
@@ -411,7 +411,7 @@ static void atl1c_set_multi(struct net_device *netdev)
        }
 }
 
-static void __atl1c_vlan_mode(u32 features, u32 *mac_ctrl_data)
+static void __atl1c_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -422,7 +422,8 @@ static void __atl1c_vlan_mode(u32 features, u32 *mac_ctrl_data)
        }
 }
 
-static void atl1c_vlan_mode(struct net_device *netdev, u32 features)
+static void atl1c_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atl1c_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = adapter->pdev;
@@ -482,7 +483,8 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
                roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
 }
 
-static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atl1c_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -499,9 +501,10 @@ static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atl1c_set_features(struct net_device *netdev, u32 features)
+static int atl1c_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atl1c_vlan_mode(netdev, features);
index 6269438d365f9d413650611e8e06cccf8d3e9a5c..6e61f9f9ebb538b4fc6d0ef885b6c427fc48e3e7 100644 (file)
@@ -310,10 +310,12 @@ static void atl1e_get_drvinfo(struct net_device *netdev,
 {
        struct atl1e_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(drvinfo->driver,  atl1e_driver_name, 32);
-       strncpy(drvinfo->version, atl1e_driver_version, 32);
-       strncpy(drvinfo->fw_version, "L1e", 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  atl1e_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, atl1e_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "L1e", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
        drvinfo->regdump_len = atl1e_get_regs_len(netdev);
index 95483bcac1d029c38764385507d8a6824b4f504f..c915c0873810ddb7c561aa416b34c416c5fb8b42 100644 (file)
@@ -313,7 +313,7 @@ static void atl1e_set_multi(struct net_device *netdev)
        }
 }
 
-static void __atl1e_vlan_mode(u32 features, u32 *mac_ctrl_data)
+static void __atl1e_vlan_mode(netdev_features_t features, u32 *mac_ctrl_data)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -324,7 +324,8 @@ static void __atl1e_vlan_mode(u32 features, u32 *mac_ctrl_data)
        }
 }
 
-static void atl1e_vlan_mode(struct net_device *netdev, u32 features)
+static void atl1e_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atl1e_adapter *adapter = netdev_priv(netdev);
        u32 mac_ctrl_data = 0;
@@ -370,7 +371,8 @@ static int atl1e_set_mac_addr(struct net_device *netdev, void *p)
        return 0;
 }
 
-static u32 atl1e_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atl1e_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -384,9 +386,10 @@ static u32 atl1e_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atl1e_set_features(struct net_device *netdev, u32 features)
+static int atl1e_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atl1e_vlan_mode(netdev, features);
index 1feae5928a4b0060707c1f8b6111caed46ea66f5..071f4c858969dad5ff166d69f62073f4c0518b09 100644 (file)
@@ -361,7 +361,7 @@ static inline void atl2_irq_disable(struct atl2_adapter *adapter)
     synchronize_irq(adapter->pdev->irq);
 }
 
-static void __atl2_vlan_mode(u32 features, u32 *ctrl)
+static void __atl2_vlan_mode(netdev_features_t features, u32 *ctrl)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -372,7 +372,8 @@ static void __atl2_vlan_mode(u32 features, u32 *ctrl)
        }
 }
 
-static void atl2_vlan_mode(struct net_device *netdev, u32 features)
+static void atl2_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atl2_adapter *adapter = netdev_priv(netdev);
        u32 ctrl;
@@ -391,7 +392,8 @@ static void atl2_restore_vlan(struct atl2_adapter *adapter)
        atl2_vlan_mode(adapter->netdev, adapter->netdev->features);
 }
 
-static u32 atl2_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atl2_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -405,9 +407,10 @@ static u32 atl2_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atl2_set_features(struct net_device *netdev, u32 features)
+static int atl2_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atl2_vlan_mode(netdev, features);
@@ -2049,10 +2052,12 @@ static void atl2_get_drvinfo(struct net_device *netdev,
 {
        struct atl2_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(drvinfo->driver,  atl2_driver_name, 32);
-       strncpy(drvinfo->version, atl2_driver_version, 32);
-       strncpy(drvinfo->fw_version, "L2", 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  atl2_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, atl2_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "L2", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
        drvinfo->regdump_len = atl2_get_regs_len(netdev);
index aabcf4b5745a31df2de00a1f6dcdd9a015b33b76..8ff7411094d58d545b5845874adc164b54e7c07f 100644 (file)
@@ -211,7 +211,7 @@ static void atlx_link_chg_task(struct work_struct *work)
        spin_unlock_irqrestore(&adapter->lock, flags);
 }
 
-static void __atlx_vlan_mode(u32 features, u32 *ctrl)
+static void __atlx_vlan_mode(netdev_features_t features, u32 *ctrl)
 {
        if (features & NETIF_F_HW_VLAN_RX) {
                /* enable VLAN tag insert/strip */
@@ -222,7 +222,8 @@ static void __atlx_vlan_mode(u32 features, u32 *ctrl)
        }
 }
 
-static void atlx_vlan_mode(struct net_device *netdev, u32 features)
+static void atlx_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct atlx_adapter *adapter = netdev_priv(netdev);
        unsigned long flags;
@@ -242,7 +243,8 @@ static void atlx_restore_vlan(struct atlx_adapter *adapter)
        atlx_vlan_mode(adapter->netdev, adapter->netdev->features);
 }
 
-static u32 atlx_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t atlx_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -256,9 +258,10 @@ static u32 atlx_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int atlx_set_features(struct net_device *netdev, u32 features)
+static int atlx_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                atlx_vlan_mode(netdev, features);
index 965c7235804d61aa4c493b472239a29bde66bcb7..66f6e7f654c3088fcd731c5a9ec92a51b59a83f7 100644 (file)
@@ -2064,21 +2064,12 @@ __acquires(&bp->phy_lock)
                bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
                adv1000_reg &= PHY_ALL_1000_SPEED;
 
-               if (bp->advertising & ADVERTISED_10baseT_Half)
-                       new_adv_reg |= ADVERTISE_10HALF;
-               if (bp->advertising & ADVERTISED_10baseT_Full)
-                       new_adv_reg |= ADVERTISE_10FULL;
-               if (bp->advertising & ADVERTISED_100baseT_Half)
-                       new_adv_reg |= ADVERTISE_100HALF;
-               if (bp->advertising & ADVERTISED_100baseT_Full)
-                       new_adv_reg |= ADVERTISE_100FULL;
-               if (bp->advertising & ADVERTISED_1000baseT_Full)
-                       new_adv1000_reg |= ADVERTISE_1000FULL;
-
+               new_adv_reg = ethtool_adv_to_mii_100bt(bp->advertising);
                new_adv_reg |= ADVERTISE_CSMA;
-
                new_adv_reg |= bnx2_phy_get_pause_adv(bp);
 
+               new_adv1000_reg |= ethtool_adv_to_mii_1000T(bp->advertising);
+
                if ((adv1000_reg != new_adv1000_reg) ||
                        (adv_reg != new_adv_reg) ||
                        ((bmcr & BMCR_ANENABLE) == 0)) {
@@ -2734,31 +2725,27 @@ bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
 }
 
 static inline int
-bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
+bnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp)
 {
-       struct sk_buff *skb;
+       u8 *data;
        struct sw_bd *rx_buf = &rxr->rx_buf_ring[index];
        dma_addr_t mapping;
        struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
-       unsigned long align;
 
-       skb = __netdev_alloc_skb(bp->dev, bp->rx_buf_size, gfp);
-       if (skb == NULL) {
+       data = kmalloc(bp->rx_buf_size, gfp);
+       if (!data)
                return -ENOMEM;
-       }
-
-       if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
-               skb_reserve(skb, BNX2_RX_ALIGN - align);
 
-       mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_use_size,
+       mapping = dma_map_single(&bp->pdev->dev,
+                                get_l2_fhdr(data),
+                                bp->rx_buf_use_size,
                                 PCI_DMA_FROMDEVICE);
        if (dma_mapping_error(&bp->pdev->dev, mapping)) {
-               dev_kfree_skb(skb);
+               kfree(data);
                return -EIO;
        }
 
-       rx_buf->skb = skb;
-       rx_buf->desc = (struct l2_fhdr *) skb->data;
+       rx_buf->data = data;
        dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
@@ -2965,8 +2952,8 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
 }
 
 static inline void
-bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
-                 struct sk_buff *skb, u16 cons, u16 prod)
+bnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
+                  u8 *data, u16 cons, u16 prod)
 {
        struct sw_bd *cons_rx_buf, *prod_rx_buf;
        struct rx_bd *cons_bd, *prod_bd;
@@ -2980,8 +2967,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
 
        rxr->rx_prod_bseq += bp->rx_buf_use_size;
 
-       prod_rx_buf->skb = skb;
-       prod_rx_buf->desc = (struct l2_fhdr *) skb->data;
+       prod_rx_buf->data = data;
 
        if (cons == prod)
                return;
@@ -2995,33 +2981,39 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
        prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
 }
 
-static int
-bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
+static struct sk_buff *
+bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data,
            unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr,
            u32 ring_idx)
 {
        int err;
        u16 prod = ring_idx & 0xffff;
+       struct sk_buff *skb;
 
-       err = bnx2_alloc_rx_skb(bp, rxr, prod, GFP_ATOMIC);
+       err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC);
        if (unlikely(err)) {
-               bnx2_reuse_rx_skb(bp, rxr, skb, (u16) (ring_idx >> 16), prod);
+               bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod);
+error:
                if (hdr_len) {
                        unsigned int raw_len = len + 4;
                        int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT;
 
                        bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages);
                }
-               return err;
+               return NULL;
        }
 
-       skb_reserve(skb, BNX2_RX_OFFSET);
        dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size,
                         PCI_DMA_FROMDEVICE);
-
+       skb = build_skb(data);
+       if (!skb) {
+               kfree(data);
+               goto error;
+       }
+       skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET);
        if (hdr_len == 0) {
                skb_put(skb, len);
-               return 0;
+               return skb;
        } else {
                unsigned int i, frag_len, frag_size, pages;
                struct sw_pg *rx_pg;
@@ -3052,7 +3044,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                                        skb_frag_size_sub(frag, tail);
                                        skb->data_len -= tail;
                                }
-                               return 0;
+                               return skb;
                        }
                        rx_pg = &rxr->rx_pg_ring[pg_cons];
 
@@ -3074,7 +3066,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                                rxr->rx_pg_prod = pg_prod;
                                bnx2_reuse_rx_skb_pages(bp, rxr, skb,
                                                        pages - i);
-                               return err;
+                               return NULL;
                        }
 
                        dma_unmap_page(&bp->pdev->dev, mapping_old,
@@ -3091,7 +3083,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                rxr->rx_pg_prod = pg_prod;
                rxr->rx_pg_cons = pg_cons;
        }
-       return 0;
+       return skb;
 }
 
 static inline u16
@@ -3130,19 +3122,17 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                struct sw_bd *rx_buf, *next_rx_buf;
                struct sk_buff *skb;
                dma_addr_t dma_addr;
+               u8 *data;
 
                sw_ring_cons = RX_RING_IDX(sw_cons);
                sw_ring_prod = RX_RING_IDX(sw_prod);
 
                rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
-               skb = rx_buf->skb;
-               prefetchw(skb);
-
-               next_rx_buf =
-                       &rxr->rx_buf_ring[RX_RING_IDX(NEXT_RX_BD(sw_cons))];
-               prefetch(next_rx_buf->desc);
+               data = rx_buf->data;
+               rx_buf->data = NULL;
 
-               rx_buf->skb = NULL;
+               rx_hdr = get_l2_fhdr(data);
+               prefetch(rx_hdr);
 
                dma_addr = dma_unmap_addr(rx_buf, mapping);
 
@@ -3150,7 +3140,10 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                        BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
                        PCI_DMA_FROMDEVICE);
 
-               rx_hdr = rx_buf->desc;
+               next_rx_buf =
+                       &rxr->rx_buf_ring[RX_RING_IDX(NEXT_RX_BD(sw_cons))];
+               prefetch(get_l2_fhdr(next_rx_buf->data));
+
                len = rx_hdr->l2_fhdr_pkt_len;
                status = rx_hdr->l2_fhdr_status;
 
@@ -3169,7 +3162,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                                       L2_FHDR_ERRORS_TOO_SHORT |
                                       L2_FHDR_ERRORS_GIANT_FRAME))) {
 
-                       bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
+                       bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
                                          sw_ring_prod);
                        if (pg_ring_used) {
                                int pages;
@@ -3184,30 +3177,29 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                len -= 4;
 
                if (len <= bp->rx_copy_thresh) {
-                       struct sk_buff *new_skb;
-
-                       new_skb = netdev_alloc_skb(bp->dev, len + 6);
-                       if (new_skb == NULL) {
-                               bnx2_reuse_rx_skb(bp, rxr, skb, sw_ring_cons,
+                       skb = netdev_alloc_skb(bp->dev, len + 6);
+                       if (skb == NULL) {
+                               bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons,
                                                  sw_ring_prod);
                                goto next_rx;
                        }
 
                        /* aligned copy */
-                       skb_copy_from_linear_data_offset(skb,
-                                                        BNX2_RX_OFFSET - 6,
-                                     new_skb->data, len + 6);
-                       skb_reserve(new_skb, 6);
-                       skb_put(new_skb, len);
+                       memcpy(skb->data,
+                              (u8 *)rx_hdr + BNX2_RX_OFFSET - 6,
+                              len + 6);
+                       skb_reserve(skb, 6);
+                       skb_put(skb, len);
 
-                       bnx2_reuse_rx_skb(bp, rxr, skb,
+                       bnx2_reuse_rx_data(bp, rxr, data,
                                sw_ring_cons, sw_ring_prod);
 
-                       skb = new_skb;
-               } else if (unlikely(bnx2_rx_skb(bp, rxr, skb, len, hdr_len,
-                          dma_addr, (sw_ring_cons << 16) | sw_ring_prod)))
-                       goto next_rx;
-
+               } else {
+                       skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr,
+                                         (sw_ring_cons << 16) | sw_ring_prod);
+                       if (!skb)
+                               goto next_rx;
+               }
                if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) &&
                    !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG))
                        __vlan_hwaccel_put_tag(skb, rx_hdr->l2_fhdr_vlan_tag);
@@ -5234,7 +5226,7 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num)
 
        ring_prod = prod = rxr->rx_prod;
        for (i = 0; i < bp->rx_ring_size; i++) {
-               if (bnx2_alloc_rx_skb(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
+               if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) {
                        netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n",
                                    ring_num, i, bp->rx_ring_size);
                        break;
@@ -5329,7 +5321,7 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
        rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8;
 
        rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD +
-               sizeof(struct skb_shared_info);
+               SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 
        bp->rx_copy_thresh = BNX2_RX_COPY_THRESH;
        bp->rx_pg_ring_size = 0;
@@ -5351,8 +5343,9 @@ bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
        }
 
        bp->rx_buf_use_size = rx_size;
-       /* hw alignment */
-       bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
+       /* hw alignment + build_skb() overhead*/
+       bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) +
+               NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
        bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET;
        bp->rx_ring_size = size;
        bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS);
@@ -5418,9 +5411,9 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
 
                for (j = 0; j < bp->rx_max_ring_idx; j++) {
                        struct sw_bd *rx_buf = &rxr->rx_buf_ring[j];
-                       struct sk_buff *skb = rx_buf->skb;
+                       u8 *data = rx_buf->data;
 
-                       if (skb == NULL)
+                       if (data == NULL)
                                continue;
 
                        dma_unmap_single(&bp->pdev->dev,
@@ -5428,9 +5421,9 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
                                         bp->rx_buf_use_size,
                                         PCI_DMA_FROMDEVICE);
 
-                       rx_buf->skb = NULL;
+                       rx_buf->data = NULL;
 
-                       dev_kfree_skb(skb);
+                       kfree(data);
                }
                for (j = 0; j < bp->rx_max_pg_ring_idx; j++)
                        bnx2_free_rx_page(bp, rxr, j);
@@ -5736,7 +5729,8 @@ static int
 bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
 {
        unsigned int pkt_size, num_pkts, i;
-       struct sk_buff *skb, *rx_skb;
+       struct sk_buff *skb;
+       u8 *data;
        unsigned char *packet;
        u16 rx_start_idx, rx_idx;
        dma_addr_t map;
@@ -5828,14 +5822,14 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        }
 
        rx_buf = &rxr->rx_buf_ring[rx_start_idx];
-       rx_skb = rx_buf->skb;
+       data = rx_buf->data;
 
-       rx_hdr = rx_buf->desc;
-       skb_reserve(rx_skb, BNX2_RX_OFFSET);
+       rx_hdr = get_l2_fhdr(data);
+       data = (u8 *)rx_hdr + BNX2_RX_OFFSET;
 
        dma_sync_single_for_cpu(&bp->pdev->dev,
                dma_unmap_addr(rx_buf, mapping),
-               bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+               bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
 
        if (rx_hdr->l2_fhdr_status &
                (L2_FHDR_ERRORS_BAD_CRC |
@@ -5852,7 +5846,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        }
 
        for (i = 14; i < pkt_size; i++) {
-               if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
+               if (*(data + i) != (unsigned char) (i & 0xff)) {
                        goto loopback_test_done;
                }
        }
@@ -6873,10 +6867,10 @@ bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-       strcpy(info->bus_info, pci_name(bp->pdev));
-       strcpy(info->fw_version, bp->fw_version);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
+       strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version));
 }
 
 #define BNX2_REGDUMP_LEN               (32 * 1024)
@@ -7571,8 +7565,8 @@ bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
        return 0;
 }
 
-static u32
-bnx2_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t
+bnx2_fix_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
@@ -7583,7 +7577,7 @@ bnx2_fix_features(struct net_device *dev, u32 features)
 }
 
 static int
-bnx2_set_features(struct net_device *dev, u32 features)
+bnx2_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2 *bp = netdev_priv(dev);
 
index 99d31a7d6aaab6d04a64c529c55700a9d74562e9..1db2d51ba3f16cd017a7d01a9bd95f37c8011c95 100644 (file)
@@ -6563,12 +6563,25 @@ struct l2_fhdr {
 #define MB_TX_CID_ADDR MB_GET_CID_ADDR(TX_CID)
 #define MB_RX_CID_ADDR MB_GET_CID_ADDR(RX_CID)
 
+/*
+ * This driver uses new build_skb() API :
+ * RX ring buffer contains pointer to kmalloc() data only,
+ * skb are built only after Hardware filled the frame.
+ */
 struct sw_bd {
-       struct sk_buff          *skb;
-       struct l2_fhdr          *desc;
+       u8                      *data;
        DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
+/* Its faster to compute this from data than storing it in sw_bd
+ * (less cache misses)
+ */
+static inline struct l2_fhdr *get_l2_fhdr(u8 *data)
+{
+       return (struct l2_fhdr *)(PTR_ALIGN(data, BNX2_RX_ALIGN) + NET_SKB_PAD);
+}
+
+
 struct sw_pg {
        struct page             *page;
        DEFINE_DMA_UNMAP_ADDR(mapping);
index aec7212ac9835a4aba89b24641238a0e2d08448e..0f7b7a463eba0d4e6e548ff0b9fe1f2a81bd39cf 100644 (file)
@@ -23,8 +23,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.70.30-0"
-#define DRV_MODULE_RELDATE      "2011/10/25"
+#define DRV_MODULE_VERSION      "1.70.35-0"
+#define DRV_MODULE_RELDATE      "2011/11/10"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
@@ -293,8 +293,13 @@ enum {
 #define FCOE_TXQ_IDX(bp)       (MAX_ETH_TXQ_IDX(bp))
 
 /* fast path */
+/*
+ * This driver uses new build_skb() API :
+ * RX ring buffer contains pointer to kmalloc() data only,
+ * skb are built only after Hardware filled the frame.
+ */
 struct sw_rx_bd {
-       struct sk_buff  *skb;
+       u8              *data;
        DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
@@ -411,8 +416,7 @@ union db_prod {
 
 
 /* Number of u64 elements in SGE mask array */
-#define RX_SGE_MASK_LEN                        ((NUM_RX_SGE_PAGES * RX_SGE_CNT) / \
-                                        BIT_VEC64_ELEM_SZ)
+#define RX_SGE_MASK_LEN                        (NUM_RX_SGE / BIT_VEC64_ELEM_SZ)
 #define RX_SGE_MASK_LEN_MASK           (RX_SGE_MASK_LEN - 1)
 #define NEXT_SGE_MASK_ELEM(el)         (((el) + 1) & RX_SGE_MASK_LEN_MASK)
 
@@ -425,8 +429,8 @@ union host_hc_status_block {
 
 struct bnx2x_agg_info {
        /*
-        * First aggregation buffer is an skb, the following - are pages.
-        * We will preallocate the skbs for each aggregation when
+        * First aggregation buffer is a data buffer, the following - are pages.
+        * We will preallocate the data buffer for each aggregation when
         * we open the interface and will replace the BD at the consumer
         * with this one when we receive the TPA_START CQE in order to
         * keep the Rx BD ring consistent.
@@ -440,6 +444,7 @@ struct bnx2x_agg_info {
        u16                     parsing_flags;
        u16                     vlan_tag;
        u16                     len_on_bd;
+       u32                     rxhash;
 };
 
 #define Q_STATS_OFFSET32(stat_name) \
@@ -507,6 +512,7 @@ struct bnx2x_fastpath {
        __le16                  fp_hc_idx;
 
        u8                      index;          /* number in fp array */
+       u8                      rx_queue;       /* index for skb_record */
        u8                      cl_id;          /* eth client id */
        u8                      cl_qzone_id;
        u8                      fw_sb_id;       /* status block number in FW */
@@ -1141,6 +1147,7 @@ struct bnx2x_fw_stats_data {
 enum {
        BNX2X_SP_RTNL_SETUP_TC,
        BNX2X_SP_RTNL_TX_TIMEOUT,
+       BNX2X_SP_RTNL_FAN_FAILURE,
 };
 
 
@@ -1186,10 +1193,20 @@ struct bnx2x {
 #define ETH_MAX_JUMBO_PACKET_SIZE      9600
 
        /* Max supported alignment is 256 (8 shift) */
-#define BNX2X_RX_ALIGN_SHIFT           ((L1_CACHE_SHIFT < 8) ? \
-                                        L1_CACHE_SHIFT : 8)
-       /* FW use 2 Cache lines Alignment for start packet and size  */
-#define BNX2X_FW_RX_ALIGN              (2 << BNX2X_RX_ALIGN_SHIFT)
+#define BNX2X_RX_ALIGN_SHIFT           min(8, L1_CACHE_SHIFT)
+
+       /* FW uses 2 Cache lines Alignment for start packet and size
+        *
+        * We assume skb_build() uses sizeof(struct skb_shared_info) bytes
+        * at the end of skb->data, to avoid wasting a full cache line.
+        * This reduces memory use (skb->truesize).
+        */
+#define BNX2X_FW_RX_ALIGN_START        (1UL << BNX2X_RX_ALIGN_SHIFT)
+
+#define BNX2X_FW_RX_ALIGN_END                                  \
+       max(1UL << BNX2X_RX_ALIGN_SHIFT,                        \
+           SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
 #define BNX2X_PXP_DRAM_ALIGN           (BNX2X_RX_ALIGN_SHIFT - 5)
 
        struct host_sp_status_block *def_status_blk;
@@ -1984,13 +2001,6 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define HW_PRTY_ASSERT_SET_4 (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR | \
                              AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)
 
-#define RSS_FLAGS(bp) \
-               (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \
-                TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \
-                TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \
-                TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \
-                (bp->multi_mode << \
-                 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT))
 #define MULTI_MASK                     0x7f
 
 
@@ -2055,6 +2065,8 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_VPD_LEN                  128
 #define VENDOR_ID_LEN                  4
 
+int bnx2x_close(struct net_device *dev);
+
 /* Congestion management fairness mode */
 #define CMNG_FNS_NONE          0
 #define CMNG_FNS_MINMAX                1
index 580b44edb066eafe779b8d55953a5d70cf8546f8..8336c784db499f2892449a38a978b1b918d0de1e 100644 (file)
@@ -79,19 +79,21 @@ static inline void bnx2x_bz_fp(struct bnx2x *bp, int index)
  * @to:                destination FP index
  *
  * Makes sure the contents of the bp->fp[to].napi is kept
- * intact.
+ * intact. This is done by first copying the napi struct from
+ * the target to the source, and then mem copying the entire
+ * source onto the target
  */
 static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
 {
        struct bnx2x_fastpath *from_fp = &bp->fp[from];
        struct bnx2x_fastpath *to_fp = &bp->fp[to];
-       struct napi_struct orig_napi = to_fp->napi;
+
+       /* Copy the NAPI object as it has been already initialized */
+       from_fp->napi = to_fp->napi;
+
        /* Move bnx2x_fastpath contents */
        memcpy(to_fp, from_fp, sizeof(*to_fp));
        to_fp->index = to;
-
-       /* Restore the NAPI object as it has been already initialized */
-       to_fp->napi = orig_napi;
 }
 
 int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -292,8 +294,21 @@ static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
           fp->last_max_sge, fp->rx_sge_prod);
 }
 
+/* Set Toeplitz hash value in the skb using the value from the
+ * CQE (calculated by HW).
+ */
+static u32 bnx2x_get_rxhash(const struct bnx2x *bp,
+                           const struct eth_fast_path_rx_cqe *cqe)
+{
+       /* Set Toeplitz hash from CQE */
+       if ((bp->dev->features & NETIF_F_RXHASH) &&
+           (cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
+               return le32_to_cpu(cqe->rss_hash_result);
+       return 0;
+}
+
 static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
-                           struct sk_buff *skb, u16 cons, u16 prod,
+                           u16 cons, u16 prod,
                            struct eth_fast_path_rx_cqe *cqe)
 {
        struct bnx2x *bp = fp->bp;
@@ -308,9 +323,9 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
        if (tpa_info->tpa_state != BNX2X_TPA_STOP)
                BNX2X_ERR("start of bin not in stop [%d]\n", queue);
 
-       /* Try to map an empty skb from the aggregation info  */
+       /* Try to map an empty data buffer from the aggregation info  */
        mapping = dma_map_single(&bp->pdev->dev,
-                                first_buf->skb->data,
+                                first_buf->data + NET_SKB_PAD,
                                 fp->rx_buf_size, DMA_FROM_DEVICE);
        /*
         *  ...if it fails - move the skb from the consumer to the producer
@@ -320,15 +335,15 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                /* Move the BD from the consumer to the producer */
-               bnx2x_reuse_rx_skb(fp, cons, prod);
+               bnx2x_reuse_rx_data(fp, cons, prod);
                tpa_info->tpa_state = BNX2X_TPA_ERROR;
                return;
        }
 
-       /* move empty skb from pool to prod */
-       prod_rx_buf->skb = first_buf->skb;
+       /* move empty data from pool to prod */
+       prod_rx_buf->data = first_buf->data;
        dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
-       /* point prod_bd to new skb */
+       /* point prod_bd to new data */
        prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
 
@@ -342,6 +357,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
        tpa_info->tpa_state = BNX2X_TPA_START;
        tpa_info->len_on_bd = le16_to_cpu(cqe->len_on_bd);
        tpa_info->placement_offset = cqe->placement_offset;
+       tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe);
 
 #ifdef BNX2X_STOP_ON_ERROR
        fp->tpa_queue_used |= (1 << queue);
@@ -469,11 +485,12 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 {
        struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue];
        struct sw_rx_bd *rx_buf = &tpa_info->first_buf;
-       u8 pad = tpa_info->placement_offset;
+       u32 pad = tpa_info->placement_offset;
        u16 len = tpa_info->len_on_bd;
-       struct sk_buff *skb = rx_buf->skb;
+       struct sk_buff *skb = NULL;
+       u8 *data = rx_buf->data;
        /* alloc new skb */
-       struct sk_buff *new_skb;
+       u8 *new_data;
        u8 old_tpa_state = tpa_info->tpa_state;
 
        tpa_info->tpa_state = BNX2X_TPA_STOP;
@@ -484,18 +501,18 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        if (old_tpa_state == BNX2X_TPA_ERROR)
                goto drop;
 
-       /* Try to allocate the new skb */
-       new_skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size);
+       /* Try to allocate the new data */
+       new_data = kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
 
        /* Unmap skb in the pool anyway, as we are going to change
           pool entry status to BNX2X_TPA_STOP even if new skb allocation
           fails. */
        dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
                         fp->rx_buf_size, DMA_FROM_DEVICE);
+       if (likely(new_data))
+               skb = build_skb(data);
 
-       if (likely(new_skb)) {
-               prefetch(skb);
-               prefetch(((char *)(skb)) + L1_CACHE_BYTES);
+       if (likely(skb)) {
 
 #ifdef BNX2X_STOP_ON_ERROR
                if (pad + len > fp->rx_buf_size) {
@@ -507,8 +524,9 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 #endif
 
-               skb_reserve(skb, pad);
+               skb_reserve(skb, pad + NET_SKB_PAD);
                skb_put(skb, len);
+               skb->rxhash = tpa_info->rxhash;
 
                skb->protocol = eth_type_trans(skb, bp->dev);
                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -524,8 +542,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
 
-               /* put new skb in bin */
-               rx_buf->skb = new_skb;
+               /* put new data in bin */
+               rx_buf->data = new_data;
 
                return;
        }
@@ -537,19 +555,6 @@ drop:
        fp->eth_q_stats.rx_skb_alloc_failed++;
 }
 
-/* Set Toeplitz hash value in the skb using the value from the
- * CQE (calculated by HW).
- */
-static inline void bnx2x_set_skb_rxhash(struct bnx2x *bp, union eth_rx_cqe *cqe,
-                                       struct sk_buff *skb)
-{
-       /* Set Toeplitz hash from CQE */
-       if ((bp->dev->features & NETIF_F_RXHASH) &&
-           (cqe->fast_path_cqe.status_flags &
-            ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
-               skb->rxhash =
-               le32_to_cpu(cqe->fast_path_cqe.rss_hash_result);
-}
 
 int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 {
@@ -592,6 +597,7 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                u8 cqe_fp_flags;
                enum eth_rx_cqe_type cqe_fp_type;
                u16 len, pad;
+               u8 *data;
 
 #ifdef BNX2X_STOP_ON_ERROR
                if (unlikely(bp->panic))
@@ -602,13 +608,6 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                bd_prod = RX_BD(bd_prod);
                bd_cons = RX_BD(bd_cons);
 
-               /* Prefetch the page containing the BD descriptor
-                  at producer's index. It will be needed when new skb is
-                  allocated */
-               prefetch((void *)(PAGE_ALIGN((unsigned long)
-                                            (&fp->rx_desc_ring[bd_prod])) -
-                                 PAGE_SIZE + 1));
-
                cqe = &fp->rx_comp_ring[comp_ring_cons];
                cqe_fp = &cqe->fast_path_cqe;
                cqe_fp_flags = cqe_fp->type_error_flags;
@@ -624,125 +623,110 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                if (unlikely(CQE_TYPE_SLOW(cqe_fp_type))) {
                        bnx2x_sp_event(fp, cqe);
                        goto next_cqe;
+               }
+               rx_buf = &fp->rx_buf_ring[bd_cons];
+               data = rx_buf->data;
 
-               /* this is an rx packet */
-               } else {
-                       rx_buf = &fp->rx_buf_ring[bd_cons];
-                       skb = rx_buf->skb;
-                       prefetch(skb);
-
-                       if (!CQE_TYPE_FAST(cqe_fp_type)) {
+               if (!CQE_TYPE_FAST(cqe_fp_type)) {
 #ifdef BNX2X_STOP_ON_ERROR
-                               /* sanity check */
-                               if (fp->disable_tpa &&
-                                   (CQE_TYPE_START(cqe_fp_type) ||
-                                    CQE_TYPE_STOP(cqe_fp_type)))
-                                       BNX2X_ERR("START/STOP packet while "
-                                                 "disable_tpa type %x\n",
-                                                 CQE_TYPE(cqe_fp_type));
+                       /* sanity check */
+                       if (fp->disable_tpa &&
+                           (CQE_TYPE_START(cqe_fp_type) ||
+                            CQE_TYPE_STOP(cqe_fp_type)))
+                               BNX2X_ERR("START/STOP packet while "
+                                         "disable_tpa type %x\n",
+                                         CQE_TYPE(cqe_fp_type));
 #endif
 
-                               if (CQE_TYPE_START(cqe_fp_type)) {
-                                       u16 queue = cqe_fp->queue_index;
-                                       DP(NETIF_MSG_RX_STATUS,
-                                          "calling tpa_start on queue %d\n",
-                                          queue);
-
-                                       bnx2x_tpa_start(fp, queue, skb,
-                                                       bd_cons, bd_prod,
-                                                       cqe_fp);
-
-                                       /* Set Toeplitz hash for LRO skb */
-                                       bnx2x_set_skb_rxhash(bp, cqe, skb);
+                       if (CQE_TYPE_START(cqe_fp_type)) {
+                               u16 queue = cqe_fp->queue_index;
+                               DP(NETIF_MSG_RX_STATUS,
+                                  "calling tpa_start on queue %d\n",
+                                  queue);
 
-                                       goto next_rx;
-
-                               } else {
-                                       u16 queue =
-                                               cqe->end_agg_cqe.queue_index;
-                                       DP(NETIF_MSG_RX_STATUS,
-                                          "calling tpa_stop on queue %d\n",
-                                          queue);
-
-                                       bnx2x_tpa_stop(bp, fp, queue,
-                                                      &cqe->end_agg_cqe,
-                                                      comp_ring_cons);
+                               bnx2x_tpa_start(fp, queue,
+                                               bd_cons, bd_prod,
+                                               cqe_fp);
+                               goto next_rx;
+                       } else {
+                               u16 queue =
+                                       cqe->end_agg_cqe.queue_index;
+                               DP(NETIF_MSG_RX_STATUS,
+                                  "calling tpa_stop on queue %d\n",
+                                  queue);
+
+                               bnx2x_tpa_stop(bp, fp, queue,
+                                              &cqe->end_agg_cqe,
+                                              comp_ring_cons);
 #ifdef BNX2X_STOP_ON_ERROR
-                                       if (bp->panic)
-                                               return 0;
+                               if (bp->panic)
+                                       return 0;
 #endif
 
-                                       bnx2x_update_sge_prod(fp, cqe_fp);
-                                       goto next_cqe;
-                               }
+                               bnx2x_update_sge_prod(fp, cqe_fp);
+                               goto next_cqe;
                        }
-                       /* non TPA */
-                       len = le16_to_cpu(cqe_fp->pkt_len);
-                       pad = cqe_fp->placement_offset;
-                       dma_sync_single_for_cpu(&bp->pdev->dev,
+               }
+               /* non TPA */
+               len = le16_to_cpu(cqe_fp->pkt_len);
+               pad = cqe_fp->placement_offset;
+               dma_sync_single_for_cpu(&bp->pdev->dev,
                                        dma_unmap_addr(rx_buf, mapping),
-                                                      pad + RX_COPY_THRESH,
-                                                      DMA_FROM_DEVICE);
-                       prefetch(((char *)(skb)) + L1_CACHE_BYTES);
+                                       pad + RX_COPY_THRESH,
+                                       DMA_FROM_DEVICE);
+               pad += NET_SKB_PAD;
+               prefetch(data + pad); /* speedup eth_type_trans() */
+               /* is this an error packet? */
+               if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
+                       DP(NETIF_MSG_RX_ERR,
+                          "ERROR  flags %x  rx packet %u\n",
+                          cqe_fp_flags, sw_comp_cons);
+                       fp->eth_q_stats.rx_err_discard_pkt++;
+                       goto reuse_rx;
+               }
 
-                       /* is this an error packet? */
-                       if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) {
+               /* Since we don't have a jumbo ring
+                * copy small packets if mtu > 1500
+                */
+               if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
+                   (len <= RX_COPY_THRESH)) {
+                       skb = netdev_alloc_skb_ip_align(bp->dev, len);
+                       if (skb == NULL) {
                                DP(NETIF_MSG_RX_ERR,
-                                  "ERROR  flags %x  rx packet %u\n",
-                                  cqe_fp_flags, sw_comp_cons);
-                               fp->eth_q_stats.rx_err_discard_pkt++;
+                                  "ERROR  packet dropped because of alloc failure\n");
+                               fp->eth_q_stats.rx_skb_alloc_failed++;
                                goto reuse_rx;
                        }
-
-                       /* Since we don't have a jumbo ring
-                        * copy small packets if mtu > 1500
-                        */
-                       if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) &&
-                           (len <= RX_COPY_THRESH)) {
-                               struct sk_buff *new_skb;
-
-                               new_skb = netdev_alloc_skb(bp->dev, len + pad);
-                               if (new_skb == NULL) {
-                                       DP(NETIF_MSG_RX_ERR,
-                                          "ERROR  packet dropped "
-                                          "because of alloc failure\n");
-                                       fp->eth_q_stats.rx_skb_alloc_failed++;
-                                       goto reuse_rx;
-                               }
-
-                               /* aligned copy */
-                               skb_copy_from_linear_data_offset(skb, pad,
-                                                   new_skb->data + pad, len);
-                               skb_reserve(new_skb, pad);
-                               skb_put(new_skb, len);
-
-                               bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod);
-
-                               skb = new_skb;
-
-                       } else
-                       if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
+                       memcpy(skb->data, data + pad, len);
+                       bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
+               } else {
+                       if (likely(bnx2x_alloc_rx_data(bp, fp, bd_prod) == 0)) {
                                dma_unmap_single(&bp->pdev->dev,
-                                       dma_unmap_addr(rx_buf, mapping),
+                                                dma_unmap_addr(rx_buf, mapping),
                                                 fp->rx_buf_size,
                                                 DMA_FROM_DEVICE);
+                               skb = build_skb(data);
+                               if (unlikely(!skb)) {
+                                       kfree(data);
+                                       fp->eth_q_stats.rx_skb_alloc_failed++;
+                                       goto next_rx;
+                               }
                                skb_reserve(skb, pad);
-                               skb_put(skb, len);
-
                        } else {
                                DP(NETIF_MSG_RX_ERR,
                                   "ERROR  packet dropped because "
                                   "of alloc failure\n");
                                fp->eth_q_stats.rx_skb_alloc_failed++;
 reuse_rx:
-                               bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod);
+                               bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
                                goto next_rx;
                        }
 
+                       skb_put(skb, len);
                        skb->protocol = eth_type_trans(skb, bp->dev);
 
                        /* Set Toeplitz hash for a none-LRO skb */
-                       bnx2x_set_skb_rxhash(bp, cqe, skb);
+                       skb->rxhash = bnx2x_get_rxhash(bp, cqe_fp);
 
                        skb_checksum_none_assert(skb);
 
@@ -755,7 +739,7 @@ reuse_rx:
                        }
                }
 
-               skb_record_rx_queue(skb, fp->index);
+               skb_record_rx_queue(skb, fp->rx_queue);
 
                if (le16_to_cpu(cqe_fp->pars_flags.flags) &
                    PARSING_FLAGS_VLAN)
@@ -765,7 +749,7 @@ reuse_rx:
 
 
 next_rx:
-               rx_buf->skb = NULL;
+               rx_buf->data = NULL;
 
                bd_cons = NEXT_RX_IDX(bd_cons);
                bd_prod = NEXT_RX_IDX(bd_prod);
@@ -1011,9 +995,9 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                                struct sw_rx_bd *first_buf =
                                        &tpa_info->first_buf;
 
-                               first_buf->skb = netdev_alloc_skb(bp->dev,
-                                                      fp->rx_buf_size);
-                               if (!first_buf->skb) {
+                               first_buf->data = kmalloc(fp->rx_buf_size + NET_SKB_PAD,
+                                                         GFP_ATOMIC);
+                               if (!first_buf->data) {
                                        BNX2X_ERR("Failed to allocate TPA "
                                                  "skb pool for queue[%d] - "
                                                  "disabling TPA on this "
@@ -1094,13 +1078,11 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
                for_each_cos_in_tx_queue(fp, cos) {
                        struct bnx2x_fp_txdata *txdata = &fp->txdata[cos];
 
-                       u16 bd_cons = txdata->tx_bd_cons;
                        u16 sw_prod = txdata->tx_pkt_prod;
                        u16 sw_cons = txdata->tx_pkt_cons;
 
                        while (sw_cons != sw_prod) {
-                               bd_cons = bnx2x_free_tx_pkt(bp, txdata,
-                                                           TX_BD(sw_cons));
+                               bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons));
                                sw_cons++;
                        }
                }
@@ -1118,16 +1100,16 @@ static void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp)
 
        for (i = 0; i < NUM_RX_BD; i++) {
                struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i];
-               struct sk_buff *skb = rx_buf->skb;
+               u8 *data = rx_buf->data;
 
-               if (skb == NULL)
+               if (data == NULL)
                        continue;
                dma_unmap_single(&bp->pdev->dev,
                                 dma_unmap_addr(rx_buf, mapping),
                                 fp->rx_buf_size, DMA_FROM_DEVICE);
 
-               rx_buf->skb = NULL;
-               dev_kfree_skb(skb);
+               rx_buf->data = NULL;
+               kfree(data);
        }
 }
 
@@ -1509,6 +1491,7 @@ static inline void bnx2x_set_rx_buf_size(struct bnx2x *bp)
 
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
+               u32 mtu;
 
                /* Always use a mini-jumbo MTU for the FCoE L2 ring */
                if (IS_FCOE_IDX(i))
@@ -1518,13 +1501,15 @@ static inline void bnx2x_set_rx_buf_size(struct bnx2x *bp)
                         * IP_HEADER_ALIGNMENT_PADDING to prevent a buffer
                         * overrun attack.
                         */
-                       fp->rx_buf_size =
-                               BNX2X_FCOE_MINI_JUMBO_MTU + ETH_OVREHEAD +
-                               BNX2X_FW_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING;
+                       mtu = BNX2X_FCOE_MINI_JUMBO_MTU;
                else
-                       fp->rx_buf_size =
-                               bp->dev->mtu + ETH_OVREHEAD +
-                               BNX2X_FW_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING;
+                       mtu = bp->dev->mtu;
+               fp->rx_buf_size = BNX2X_FW_RX_ALIGN_START +
+                                 IP_HEADER_ALIGNMENT_PADDING +
+                                 ETH_OVREHEAD +
+                                 mtu +
+                                 BNX2X_FW_RX_ALIGN_END;
+               /* Note : rx_buf_size doesnt take into account NET_SKB_PAD */
        }
 }
 
@@ -1929,13 +1914,17 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
                break;
        }
 
-       if (!bp->port.pmf)
+       if (bp->port.pmf)
+               bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0);
+       else
                bnx2x__link_status_update(bp);
 
        /* start the timer */
        mod_timer(&bp->timer, jiffies + bp->current_interval);
 
 #ifdef BCM_CNIC
+       /* re-read iscsi info */
+       bnx2x_get_iscsi_info(bp);
        bnx2x_setup_cnic_irq_info(bp);
        if (bp->state == BNX2X_STATE_OPEN)
                bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
@@ -3409,7 +3398,8 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
        return bnx2x_reload_if_running(dev);
 }
 
-u32 bnx2x_fix_features(struct net_device *dev, u32 features)
+netdev_features_t bnx2x_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -3420,7 +3410,7 @@ u32 bnx2x_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-int bnx2x_set_features(struct net_device *dev, u32 features)
+int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct bnx2x *bp = netdev_priv(dev);
        u32 flags = bp->flags;
index 283d663da18022b848b04b976186140d436eac78..80c5ed08e419c51b72f2818e07f980adfa497a62 100644 (file)
@@ -533,8 +533,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
  */
 int bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type);
 #endif
-u32 bnx2x_fix_features(struct net_device *dev, u32 features);
-int bnx2x_set_features(struct net_device *dev, u32 features);
+netdev_features_t bnx2x_fix_features(struct net_device *dev,
+       netdev_features_t features);
+int bnx2x_set_features(struct net_device *dev, netdev_features_t features);
 
 /**
  * bnx2x_tx_timeout - tx timeout netdev callback
@@ -874,8 +875,7 @@ static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
 static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp)
 {
        /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */
-       memset(fp->sge_mask, 0xff,
-              (NUM_RX_SGE >> BIT_VEC64_ELEM_SHIFT)*sizeof(u64));
+       memset(fp->sge_mask, 0xff, sizeof(fp->sge_mask));
 
        /* Clear the two last indices in the page to 1:
           these are the indices that correspond to the "next" element,
@@ -911,26 +911,27 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
        return 0;
 }
 
-static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
-                                    struct bnx2x_fastpath *fp, u16 index)
+static inline int bnx2x_alloc_rx_data(struct bnx2x *bp,
+                                     struct bnx2x_fastpath *fp, u16 index)
 {
-       struct sk_buff *skb;
+       u8 *data;
        struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
        struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
        dma_addr_t mapping;
 
-       skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size);
-       if (unlikely(skb == NULL))
+       data = kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
+       if (unlikely(data == NULL))
                return -ENOMEM;
 
-       mapping = dma_map_single(&bp->pdev->dev, skb->data, fp->rx_buf_size,
+       mapping = dma_map_single(&bp->pdev->dev, data + NET_SKB_PAD,
+                                fp->rx_buf_size,
                                 DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
-               dev_kfree_skb_any(skb);
+               kfree(data);
                return -ENOMEM;
        }
 
-       rx_buf->skb = skb;
+       rx_buf->data = data;
        dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
@@ -939,12 +940,12 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
        return 0;
 }
 
-/* note that we are not allocating a new skb,
+/* note that we are not allocating a new buffer,
  * we are just moving one from cons to prod
  * we are not creating a new mapping,
  * so there is no need to check for dma_mapping_error().
  */
-static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
+static inline void bnx2x_reuse_rx_data(struct bnx2x_fastpath *fp,
                                      u16 cons, u16 prod)
 {
        struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons];
@@ -954,7 +955,7 @@ static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
 
        dma_unmap_addr_set(prod_rx_buf, mapping,
                           dma_unmap_addr(cons_rx_buf, mapping));
-       prod_rx_buf->skb = cons_rx_buf->skb;
+       prod_rx_buf->data = cons_rx_buf->data;
        *prod_bd = *cons_bd;
 }
 
@@ -1030,9 +1031,9 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
        for (i = 0; i < last; i++) {
                struct bnx2x_agg_info *tpa_info = &fp->tpa_info[i];
                struct sw_rx_bd *first_buf = &tpa_info->first_buf;
-               struct sk_buff *skb = first_buf->skb;
+               u8 *data = first_buf->data;
 
-               if (skb == NULL) {
+               if (data == NULL) {
                        DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i);
                        continue;
                }
@@ -1040,8 +1041,8 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
                        dma_unmap_single(&bp->pdev->dev,
                                         dma_unmap_addr(first_buf, mapping),
                                         fp->rx_buf_size, DMA_FROM_DEVICE);
-               dev_kfree_skb(skb);
-               first_buf->skb = NULL;
+               kfree(data);
+               first_buf->data = NULL;
        }
 }
 
@@ -1149,7 +1150,7 @@ static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
         * fp->eth_q_stats.rx_skb_alloc_failed = 0
         */
        for (i = 0; i < rx_ring_size; i++) {
-               if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+               if (bnx2x_alloc_rx_data(bp, fp, ring_prod) < 0) {
                        fp->eth_q_stats.rx_skb_alloc_failed++;
                        continue;
                }
@@ -1318,6 +1319,7 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
        struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
        unsigned long q_type = 0;
 
+       bnx2x_fcoe(bp, rx_queue) = BNX2X_NUM_ETH_QUEUES(bp);
        bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp,
                                                     BNX2X_FCOE_ETH_CL_ID_IDX);
        /** Current BNX2X_FCOE_ETH_CID deffinition implies not more than
@@ -1488,4 +1490,68 @@ static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg)
        return max_cfg;
 }
 
+#ifdef BCM_CNIC
+/**
+ * bnx2x_get_iscsi_info - update iSCSI params according to licensing info.
+ *
+ * @bp:                driver handle
+ *
+ */
+void bnx2x_get_iscsi_info(struct bnx2x *bp);
+#endif
+
+/* returns func by VN for current port */
+static inline int func_by_vn(struct bnx2x *bp, int vn)
+{
+       return 2 * vn + BP_PORT(bp);
+}
+
+/**
+ * bnx2x_link_sync_notify - send notification to other functions.
+ *
+ * @bp:                driver handle
+ *
+ */
+static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
+{
+       int func;
+       int vn;
+
+       /* Set the attention towards other drivers on the same port */
+       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
+               if (vn == BP_VN(bp))
+                       continue;
+
+               func = func_by_vn(bp, vn);
+               REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
+                      (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
+       }
+}
+
+/**
+ * bnx2x_update_drv_flags - update flags in shmem
+ *
+ * @bp:                driver handle
+ * @flags:     flags to update
+ * @set:       set or clear
+ *
+ */
+static inline void bnx2x_update_drv_flags(struct bnx2x *bp, u32 flags, u32 set)
+{
+       if (SHMEM2_HAS(bp, drv_flags)) {
+               u32 drv_flags;
+               bnx2x_acquire_hw_lock(bp, HW_LOCK_DRV_FLAGS);
+               drv_flags = SHMEM2_RD(bp, drv_flags);
+
+               if (set)
+                       SET_FLAGS(drv_flags, flags);
+               else
+                       RESET_FLAGS(drv_flags, flags);
+
+               SHMEM2_WR(bp, drv_flags, drv_flags);
+               DP(NETIF_MSG_HW, "drv_flags 0x%08x\n", drv_flags);
+               bnx2x_release_hw_lock(bp, HW_LOCK_DRV_FLAGS);
+       }
+}
+
 #endif /* BNX2X_CMN_H */
index 51bd7485ab189f11f3c9b3aa4b7e0c59557a987c..5051cf3deb2090bbeae422b3e588e46b8753788c 100644 (file)
@@ -685,24 +685,6 @@ int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall)
 }
 #endif
 
-static inline void bnx2x_update_drv_flags(struct bnx2x *bp, u32 flags, u32 set)
-{
-       if (SHMEM2_HAS(bp, drv_flags)) {
-               u32 drv_flags;
-               bnx2x_acquire_hw_lock(bp, HW_LOCK_DRV_FLAGS);
-               drv_flags = SHMEM2_RD(bp, drv_flags);
-
-               if (set)
-                       SET_FLAGS(drv_flags, flags);
-               else
-                       RESET_FLAGS(drv_flags, flags);
-
-               SHMEM2_WR(bp, drv_flags, drv_flags);
-               DP(NETIF_MSG_HW, "drv_flags 0x%08x\n", drv_flags);
-               bnx2x_release_hw_lock(bp, HW_LOCK_DRV_FLAGS);
-       }
-}
-
 static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
 {
        u8 prio, cos;
@@ -755,18 +737,26 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
                        /* mark DCBX result for PMF migration */
                        bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 1);
 #ifdef BCM_DCBNL
-                       /**
+                       /*
                         * Add new app tlvs to dcbnl
                         */
                        bnx2x_dcbnl_update_applist(bp, false);
 #endif
-                       bnx2x_dcbx_stop_hw_tx(bp);
-
-                       /* reconfigure the netdevice with the results of the new
+                       /*
+                        * reconfigure the netdevice with the results of the new
                         * dcbx negotiation.
                         */
                        bnx2x_dcbx_update_tc_mapping(bp);
 
+                       /*
+                        * allow other funtions to update their netdevices
+                        * accordingly
+                        */
+                       if (IS_MF(bp))
+                               bnx2x_link_sync_notify(bp);
+
+                       bnx2x_dcbx_stop_hw_tx(bp);
+
                        return;
                }
        case BNX2X_DCBX_STATE_TX_PAUSED:
@@ -775,6 +765,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
 
                bnx2x_dcbx_update_ets_params(bp);
                bnx2x_dcbx_resume_hw_tx(bp);
+
                return;
        case BNX2X_DCBX_STATE_TX_RELEASED:
                DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_RELEASED\n");
@@ -883,7 +874,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
                /*For IEEE admin_recommendation_bw_precentage
                 *For IEEE admin_recommendation_ets_pg */
                af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
                        if (dp->admin_priority_app_table[i].valid) {
                                struct bnx2x_admin_priority_app_table *table =
                                        dp->admin_priority_app_table;
@@ -923,7 +914,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
 
 void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
 {
-       if (!CHIP_IS_E1x(bp) && !CHIP_IS_E3(bp)) {
+       if (!CHIP_IS_E1x(bp)) {
                bp->dcb_state = dcb_on;
                bp->dcbx_enabled = dcbx_enabled;
        } else {
@@ -1863,7 +1854,7 @@ static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
 void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
 {
        /* if we need to syncronize DCBX result from prev PMF
-        * read it from shmem and update bp accordingly
+        * read it from shmem and update bp and netdev accordingly
         */
        if (SHMEM2_HAS(bp, drv_flags) &&
           GET_FLAGS(SHMEM2_RD(bp, drv_flags), DRV_FLAGS_DCB_CONFIGURED)) {
@@ -1875,6 +1866,22 @@ void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
                                          bp->dcbx_error);
                bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat,
                                         bp->dcbx_error);
+#ifdef BCM_DCBNL
+               /*
+                * Add new app tlvs to dcbnl
+                */
+               bnx2x_dcbnl_update_applist(bp, false);
+               /*
+                * Send a notification for the new negotiated parameters
+                */
+               dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0);
+#endif
+               /*
+                * reconfigure the netdevice with the results of the new
+                * dcbx negotiation.
+                */
+               bnx2x_dcbx_update_tc_mapping(bp);
+
        }
 }
 
@@ -2242,7 +2249,7 @@ static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
        int i, ff;
 
        /* iterate over the app entries looking for idtype and idval */
-       for (i = 0, ff = -1; i < 4; i++) {
+       for (i = 0, ff = -1; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
                struct bnx2x_admin_priority_app_table *app_ent =
                        &bp->dcbx_config_params.admin_priority_app_table[i];
                if (bnx2x_admin_app_is_equal(app_ent, idtype, idval))
@@ -2251,7 +2258,7 @@ static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up)
                if (ff < 0 && !app_ent->valid)
                        ff = i;
        }
-       if (i < 4)
+       if (i < DCBX_CONFIG_MAX_APP_PROTOCOL)
                /* if found overwrite up */
                bp->dcbx_config_params.
                        admin_priority_app_table[i].priority = up;
index 2c6a3bca6f284cb82674fb73da8a41cf04325c39..2ab9254e2d5eff4b7cf9ccb5a02cc38df66a9f06 100644 (file)
@@ -90,6 +90,7 @@ struct bnx2x_admin_priority_app_table {
                u32 app_id;
 };
 
+#define DCBX_CONFIG_MAX_APP_PROTOCOL 4
 struct bnx2x_config_dcbx_params {
        u32 overwrite_settings;
        u32 admin_dcbx_version;
@@ -109,7 +110,8 @@ struct bnx2x_config_dcbx_params {
        u32 admin_recommendation_bw_precentage[8];
        u32 admin_recommendation_ets_pg[8];
        u32 admin_pfc_bitmap;
-       struct bnx2x_admin_priority_app_table admin_priority_app_table[4];
+       struct bnx2x_admin_priority_app_table
+               admin_priority_app_table[DCBX_CONFIG_MAX_APP_PROTOCOL];
        u32 admin_default_priority;
 };
 
index f0ca8b27a55eea7b96f3984b03aaead457ba3db8..ec318711f483b24b339f1fa7ea87bd098a9a1895 100644 (file)
@@ -761,8 +761,8 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
        u8 phy_fw_ver[PHY_FW_VER_LEN];
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
 
        phy_fw_ver[0] = '\0';
        if (bp->port.pmf) {
@@ -773,14 +773,14 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
                bnx2x_release_phy_lock(bp);
        }
 
-       strncpy(info->fw_version, bp->fw_ver, 32);
+       strlcpy(info->fw_version, bp->fw_ver, sizeof(info->fw_version));
        snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
                 "bc %d.%d.%d%s%s",
                 (bp->common.bc_ver & 0xff0000) >> 16,
                 (bp->common.bc_ver & 0xff00) >> 8,
                 (bp->common.bc_ver & 0xff),
                 ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
-       strcpy(info->bus_info, pci_name(bp->pdev));
+       strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
        info->n_stats = BNX2X_NUM_STATS;
        info->testinfo_len = BNX2X_NUM_TESTS;
        info->eedump_len = bp->common.flash_size;
@@ -1740,6 +1740,7 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
        struct sw_rx_bd *rx_buf;
        u16 len;
        int rc = -ENODEV;
+       u8 *data;
 
        /* check the loopback mode */
        switch (loopback_mode) {
@@ -1865,10 +1866,9 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode)
        dma_sync_single_for_cpu(&bp->pdev->dev,
                                   dma_unmap_addr(rx_buf, mapping),
                                   fp_rx->rx_buf_size, DMA_FROM_DEVICE);
-       skb = rx_buf->skb;
-       skb_reserve(skb, cqe->fast_path_cqe.placement_offset);
+       data = rx_buf->data + NET_SKB_PAD + cqe->fast_path_cqe.placement_offset;
        for (i = ETH_HLEN; i < pkt_size; i++)
-               if (*(skb->data + i) != (unsigned char) (i & 0xff))
+               if (*(data + i) != (unsigned char) (i & 0xff))
                        goto test_loopback_rx_exit;
 
        rc = 0;
index 2f6361e949f0c836562ff896928cb6709abf883a..83481e20f144f2f3ad0801f78d649a8e909cbe70 100644 (file)
@@ -2318,12 +2318,6 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp)
                                        CMNG_FLAGS_PER_PORT_FAIRNESS_VN;
 }
 
-/* returns func by VN for current port */
-static inline int func_by_vn(struct bnx2x *bp, int vn)
-{
-       return 2 * vn + BP_PORT(bp);
-}
-
 static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn)
 {
        struct rate_shaping_vars_per_vn m_rs_vn;
@@ -2475,22 +2469,6 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
           "rate shaping and fairness are disabled\n");
 }
 
-static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
-{
-       int func;
-       int vn;
-
-       /* Set the attention towards other drivers on the same port */
-       for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) {
-               if (vn == BP_VN(bp))
-                       continue;
-
-               func = func_by_vn(bp, vn);
-               REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 +
-                      (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1);
-       }
-}
-
 /* This function is called upon link interrupt */
 static void bnx2x_link_attn(struct bnx2x *bp)
 {
@@ -2549,6 +2527,9 @@ void bnx2x__link_status_update(struct bnx2x *bp)
        if (bp->state != BNX2X_STATE_OPEN)
                return;
 
+       /* read updated dcb configuration */
+       bnx2x_dcbx_pmf_update(bp);
+
        bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
 
        if (bp->link_vars.link_up)
@@ -2808,8 +2789,8 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
        /* This should be a maximum number of data bytes that may be
         * placed on the BD (not including paddings).
         */
-       rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN -
-               IP_HEADER_ALIGNMENT_PADDING;
+       rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN_START -
+               BNX2X_FW_RX_ALIGN_END - IP_HEADER_ALIGNMENT_PADDING;
 
        rxq_init->cl_qzone_id = fp->cl_qzone_id;
        rxq_init->tpa_agg_sz = tpa_agg_size;
@@ -3318,6 +3299,17 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp)
        netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
               " the driver to shutdown the card to prevent permanent"
               " damage.  Please contact OEM Support for assistance\n");
+
+       /*
+        * Scheudle device reset (unload)
+        * This is due to some boards consuming sufficient power when driver is
+        * up to overheat if fan fails.
+        */
+       smp_mb__before_clear_bit();
+       set_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state);
+       smp_mb__after_clear_bit();
+       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+
 }
 
 static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -5247,7 +5239,7 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
        u8 cos;
        unsigned long q_type = 0;
        u32 cids[BNX2X_MULTI_TX_COS] = { 0 };
-
+       fp->rx_queue = fp_idx;
        fp->cid = fp_idx;
        fp->cl_id = bnx2x_fp_cl_id(fp);
        fp->fw_sb_id = bnx2x_fp_fw_sb_id(fp);
@@ -8522,6 +8514,17 @@ sp_rtnl_not_reset:
        if (test_and_clear_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state))
                bnx2x_setup_tc(bp->dev, bp->dcbx_port_params.ets.num_of_cos);
 
+       /*
+        * in case of fan failure we need to reset id if the "stop on error"
+        * debug flag is set, since we trying to prevent permanent overheating
+        * damage
+        */
+       if (test_and_clear_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state)) {
+               DP(BNX2X_MSG_SP, "fan failure detected. Unloading driver\n");
+               netif_device_detach(bp->dev);
+               bnx2x_close(bp->dev);
+       }
+
 sp_rtnl_exit:
        rtnl_unlock();
 }
@@ -9268,21 +9271,38 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
 }
 
 #ifdef BCM_CNIC
-static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp)
+void bnx2x_get_iscsi_info(struct bnx2x *bp)
 {
        int port = BP_PORT(bp);
-       int func = BP_ABS_FUNC(bp);
 
        u32 max_iscsi_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
                                drv_lic_key[port].max_iscsi_conn);
-       u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
-                               drv_lic_key[port].max_fcoe_conn);
 
-       /* Get the number of maximum allowed iSCSI and FCoE connections */
+       /* Get the number of maximum allowed iSCSI connections */
        bp->cnic_eth_dev.max_iscsi_conn =
                (max_iscsi_conn & BNX2X_MAX_ISCSI_INIT_CONN_MASK) >>
                BNX2X_MAX_ISCSI_INIT_CONN_SHIFT;
 
+       BNX2X_DEV_INFO("max_iscsi_conn 0x%x\n",
+                      bp->cnic_eth_dev.max_iscsi_conn);
+
+       /*
+        * If maximum allowed number of connections is zero -
+        * disable the feature.
+        */
+       if (!bp->cnic_eth_dev.max_iscsi_conn)
+               bp->flags |= NO_ISCSI_FLAG;
+}
+
+static void __devinit bnx2x_get_fcoe_info(struct bnx2x *bp)
+{
+       int port = BP_PORT(bp);
+       int func = BP_ABS_FUNC(bp);
+
+       u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
+                               drv_lic_key[port].max_fcoe_conn);
+
+       /* Get the number of maximum allowed FCoE connections */
        bp->cnic_eth_dev.max_fcoe_conn =
                (max_fcoe_conn & BNX2X_MAX_FCOE_INIT_CONN_MASK) >>
                BNX2X_MAX_FCOE_INIT_CONN_SHIFT;
@@ -9334,20 +9354,26 @@ static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp)
                }
        }
 
-       BNX2X_DEV_INFO("max_iscsi_conn 0x%x max_fcoe_conn 0x%x\n",
-                      bp->cnic_eth_dev.max_iscsi_conn,
-                      bp->cnic_eth_dev.max_fcoe_conn);
+       BNX2X_DEV_INFO("max_fcoe_conn 0x%x\n", bp->cnic_eth_dev.max_fcoe_conn);
 
        /*
         * If maximum allowed number of connections is zero -
         * disable the feature.
         */
-       if (!bp->cnic_eth_dev.max_iscsi_conn)
-               bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG;
-
        if (!bp->cnic_eth_dev.max_fcoe_conn)
                bp->flags |= NO_FCOE_FLAG;
 }
+
+static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp)
+{
+       /*
+        * iSCSI may be dynamically disabled but reading
+        * info here we will decrease memory usage by driver
+        * if the feature is disabled for good
+        */
+       bnx2x_get_iscsi_info(bp);
+       bnx2x_get_fcoe_info(bp);
+}
 #endif
 
 static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
@@ -9965,7 +9991,7 @@ static int bnx2x_open(struct net_device *dev)
 }
 
 /* called with rtnl_lock */
-static int bnx2x_close(struct net_device *dev)
+int bnx2x_close(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -10823,8 +10849,8 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
 
 #ifdef BCM_CNIC
-       /* disable FCOE L2 queue for E1x and E3*/
-       if (CHIP_IS_E1x(bp) || CHIP_IS_E3(bp))
+       /* disable FCOE L2 queue for E1x */
+       if (CHIP_IS_E1x(bp))
                bp->flags |= NO_FCOE_FLAG;
 
 #endif
index 02ac6a771bf99eaa254ee9c66e199dfbe70552df..3034f0e319387d97a78a1932bc55c17e4e5c2627 100644 (file)
@@ -1349,12 +1349,14 @@ void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
        enum bnx2x_stats_state state;
        if (unlikely(bp->panic))
                return;
-       bnx2x_stats_stm[bp->stats_state][event].action(bp);
+
        spin_lock_bh(&bp->stats_lock);
        state = bp->stats_state;
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
        spin_unlock_bh(&bp->stats_lock);
 
+       bnx2x_stats_stm[state][event].action(bp);
+
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
                   state, event, bp->stats_state);
index 0a1d7f279fc8fd83565915a2daaed7bcc3df2621..aa58f9e3f9135cdfffaa17a08472436bab3c60cb 100644 (file)
@@ -163,7 +163,6 @@ enum sbmac_state {
 #define SBMAC_MAX_TXDESCR      256
 #define SBMAC_MAX_RXDESCR      256
 
-#define ETHER_ADDR_LEN         6
 #define ENET_PACKET_SIZE       1518
 /*#define ENET_PACKET_SIZE     9216 */
 
@@ -266,7 +265,7 @@ struct sbmac_softc {
        int                     sbm_pause;      /* current pause setting */
        int                     sbm_link;       /* current link state */
 
-       unsigned char           sbm_hwaddr[ETHER_ADDR_LEN];
+       unsigned char           sbm_hwaddr[ETH_ALEN];
 
        struct sbmacdma         sbm_txdma;      /* only channel 0 for now */
        struct sbmacdma         sbm_rxdma;
index bf4074167d6a321e8f5888c2e2909b0b71e1f62b..024ca1d4d0282f0613bb7e18f3dff05f06544f47 100644 (file)
@@ -3594,15 +3594,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
        u32 val, new_adv;
 
        new_adv = ADVERTISE_CSMA;
-       if (advertise & ADVERTISED_10baseT_Half)
-               new_adv |= ADVERTISE_10HALF;
-       if (advertise & ADVERTISED_10baseT_Full)
-               new_adv |= ADVERTISE_10FULL;
-       if (advertise & ADVERTISED_100baseT_Half)
-               new_adv |= ADVERTISE_100HALF;
-       if (advertise & ADVERTISED_100baseT_Full)
-               new_adv |= ADVERTISE_100FULL;
-
+       new_adv |= ethtool_adv_to_mii_100bt(advertise);
        new_adv |= tg3_advert_flowctrl_1000T(flowctrl);
 
        err = tg3_writephy(tp, MII_ADVERTISE, new_adv);
@@ -3612,11 +3604,7 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
        if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
                goto done;
 
-       new_adv = 0;
-       if (advertise & ADVERTISED_1000baseT_Half)
-               new_adv |= ADVERTISE_1000HALF;
-       if (advertise & ADVERTISED_1000baseT_Full)
-               new_adv |= ADVERTISE_1000FULL;
+       new_adv = ethtool_adv_to_mii_1000T(advertise);
 
        if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
            tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
@@ -3790,14 +3778,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
 {
        u32 adv_reg, all_mask = 0;
 
-       if (mask & ADVERTISED_10baseT_Half)
-               all_mask |= ADVERTISE_10HALF;
-       if (mask & ADVERTISED_10baseT_Full)
-               all_mask |= ADVERTISE_10FULL;
-       if (mask & ADVERTISED_100baseT_Half)
-               all_mask |= ADVERTISE_100HALF;
-       if (mask & ADVERTISED_100baseT_Full)
-               all_mask |= ADVERTISE_100FULL;
+       all_mask = ethtool_adv_to_mii_100bt(mask);
 
        if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
                return 0;
@@ -3808,11 +3789,7 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
        if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) {
                u32 tg3_ctrl;
 
-               all_mask = 0;
-               if (mask & ADVERTISED_1000baseT_Half)
-                       all_mask |= ADVERTISE_1000HALF;
-               if (mask & ADVERTISED_1000baseT_Full)
-                       all_mask |= ADVERTISE_1000FULL;
+               all_mask = ethtool_adv_to_mii_1000T(mask);
 
                if (tg3_readphy(tp, MII_CTRL1000, &tg3_ctrl))
                        return 0;
@@ -4903,23 +4880,19 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
            (tp->phy_flags & TG3_PHYFLG_PARALLEL_DETECT)) {
                /* do nothing, just check for link up at the end */
        } else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
-               u32 adv, new_adv;
+               u32 adv, newadv;
 
                err |= tg3_readphy(tp, MII_ADVERTISE, &adv);
-               new_adv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF |
-                                 ADVERTISE_1000XPAUSE |
-                                 ADVERTISE_1000XPSE_ASYM |
-                                 ADVERTISE_SLCT);
-
-               new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+               newadv = adv & ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF |
+                                ADVERTISE_1000XPAUSE |
+                                ADVERTISE_1000XPSE_ASYM |
+                                ADVERTISE_SLCT);
 
-               if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
-                       new_adv |= ADVERTISE_1000XHALF;
-               if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
-                       new_adv |= ADVERTISE_1000XFULL;
+               newadv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+               newadv |= ethtool_adv_to_mii_1000X(tp->link_config.advertising);
 
-               if ((new_adv != adv) || !(bmcr & BMCR_ANENABLE)) {
-                       tg3_writephy(tp, MII_ADVERTISE, new_adv);
+               if ((newadv != adv) || !(bmcr & BMCR_ANENABLE)) {
+                       tg3_writephy(tp, MII_ADVERTISE, newadv);
                        bmcr |= BMCR_ANENABLE | BMCR_ANRESTART;
                        tg3_writephy(tp, MII_BMCR, bmcr);
 
@@ -6968,7 +6941,7 @@ static int tg3_phy_lpbk_set(struct tg3 *tp, u32 speed, bool extlpbk)
        return 0;
 }
 
-static void tg3_set_loopback(struct net_device *dev, u32 features)
+static void tg3_set_loopback(struct net_device *dev, netdev_features_t features)
 {
        struct tg3 *tp = netdev_priv(dev);
 
@@ -6994,7 +6967,8 @@ static void tg3_set_loopback(struct net_device *dev, u32 features)
        }
 }
 
-static u32 tg3_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t tg3_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct tg3 *tp = netdev_priv(dev);
 
@@ -7004,9 +6978,9 @@ static u32 tg3_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int tg3_set_features(struct net_device *dev, u32 features)
+static int tg3_set_features(struct net_device *dev, netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if ((changed & NETIF_F_LOOPBACK) && netif_running(dev))
                tg3_set_loopback(dev, features);
@@ -10428,10 +10402,10 @@ static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-       strcpy(info->fw_version, tp->fw_ver);
-       strcpy(info->bus_info, pci_name(tp->pdev));
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, tp->fw_ver, sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(tp->pdev), sizeof(info->bus_info));
 }
 
 static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -15313,7 +15287,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        u32 sndmbx, rcvmbx, intmbx;
        char str[40];
        u64 dma_mask, persist_dma_mask;
-       u32 features = 0;
+       netdev_features_t features = 0;
 
        printk_once(KERN_INFO "%s\n", version);
 
index fd3dcc1e91453d24db9c8a0b9a6779c8046536f3..38d5c66075f9096a9fa3ea76e985fdd1e9a6d187 100644 (file)
@@ -296,8 +296,8 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
        struct bfa_ioc_attr *ioc_attr;
        unsigned long flags;
 
-       strcpy(drvinfo->driver, BNAD_NAME);
-       strcpy(drvinfo->version, BNAD_VERSION);
+       strlcpy(drvinfo->driver, BNAD_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, BNAD_VERSION, sizeof(drvinfo->version));
 
        ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
        if (ioc_attr) {
@@ -305,12 +305,13 @@ bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
                bfa_nw_ioc_get_attr(&bnad->bna.ioceth.ioc, ioc_attr);
                spin_unlock_irqrestore(&bnad->bna_lock, flags);
 
-               strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
-                       sizeof(drvinfo->fw_version) - 1);
+               strlcpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
+                       sizeof(drvinfo->fw_version));
                kfree(ioc_attr);
        }
 
-       strncpy(drvinfo->bus_info, pci_name(bnad->pcidev), ETHTOOL_BUSINFO_LEN);
+       strlcpy(drvinfo->bus_info, pci_name(bnad->pcidev),
+               sizeof(drvinfo->bus_info));
 }
 
 static void
index 1b3e90dfbd9a40d4cb9c0614411e83f1605b2d7b..32e8f178ab76a964af67dcce189e8ec84195ab42 100644 (file)
@@ -43,8 +43,7 @@ extern char bfa_version[];
 
 #pragma pack(1)
 
-#define MAC_ADDRLEN    (6)
-typedef struct mac { u8 mac[MAC_ADDRLEN]; } mac_t;
+typedef struct mac { u8 mac[ETH_ALEN]; } mac_t;
 
 #pragma pack()
 
index ca26d97171bddda55a642d330e24f1b43160cc7d..a971796b2262a8040f2400699a0f2a2d334e6efc 100644 (file)
@@ -434,10 +434,11 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct adapter *adapter = dev->ml_priv;
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(adapter->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
 }
 
 static int get_sset_count(struct net_device *dev, int sset)
@@ -849,7 +850,8 @@ static int t1_set_mac_addr(struct net_device *dev, void *p)
        return 0;
 }
 
-static u32 t1_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t t1_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -863,9 +865,9 @@ static u32 t1_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int t1_set_features(struct net_device *dev, u32 features)
+static int t1_set_features(struct net_device *dev, netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
        struct adapter *adapter = dev->ml_priv;
 
        if (changed & NETIF_F_HW_VLAN_RX)
index f9b6023000404da4d012fe186dc5a704ce7e8db4..47a84359d4e44b65fa6536553215f714a2df47a5 100644 (file)
@@ -742,7 +742,7 @@ static inline void setup_ring_params(struct adapter *adapter, u64 addr,
 /*
  * Enable/disable VLAN acceleration.
  */
-void t1_vlan_mode(struct adapter *adapter, u32 features)
+void t1_vlan_mode(struct adapter *adapter, netdev_features_t features)
 {
        struct sge *sge = adapter->sge;
 
index e03980bcdd6516adcbbbfeaedcf5ad9db172329d..b9bf16b385f7241c3cffc353e3fbc0feb798eafd 100644 (file)
@@ -79,7 +79,7 @@ irqreturn_t t1_interrupt(int irq, void *cookie);
 int t1_poll(struct napi_struct *, int);
 
 netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
-void t1_vlan_mode(struct adapter *adapter, u32 features);
+void t1_vlan_mode(struct adapter *adapter, netdev_features_t features);
 void t1_sge_start(struct sge *);
 void t1_sge_stop(struct sge *);
 int t1_sge_intr_error_handler(struct sge *);
index 4d15c8f99c3b8911d4f9ec71c61b4be40988379c..63ffaa7e255f43e9dd82e9bfa168acc1fbac0281 100644 (file)
@@ -1576,11 +1576,12 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        t3_get_tp_version(adapter, &tp_vers);
        spin_unlock(&adapter->stats_lock);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(adapter->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
        if (!fw_vers)
-               strcpy(info->fw_version, "N/A");
+               strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
        else {
                snprintf(info->fw_version, sizeof(info->fw_version),
                         "%s %u.%u.%u TP %u.%u.%u",
@@ -2531,7 +2532,7 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
        }
 }
 
-static void cxgb_vlan_mode(struct net_device *dev, u32 features)
+static void cxgb_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
@@ -2552,7 +2553,8 @@ static void cxgb_vlan_mode(struct net_device *dev, u32 features)
        t3_synchronize_rx(adapter, pi);
 }
 
-static u32 cxgb_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t cxgb_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -2566,9 +2568,9 @@ static u32 cxgb_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int cxgb_set_features(struct net_device *dev, u32 features)
+static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                cxgb_vlan_mode(dev, features);
index 4c8f42afa3c6d2b9b29e2925ab52e80ffe742538..fd6d460ea47522dc4b8011e8350648bbb0586562 100644 (file)
@@ -1002,12 +1002,13 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct adapter *adapter = netdev2adap(dev);
 
-       strcpy(info->driver, KBUILD_MODNAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(adapter->pdev));
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(adapter->pdev),
+               sizeof(info->bus_info));
 
        if (!adapter->params.fw_vers)
-               strcpy(info->fw_version, "N/A");
+               strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
        else
                snprintf(info->fw_version, sizeof(info->fw_version),
                        "%u.%u.%u.%u, TP %u.%u.%u.%u",
@@ -1855,10 +1856,10 @@ static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        return err;
 }
 
-static int cxgb_set_features(struct net_device *dev, u32 features)
+static int cxgb_set_features(struct net_device *dev, netdev_features_t features)
 {
        const struct port_info *pi = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
        int err;
 
        if (!(changed & NETIF_F_HW_VLAN_RX))
@@ -3537,7 +3538,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 {
        int func, i, err;
        struct port_info *pi;
-       unsigned int highdma = 0;
+       bool highdma = false;
        struct adapter *adapter = NULL;
 
        printk_once(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
@@ -3563,7 +3564,7 @@ static int __devinit init_one(struct pci_dev *pdev,
        }
 
        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
-               highdma = NETIF_F_HIGHDMA;
+               highdma = true;
                err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
                if (err) {
                        dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
@@ -3637,7 +3638,9 @@ static int __devinit init_one(struct pci_dev *pdev,
                        NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                        NETIF_F_RXCSUM | NETIF_F_RXHASH |
                        NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-               netdev->features |= netdev->hw_features | highdma;
+               if (highdma)
+                       netdev->hw_features |= NETIF_F_HIGHDMA;
+               netdev->features |= netdev->hw_features;
                netdev->vlan_features = netdev->features & VLAN_FEAT;
 
                netdev->priv_flags |= IFF_UNICAST_FLT;
index da9072bfca8b859a508943d1abdc9fd12201865c..8155cfecae19d9e97d944c09fa9d92617bbf61bc 100644 (file)
@@ -1092,7 +1092,8 @@ static int cxgb4vf_change_mtu(struct net_device *dev, int new_mtu)
        return ret;
 }
 
-static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t cxgb4vf_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -1106,10 +1107,11 @@ static u32 cxgb4vf_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int cxgb4vf_set_features(struct net_device *dev, u32 features)
+static int cxgb4vf_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct port_info *pi = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                t4vf_set_rxmode(pi->adapter, pi->viid, -1, -1, -1, -1,
@@ -1203,9 +1205,10 @@ static void cxgb4vf_get_drvinfo(struct net_device *dev,
 {
        struct adapter *adapter = netdev2adap(dev);
 
-       strcpy(drvinfo->driver, KBUILD_MODNAME);
-       strcpy(drvinfo->version, DRV_VERSION);
-       strcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent)));
+       strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->bus_info, pci_name(to_pci_dev(dev->dev.parent)),
+               sizeof(drvinfo->bus_info));
        snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
                 "%u.%u.%u.%u, TP %u.%u.%u.%u",
                 FW_HDR_FW_VER_MAJOR_GET(adapter->params.dev.fwrev),
index c3786fda11dbc6a399c4f8cb32fc1646ae4b9d91..1fe5df0284a659da5137fc2fbbdd07669c9f37b1 100644 (file)
@@ -217,11 +217,11 @@ static void enic_get_drvinfo(struct net_device *netdev,
 
        enic_dev_fw_info(enic, &fw_info);
 
-       strncpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
-       strncpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
-       strncpy(drvinfo->fw_version, fw_info->fw_version,
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, fw_info->fw_version,
                sizeof(drvinfo->fw_version));
-       strncpy(drvinfo->bus_info, pci_name(enic->pdev),
+       strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
                sizeof(drvinfo->bus_info));
 }
 
index 438f4580bf66207539761761e37c42e0ef303b78..26be1dfc1577e1e427e0ab2090bcbc490ec1c18c 100644 (file)
@@ -474,10 +474,11 @@ static int dm9000_nway_reset(struct net_device *dev)
        return mii_nway_restart(&dm->mii);
 }
 
-static int dm9000_set_features(struct net_device *dev, u32 features)
+static int dm9000_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        board_info_t *dm = to_dm9000_board(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
        unsigned long flags;
 
        if (!(changed & NETIF_F_RXCSUM))
index 1427739d9a514c9881e3b5b8187df303bc6d66c2..1eb46a0bb488f86ec4df92b24ec1673b6e2c3599 100644 (file)
@@ -1598,9 +1598,9 @@ static void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info)
 {
        struct de_private *de = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(de->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(de->pdev), sizeof(info->bus_info));
        info->eedump_len = DE_EEPROM_SIZE;
 }
 
index 17b11ee1745a3795fb2da04a928ebbdfb19357c5..51f7542eb451a048f851ae1979565008d1840b47 100644 (file)
@@ -1085,10 +1085,11 @@ static void dmfe_ethtool_get_drvinfo(struct net_device *dev,
 {
        struct dmfe_board_info *np = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        if (np->pdev)
-               strcpy(info->bus_info, pci_name(np->pdev));
+               strlcpy(info->bus_info, pci_name(np->pdev),
+                       sizeof(info->bus_info));
        else
                sprintf(info->bus_info, "EISA 0x%lx %d",
                        dev->base_addr, dev->irq);
index 9656dd0647d983d1d0dc056b87d1ecf77fe5c415..4eb0d76145c2347cf5060223f6003a94bfbb7857 100644 (file)
@@ -871,9 +871,9 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev)
 static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct tulip_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
 }
 
 
index 7a44a7a6adc8a0c172a4aa11dfd623ab74ccdc15..48b0b6566eef2105399e3bc06ddae226e94cde0d 100644 (file)
@@ -960,10 +960,11 @@ static void netdev_get_drvinfo(struct net_device *dev,
 {
        struct uli526x_board_info *np = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
        if (np->pdev)
-               strcpy(info->bus_info, pci_name(np->pdev));
+               strlcpy(info->bus_info, pci_name(np->pdev),
+                       sizeof(info->bus_info));
        else
                sprintf(info->bus_info, "EISA 0x%lx %d",
                        dev->base_addr, dev->irq);
index 4d01219ba22ffaf11890d0686e49217db8b63749..52da7b2fe3b6123c32749bd29a4a13c7e94be128 100644 (file)
@@ -1390,9 +1390,9 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *
 {
        struct netdev_private *np = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index dcd7f7a71ad4aaddbd426b8098b83d2b0aa8d14e..28a3a9b50b8b2856ecac014cc6797b53f7930a7f 100644 (file)
@@ -1634,9 +1634,9 @@ static int check_if_running(struct net_device *dev)
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index c1063d1540c2acd993e7d695803c64917cafc18d..d94b9686b80cca89b2063ad570db75ba4f015ba9 100644 (file)
@@ -804,9 +804,9 @@ static int dnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 static void dnet_get_drvinfo(struct net_device *dev,
                             struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, "0");
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, "0", sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops dnet_ethtool_ops = {
index 644e8fed836497483d8d2e5b59a61c03c8c0dcf7..34f162db9f2e3345fd43b803f0fe77857a4aaf98 100644 (file)
@@ -289,14 +289,12 @@ struct be_drv_stats {
 
 struct be_vf_cfg {
        unsigned char vf_mac_addr[ETH_ALEN];
-       u32 vf_if_handle;
-       u32 vf_pmac_id;
+       int vf_if_handle;
+       int vf_pmac_id;
        u16 vf_vlan_tag;
        u32 vf_tx_rate;
 };
 
-#define BE_INVALID_PMAC_ID             0xffffffff
-
 struct be_adapter {
        struct pci_dev *pdev;
        struct net_device *netdev;
@@ -347,11 +345,13 @@ struct be_adapter {
 
        /* Ethtool knobs and info */
        char fw_ver[FW_VER_LEN];
-       u32 if_handle;          /* Used to configure filtering */
+       int if_handle;          /* Used to configure filtering */
        u32 pmac_id;            /* MAC addr handle used by BE card */
        u32 beacon_state;       /* for set_phys_id */
 
        bool eeh_err;
+       bool ue_detected;
+       bool fw_timeout;
        u32 port_num;
        bool promiscuous;
        bool wol;
@@ -359,7 +359,6 @@ struct be_adapter {
        u32 function_caps;
        u32 rx_fc;              /* Rx flow control */
        u32 tx_fc;              /* Tx flow control */
-       bool ue_detected;
        bool stats_cmd_sent;
        int link_speed;
        u8 port_type;
@@ -524,6 +523,11 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter)
        return adapter->num_rx_qs > 1;
 }
 
+static inline bool be_error(struct be_adapter *adapter)
+{
+       return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout;
+}
+
 extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
                u16 num_popped);
 extern void be_link_status_update(struct be_adapter *adapter, u32 link_status);
index 2c7b36673dfc27bbae1c94a033ff702a2a928be4..64f0c1aa1b09215cce3d8cfefa75263af0fb312d 100644 (file)
@@ -31,11 +31,8 @@ static void be_mcc_notify(struct be_adapter *adapter)
        struct be_queue_info *mccq = &adapter->mcc_obj.q;
        u32 val = 0;
 
-       if (adapter->eeh_err) {
-               dev_info(&adapter->pdev->dev,
-                       "Error in Card Detected! Cannot issue commands\n");
+       if (be_error(adapter))
                return;
-       }
 
        val |= mccq->id & DB_MCCQ_RING_ID_MASK;
        val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
@@ -266,10 +263,10 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
        int i, num, status = 0;
        struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
        for (i = 0; i < mcc_timeout; i++) {
+               if (be_error(adapter))
+                       return -EIO;
+
                num = be_process_mcc(adapter, &status);
                if (num)
                        be_cq_notify(adapter, mcc_obj->cq.id,
@@ -280,7 +277,8 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
                udelay(100);
        }
        if (i == mcc_timeout) {
-               dev_err(&adapter->pdev->dev, "mccq poll timed out\n");
+               dev_err(&adapter->pdev->dev, "FW not responding\n");
+               adapter->fw_timeout = true;
                return -1;
        }
        return status;
@@ -298,26 +296,21 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
        int msecs = 0;
        u32 ready;
 
-       if (adapter->eeh_err) {
-               dev_err(&adapter->pdev->dev,
-                       "Error detected in card.Cannot issue commands\n");
-               return -EIO;
-       }
-
        do {
+               if (be_error(adapter))
+                       return -EIO;
+
                ready = ioread32(db);
-               if (ready == 0xffffffff) {
-                       dev_err(&adapter->pdev->dev,
-                               "pci slot disconnected\n");
+               if (ready == 0xffffffff)
                        return -1;
-               }
 
                ready &= MPU_MAILBOX_DB_RDY_MASK;
                if (ready)
                        break;
 
                if (msecs > 4000) {
-                       dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
+                       dev_err(&adapter->pdev->dev, "FW not responding\n");
+                       adapter->fw_timeout = true;
                        be_detect_dump_ue(adapter);
                        return -1;
                }
@@ -555,9 +548,6 @@ int be_cmd_fw_clean(struct be_adapter *adapter)
        u8 *wrb;
        int status;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
        if (mutex_lock_interruptible(&adapter->mbox_lock))
                return -1;
 
@@ -695,12 +685,15 @@ err:
 }
 
 /* Uses synchronous MCCQ */
-int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom)
+int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_pmac_del *req;
        int status;
 
+       if (pmac_id == -1)
+               return 0;
+
        spin_lock_bh(&adapter->mcc_lock);
 
        wrb = wrb_from_mccq(adapter);
@@ -923,10 +916,14 @@ int be_cmd_txq_create(struct be_adapter *adapter,
        void *ctxt;
        int status;
 
-       if (mutex_lock_interruptible(&adapter->mbox_lock))
-               return -1;
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
 
-       wrb = wrb_from_mbox(adapter);
        req = embedded_payload(wrb);
        ctxt = &req->context;
 
@@ -952,14 +949,15 @@ int be_cmd_txq_create(struct be_adapter *adapter,
 
        be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
 
-       status = be_mbox_notify_wait(adapter);
+       status = be_mcc_notify_wait(adapter);
        if (!status) {
                struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb);
                txq->id = le16_to_cpu(resp->cid);
                txq->created = true;
        }
 
-       mutex_unlock(&adapter->mbox_lock);
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
 
        return status;
 }
@@ -1018,9 +1016,6 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
        u8 subsys = 0, opcode = 0;
        int status;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
        if (mutex_lock_interruptible(&adapter->mbox_lock))
                return -1;
 
@@ -1136,16 +1131,13 @@ err:
 }
 
 /* Uses MCCQ */
-int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
+int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_if_destroy *req;
        int status;
 
-       if (adapter->eeh_err)
-               return -EIO;
-
-       if (!interface_id)
+       if (interface_id == -1)
                return 0;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -1254,6 +1246,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed,
        }
        req = embedded_payload(wrb);
 
+       if (lancer_chip(adapter))
+               req->hdr.version = 1;
+
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL);
 
@@ -1836,6 +1831,53 @@ err_unlock:
        return status;
 }
 
+int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+               u32 data_size, u32 data_offset, const char *obj_name,
+               u32 *data_read, u32 *eof, u8 *addn_status)
+{
+       struct be_mcc_wrb *wrb;
+       struct lancer_cmd_req_read_object *req;
+       struct lancer_cmd_resp_read_object *resp;
+       int status;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err_unlock;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_READ_OBJECT,
+                       sizeof(struct lancer_cmd_req_read_object), wrb,
+                       NULL);
+
+       req->desired_read_len = cpu_to_le32(data_size);
+       req->read_offset = cpu_to_le32(data_offset);
+       strcpy(req->object_name, obj_name);
+       req->descriptor_count = cpu_to_le32(1);
+       req->buf_len = cpu_to_le32(data_size);
+       req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF));
+       req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma));
+
+       status = be_mcc_notify_wait(adapter);
+
+       resp = embedded_payload(wrb);
+       if (!status) {
+               *data_read = le32_to_cpu(resp->actual_read_len);
+               *eof = le32_to_cpu(resp->eof);
+       } else {
+               *addn_status = resp->additional_status;
+       }
+
+err_unlock:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
 int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
                        u32 flash_type, u32 flash_opcode, u32 buf_size)
 {
index a35cd03fac4e840ab5f4aa7a15cae8ac4c01e652..ac112465e71901c21b30105aecc83f39be551272 100644 (file)
@@ -189,6 +189,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_PHY_DETAILS                  102
 #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP          103
 #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES   121
+#define OPCODE_COMMON_READ_OBJECT                      171
 #define OPCODE_COMMON_WRITE_OBJECT                     172
 
 #define OPCODE_ETH_RSS_CONFIG                          1
@@ -1161,6 +1162,38 @@ struct lancer_cmd_resp_write_object {
        u32 actual_write_len;
 };
 
+/************************ Lancer Read FW info **************/
+#define LANCER_READ_FILE_CHUNK                 (32*1024)
+#define LANCER_READ_FILE_EOF_MASK              0x80000000
+
+#define LANCER_FW_DUMP_FILE                    "/dbg/dump.bin"
+#define LANCER_VPD_PF_FILE                     "/vpd/ntr_pf.vpd"
+#define LANCER_VPD_VF_FILE                     "/vpd/ntr_vf.vpd"
+
+struct lancer_cmd_req_read_object {
+       struct be_cmd_req_hdr hdr;
+       u32 desired_read_len;
+       u32 read_offset;
+       u8 object_name[104];
+       u32 descriptor_count;
+       u32 buf_len;
+       u32 addr_low;
+       u32 addr_high;
+};
+
+struct lancer_cmd_resp_read_object {
+       u8 opcode;
+       u8 subsystem;
+       u8 rsvd1[2];
+       u8 status;
+       u8 additional_status;
+       u8 rsvd2[2];
+       u32 resp_len;
+       u32 actual_resp_len;
+       u32 actual_read_len;
+       u32 eof;
+};
+
 /************************ WOL *******************************/
 struct be_cmd_req_acpi_wol_magic_config{
        struct be_cmd_req_hdr hdr;
@@ -1417,11 +1450,11 @@ extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
 extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
                        u32 if_id, u32 *pmac_id, u32 domain);
 extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id,
-                       u32 pmac_id, u32 domain);
+                       int pmac_id, u32 domain);
 extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
                        u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id,
                        u32 domain);
-extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle,
+extern int be_cmd_if_destroy(struct be_adapter *adapter, int if_handle,
                        u32 domain);
 extern int be_cmd_eq_create(struct be_adapter *adapter,
                        struct be_queue_info *eq, int eq_delay);
@@ -1480,6 +1513,9 @@ extern int lancer_cmd_write_object(struct be_adapter *adapter,
                                u32 data_size, u32 data_offset,
                                const char *obj_name,
                                u32 *data_written, u8 *addn_status);
+int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+               u32 data_size, u32 data_offset, const char *obj_name,
+               u32 *data_read, u32 *eof, u8 *addn_status);
 int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
                                int offset);
 extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
index bf8153ea4ed81a6a443681c551e7f45fd9aa7bc8..575c78306313c2d264476e81cdf1ec01e0af6a19 100644 (file)
@@ -127,8 +127,8 @@ static void be_get_drvinfo(struct net_device *netdev,
        memset(fw_on_flash, 0 , sizeof(fw_on_flash));
        be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash);
 
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->version, DRV_VER);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
        strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
        if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
                strcat(drvinfo->fw_version, " [");
@@ -136,21 +136,84 @@ static void be_get_drvinfo(struct net_device *netdev,
                strcat(drvinfo->fw_version, "]");
        }
 
-       strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->testinfo_len = 0;
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
 }
 
+static u32
+lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)
+{
+       u32 data_read = 0, eof;
+       u8 addn_status;
+       struct be_dma_mem data_len_cmd;
+       int status;
+
+       memset(&data_len_cmd, 0, sizeof(data_len_cmd));
+       /* data_offset and data_size should be 0 to get reg len */
+       status = lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0,
+                               file_name, &data_read, &eof, &addn_status);
+
+       return data_read;
+}
+
+static int
+lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,
+               u32 buf_len, void *buf)
+{
+       struct be_dma_mem read_cmd;
+       u32 read_len = 0, total_read_len = 0, chunk_size;
+       u32 eof = 0;
+       u8 addn_status;
+       int status = 0;
+
+       read_cmd.size = LANCER_READ_FILE_CHUNK;
+       read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size,
+                       &read_cmd.dma);
+
+       if (!read_cmd.va) {
+               dev_err(&adapter->pdev->dev,
+                               "Memory allocation failure while reading dump\n");
+               return -ENOMEM;
+       }
+
+       while ((total_read_len < buf_len) && !eof) {
+               chunk_size = min_t(u32, (buf_len - total_read_len),
+                               LANCER_READ_FILE_CHUNK);
+               chunk_size = ALIGN(chunk_size, 4);
+               status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size,
+                               total_read_len, file_name, &read_len,
+                               &eof, &addn_status);
+               if (!status) {
+                       memcpy(buf + total_read_len, read_cmd.va, read_len);
+                       total_read_len += read_len;
+                       eof &= LANCER_READ_FILE_EOF_MASK;
+               } else {
+                       status = -EIO;
+                       break;
+               }
+       }
+       pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va,
+                       read_cmd.dma);
+
+       return status;
+}
+
 static int
 be_get_reg_len(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
        u32 log_size = 0;
 
-       if (be_physfn(adapter))
-               be_cmd_get_reg_len(adapter, &log_size);
-
+       if (be_physfn(adapter)) {
+               if (lancer_chip(adapter))
+                       log_size = lancer_cmd_get_file_len(adapter,
+                                       LANCER_FW_DUMP_FILE);
+               else
+                       be_cmd_get_reg_len(adapter, &log_size);
+       }
        return log_size;
 }
 
@@ -161,7 +224,11 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
 
        if (be_physfn(adapter)) {
                memset(buf, 0, regs->len);
-               be_cmd_get_regs(adapter, regs->len, buf);
+               if (lancer_chip(adapter))
+                       lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE,
+                                       regs->len, buf);
+               else
+                       be_cmd_get_regs(adapter, regs->len, buf);
        }
 }
 
@@ -660,7 +727,17 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
 static int
 be_get_eeprom_len(struct net_device *netdev)
 {
-       return BE_READ_SEEPROM_LEN;
+       struct be_adapter *adapter = netdev_priv(netdev);
+       if (lancer_chip(adapter)) {
+               if (be_physfn(adapter))
+                       return lancer_cmd_get_file_len(adapter,
+                                       LANCER_VPD_PF_FILE);
+               else
+                       return lancer_cmd_get_file_len(adapter,
+                                       LANCER_VPD_VF_FILE);
+       } else {
+               return BE_READ_SEEPROM_LEN;
+       }
 }
 
 static int
@@ -675,6 +752,15 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
        if (!eeprom->len)
                return -EINVAL;
 
+       if (lancer_chip(adapter)) {
+               if (be_physfn(adapter))
+                       return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE,
+                                       eeprom->len, data);
+               else
+                       return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE,
+                                       eeprom->len, data);
+       }
+
        eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
 
        memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
index bf266a00c7742129fd8d86699e1756d0dc1ba070..93869d457b14d7771c229a6c69570f239ede7e3c 100644 (file)
@@ -848,15 +848,11 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
                return -EINVAL;
 
-       if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
-               status = be_cmd_pmac_del(adapter,
-                                       adapter->vf_cfg[vf].vf_if_handle,
-                                       adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
+       status = be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle,
+                               adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
 
-       status = be_cmd_pmac_add(adapter, mac,
-                               adapter->vf_cfg[vf].vf_if_handle,
+       status = be_cmd_pmac_add(adapter, mac, adapter->vf_cfg[vf].vf_if_handle,
                                &adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
-
        if (status)
                dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
                                mac, vf);
@@ -1693,9 +1689,6 @@ static int be_tx_queues_create(struct be_adapter *adapter)
                if (be_queue_alloc(adapter, q, TX_Q_LEN,
                        sizeof(struct be_eth_wrb)))
                        goto err;
-
-               if (be_cmd_txq_create(adapter, q, cq))
-                       goto err;
        }
        return 0;
 
@@ -1982,6 +1975,9 @@ void be_detect_dump_ue(struct be_adapter *adapter)
        u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
        u32 i;
 
+       if (adapter->eeh_err || adapter->ue_detected)
+               return;
+
        if (lancer_chip(adapter)) {
                sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
                if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
@@ -2008,7 +2004,8 @@ void be_detect_dump_ue(struct be_adapter *adapter)
                sliport_status & SLIPORT_STATUS_ERR_MASK) {
                adapter->ue_detected = true;
                adapter->eeh_err = true;
-               dev_err(&adapter->pdev->dev, "UE Detected!!\n");
+               dev_err(&adapter->pdev->dev,
+                       "Unrecoverable error in the card\n");
        }
 
        if (ue_lo) {
@@ -2043,8 +2040,7 @@ static void be_worker(struct work_struct *work)
        struct be_rx_obj *rxo;
        int i;
 
-       if (!adapter->ue_detected)
-               be_detect_dump_ue(adapter);
+       be_detect_dump_ue(adapter);
 
        /* when interrupts are not yet enabled, just reap any pending
        * mcc completions */
@@ -2488,17 +2484,13 @@ static void be_vf_clear(struct be_adapter *adapter)
 {
        u32 vf;
 
-       for (vf = 0; vf < num_vfs; vf++) {
-               if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
-                       be_cmd_pmac_del(adapter,
-                                       adapter->vf_cfg[vf].vf_if_handle,
-                                       adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
-       }
+       for (vf = 0; vf < num_vfs; vf++)
+               be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle,
+                               adapter->vf_cfg[vf].vf_pmac_id, vf + 1);
 
        for (vf = 0; vf < num_vfs; vf++)
-               if (adapter->vf_cfg[vf].vf_if_handle)
-                       be_cmd_if_destroy(adapter,
-                               adapter->vf_cfg[vf].vf_if_handle, vf + 1);
+               be_cmd_if_destroy(adapter, adapter->vf_cfg[vf].vf_if_handle,
+                               vf + 1);
 }
 
 static int be_clear(struct be_adapter *adapter)
@@ -2511,22 +2503,30 @@ static int be_clear(struct be_adapter *adapter)
        be_mcc_queues_destroy(adapter);
        be_rx_queues_destroy(adapter);
        be_tx_queues_destroy(adapter);
-       adapter->eq_next_idx = 0;
-
-       adapter->be3_native = false;
-       adapter->promiscuous = false;
 
        /* tell fw we're done with firing cmds */
        be_cmd_fw_clean(adapter);
        return 0;
 }
 
+static void be_vf_setup_init(struct be_adapter *adapter)
+{
+       int vf;
+
+       for (vf = 0; vf < num_vfs; vf++) {
+               adapter->vf_cfg[vf].vf_if_handle = -1;
+               adapter->vf_cfg[vf].vf_pmac_id = -1;
+       }
+}
+
 static int be_vf_setup(struct be_adapter *adapter)
 {
        u32 cap_flags, en_flags, vf;
        u16 lnk_speed;
        int status;
 
+       be_vf_setup_init(adapter);
+
        cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST;
        for (vf = 0; vf < num_vfs; vf++) {
                status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL,
@@ -2534,7 +2534,6 @@ static int be_vf_setup(struct be_adapter *adapter)
                                        NULL, vf+1);
                if (status)
                        goto err;
-               adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
        }
 
        if (!lancer_chip(adapter)) {
@@ -2555,17 +2554,26 @@ err:
        return status;
 }
 
+static void be_setup_init(struct be_adapter *adapter)
+{
+       adapter->vlan_prio_bmap = 0xff;
+       adapter->link_speed = -1;
+       adapter->if_handle = -1;
+       adapter->be3_native = false;
+       adapter->promiscuous = false;
+       adapter->eq_next_idx = 0;
+}
+
 static int be_setup(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        u32 cap_flags, en_flags;
        u32 tx_fc, rx_fc;
-       int status;
+       int status, i;
        u8 mac[ETH_ALEN];
+       struct be_tx_obj *txo;
 
-       /* Allow all priorities by default. A GRP5 evt may modify this */
-       adapter->vlan_prio_bmap = 0xff;
-       adapter->link_speed = -1;
+       be_setup_init(adapter);
 
        be_cmd_req_native_mode(adapter);
 
@@ -2592,7 +2600,8 @@ static int be_setup(struct be_adapter *adapter)
        en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                        BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
        cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS |
-                       BE_IF_FLAGS_PROMISCUOUS;
+                       BE_IF_FLAGS_VLAN_PROMISCUOUS | BE_IF_FLAGS_PROMISCUOUS;
+
        if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
                cap_flags |= BE_IF_FLAGS_RSS;
                en_flags |= BE_IF_FLAGS_RSS;
@@ -2603,6 +2612,12 @@ static int be_setup(struct be_adapter *adapter)
        if (status != 0)
                goto err;
 
+        for_all_tx_queues(adapter, txo, i) {
+               status = be_cmd_txq_create(adapter, &txo->q, &txo->cq);
+               if (status)
+                       goto err;
+       }
+
        /* For BEx, the VF's permanent mac queried from card is incorrect.
         * Query the mac configued by the PF using if_handle
         */
@@ -3559,6 +3574,8 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
 
        dev_info(&adapter->pdev->dev, "EEH reset\n");
        adapter->eeh_err = false;
+       adapter->ue_detected = false;
+       adapter->fw_timeout = false;
 
        status = pci_enable_device(pdev);
        if (status)
index 61d2bddec1fa9e6c38fc5521a3962647e159f4e0..c82d444b582d52533dbbd8072ceccc0613b1a12c 100644 (file)
@@ -1818,9 +1818,9 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
 {
        struct netdev_private *np = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 52f4e8ad48e77c84b8bd4ed9cd52faa3f5adb419..8dee1aed47e4c15a912cbddcb29608fa5ed3f811 100644 (file)
@@ -183,28 +183,10 @@ void fsl_pq_mdio_bus_name(char *name, struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name);
 
-/* Scan the bus in reverse, looking for an empty spot */
-static int fsl_pq_mdio_find_free(struct mii_bus *new_bus)
-{
-       int i;
-
-       for (i = PHY_MAX_ADDR; i > 0; i--) {
-               u32 phy_id;
-
-               if (get_phy_id(new_bus, i, &phy_id))
-                       return -1;
-
-               if (phy_id == 0xffffffff)
-                       break;
-       }
-
-       return i;
-}
 
-
-#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
 static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np)
 {
+#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
        struct gfar __iomem *enet_regs;
 
        /*
@@ -220,15 +202,15 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct devi
        } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") ||
                        of_device_is_compatible(np, "fsl,etsec2-tbi")) {
                return of_iomap(np, 1);
-       } else
-               return NULL;
-}
+       }
 #endif
+       return NULL;
+}
 
 
-#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
 static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id)
 {
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
        struct device_node *np = NULL;
        int err = 0;
 
@@ -261,9 +243,10 @@ static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id)
                return err;
        else
                return -EINVAL;
-}
+#else
+       return -ENODEV;
 #endif
-
+}
 
 static int fsl_pq_mdio_probe(struct platform_device *ofdev)
 {
@@ -339,19 +322,13 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev)
                        of_device_is_compatible(np, "fsl,etsec2-mdio") ||
                        of_device_is_compatible(np, "fsl,etsec2-tbi") ||
                        of_device_is_compatible(np, "gianfar")) {
-#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE)
                tbipa = get_gfar_tbipa(regs, np);
                if (!tbipa) {
                        err = -EINVAL;
                        goto err_free_irqs;
                }
-#else
-               err = -ENODEV;
-               goto err_free_irqs;
-#endif
        } else if (of_device_is_compatible(np, "fsl,ucc-mdio") ||
                        of_device_is_compatible(np, "ucc_geth_phy")) {
-#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE)
                u32 id;
                static u32 mii_mng_master;
 
@@ -364,10 +341,6 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev)
                        mii_mng_master = id;
                        ucc_set_qe_mux_mii_mng(id - 1);
                }
-#else
-               err = -ENODEV;
-               goto err_free_irqs;
-#endif
        } else {
                err = -ENODEV;
                goto err_free_irqs;
@@ -383,26 +356,16 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev)
 
                if (prop)
                        tbiaddr = *prop;
-       }
-
-       if (tbiaddr == -1) {
-               out_be32(tbipa, 0);
 
-               tbiaddr = fsl_pq_mdio_find_free(new_bus);
-       }
-
-       /*
-        * We define TBIPA at 0 to be illegal, opting to fail for boards that
-        * have PHYs at 1-31, rather than change tbipa and rescan.
-        */
-       if (tbiaddr == 0) {
-               err = -EBUSY;
+               if (tbiaddr == -1) {
+                       err = -EBUSY;
 
-               goto err_free_irqs;
+                       goto err_free_irqs;
+               } else {
+                       out_be32(tbipa, tbiaddr);
+               }
        }
 
-       out_be32(tbipa, tbiaddr);
-
        err = of_mdiobus_register(new_bus, np);
        if (err) {
                printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
index 83199fd0d62b14df6e13ae5403feecdf4eb35af8..8e21ceb3b7da673ec590bf102f302dc76437a45a 100644 (file)
@@ -734,7 +734,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 
        mac_addr = of_get_mac_address(np);
        if (mac_addr)
-               memcpy(dev->dev_addr, mac_addr, MAC_ADDR_LEN);
+               memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
 
        if (model && !strcasecmp(model, "TSEC"))
                priv->device_flags =
@@ -2306,7 +2306,7 @@ void gfar_check_rx_parser_mode(struct gfar_private *priv)
 }
 
 /* Enables and disables VLAN insertion/extraction */
-void gfar_vlan_mode(struct net_device *dev, u32 features)
+void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = NULL;
@@ -3114,7 +3114,7 @@ static void gfar_set_multi(struct net_device *dev)
 static void gfar_clear_exact_match(struct net_device *dev)
 {
        int idx;
-       static const u8 zero_arr[MAC_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
+       static const u8 zero_arr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
        for(idx = 1;idx < GFAR_EM_NUM + 1;idx++)
                gfar_set_mac_for_addr(dev, idx, zero_arr);
@@ -3137,7 +3137,7 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
 {
        u32 tempval;
        struct gfar_private *priv = netdev_priv(dev);
-       u32 result = ether_crc(MAC_ADDR_LEN, addr);
+       u32 result = ether_crc(ETH_ALEN, addr);
        int width = priv->hash_width;
        u8 whichbit = (result >> (32 - width)) & 0x1f;
        u8 whichreg = result >> (32 - width + 5);
@@ -3158,7 +3158,7 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num,
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        int idx;
-       char tmpbuf[MAC_ADDR_LEN];
+       char tmpbuf[ETH_ALEN];
        u32 tempval;
        u32 __iomem *macptr = &regs->macstnaddr1;
 
@@ -3166,8 +3166,8 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num,
 
        /* Now copy it into the mac registers backwards, cuz */
        /* little endian is silly */
-       for (idx = 0; idx < MAC_ADDR_LEN; idx++)
-               tmpbuf[MAC_ADDR_LEN - 1 - idx] = addr[idx];
+       for (idx = 0; idx < ETH_ALEN; idx++)
+               tmpbuf[ETH_ALEN - 1 - idx] = addr[idx];
 
        gfar_write(macptr, *((u32 *) (tmpbuf)));
 
index 9aa43773e8e35047da95bad312d9027650714d65..fe7ac3a83194d8407f191227e710fe19a699e13a 100644 (file)
@@ -74,9 +74,6 @@ struct ethtool_rx_list {
  * will be the next highest multiple of 512 bytes. */
 #define INCREMENTAL_BUFFER_SIZE 512
 
-
-#define MAC_ADDR_LEN 6
-
 #define PHY_INIT_TIMEOUT 100000
 #define GFAR_PHY_CHANGE_TIME 2
 
@@ -1179,9 +1176,9 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
 extern void gfar_configure_coalescing(struct gfar_private *priv,
                unsigned long tx_mask, unsigned long rx_mask);
 void gfar_init_sysfs(struct net_device *dev);
-int gfar_set_features(struct net_device *dev, u32 features);
+int gfar_set_features(struct net_device *dev, netdev_features_t features);
 extern void gfar_check_rx_parser_mode(struct gfar_private *priv);
-extern void gfar_vlan_mode(struct net_device *dev, u32 features);
+extern void gfar_vlan_mode(struct net_device *dev, netdev_features_t features);
 
 extern const struct ethtool_ops gfar_ethtool_ops;
 
index 212736bab6bb27ac8a261b9d97d0c0415e978ef2..1ea0eb9ee6438390f888926a951b870fc0d8ec2f 100644 (file)
@@ -519,12 +519,12 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
        return err;
 }
 
-int gfar_set_features(struct net_device *dev, u32 features)
+int gfar_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct gfar_private *priv = netdev_priv(dev);
        unsigned long flags;
        int err = 0, i = 0;
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
                gfar_vlan_mode(dev, features);
index b5dc0273a1d1d63f213096dfd3f1057006d0b6e2..ba2dc083bfc007fa416e3c714dd1e6350d59e99b 100644 (file)
@@ -443,7 +443,7 @@ static void hw_add_addr_in_hash(struct ucc_geth_private *ugeth,
 
 static inline int compare_addr(u8 **addr1, u8 **addr2)
 {
-       return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
+       return memcmp(addr1, addr2, ETH_ALEN);
 }
 
 #ifdef DEBUG
index d12fcad145e9b2f0765caa7195e033a1adb43647..2e395a2566b8d6221747f79828cbdfb70f72947c 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/if_ether.h>
 
 #include <asm/immap_qe.h>
 #include <asm/qe.h>
@@ -881,7 +882,6 @@ struct ucc_geth_hardware_statistics {
 #define TX_RING_MOD_MASK(size)                  (size-1)
 #define RX_RING_MOD_MASK(size)                  (size-1)
 
-#define ENET_NUM_OCTETS_PER_ADDRESS             6
 #define ENET_GROUP_ADDR                         0x01   /* Group address mask
                                                           for ethernet
                                                           addresses */
@@ -1051,7 +1051,7 @@ enum ucc_geth_num_of_station_addresses {
 
 /* UCC GETH 82xx Ethernet Address Container */
 struct enet_addr_container {
-       u8 address[ENET_NUM_OCTETS_PER_ADDRESS];        /* ethernet address */
+       u8 address[ETH_ALEN];   /* ethernet address */
        enum ucc_geth_enet_address_recognition_location location;       /* location in
                                                                   82xx address
                                                                   recognition
@@ -1194,7 +1194,7 @@ struct ucc_geth_private {
        u16 cpucount[NUM_TX_QUEUES];
        u16 __iomem *p_cpucount[NUM_TX_QUEUES];
        int indAddrRegUsed[NUM_OF_PADDRS];
-       u8 paddr[NUM_OF_PADDRS][ENET_NUM_OCTETS_PER_ADDRESS];   /* ethernet address */
+       u8 paddr[NUM_OF_PADDRS][ETH_ALEN];      /* ethernet address */
        u8 numGroupAddrInHash;
        u8 numIndAddrInHash;
        u8 numIndAddrInReg;
index 15416752c13e0646ccfc3eac1435671dc9f4ac25..ee84b472cee60c377556495ff54504e8a4f6b7f8 100644 (file)
@@ -1058,9 +1058,10 @@ static void fjn_rx(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       snprintf(info->bus_info, sizeof(info->bus_info),
+               "PCMCIA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
index 067c46069a113aed9e8c9ac7220e3e6516599b97..114cda7721fe5d155a46045894b386efa850c545 100644 (file)
@@ -1726,9 +1726,10 @@ static int eepro_ethtool_get_settings(struct net_device *dev,
 static void eepro_ethtool_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *drvinfo)
 {
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->version, DRV_VERSION);
-       sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+       snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info),
+               "ISA 0x%lx", dev->base_addr);
 }
 
 static const struct ethtool_ops eepro_ethtool_ops = {
index ed79b2d3ad3ebaee10cf400606481dc3a3ea5a4e..2abce965c7bdf81105238bdc890581141b3ecb85 100644 (file)
@@ -2924,6 +2924,9 @@ static int __devexit emac_remove(struct platform_device *ofdev)
        if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
                zmii_detach(dev->zmii_dev, dev->zmii_port);
 
+       busy_phy_map &= ~(1 << dev->phy.address);
+       DBG(dev, "busy_phy_map now %#x" NL, busy_phy_map);
+
        mal_unregister_commac(dev->mal, &dev->commac);
        emac_put_deps(dev);
 
index b1cd41b9c61ca0e970adc2285a845505c8daf7e9..e877371680a9b1417f53b7b4c73f770b4e6c3d43 100644 (file)
@@ -735,7 +735,8 @@ static void netdev_get_drvinfo(struct net_device *dev,
                sizeof(info->version) - 1);
 }
 
-static u32 ibmveth_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t ibmveth_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /*
         * Since the ibmveth firmware interface does not have the
@@ -838,7 +839,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
        return rc1 ? rc1 : rc2;
 }
 
-static int ibmveth_set_features(struct net_device *dev, u32 features)
+static int ibmveth_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct ibmveth_adapter *adapter = netdev_priv(dev);
        int rx_csum = !!(features & NETIF_F_RXCSUM);
index 5a2fdf7a00c8bbbe9a8f9f7a3a7abf8fd1be180f..46003278ffa0be85db7a05a29c226e53651da3c2 100644 (file)
@@ -2376,10 +2376,11 @@ static void e100_get_drvinfo(struct net_device *netdev,
        struct ethtool_drvinfo *info)
 {
        struct nic *nic = netdev_priv(netdev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(nic->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(nic->pdev),
+               sizeof(info->bus_info));
 }
 
 #define E100_PHY_REGS 0x1C
index 2b223ac99c421c9a6413e06f996ca4efc2f45a7a..63faec693deb37b14c3b27b5067151930ebad3fd 100644 (file)
@@ -515,14 +515,15 @@ static void e1000_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *drvinfo)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
 
-       strncpy(drvinfo->driver,  e1000_driver_name, 32);
-       strncpy(drvinfo->version, e1000_driver_version, 32);
+       strlcpy(drvinfo->driver,  e1000_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, e1000_driver_version,
+               sizeof(drvinfo->version));
 
-       sprintf(firmware_version, "N/A");
-       strncpy(drvinfo->fw_version, firmware_version, 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = e1000_get_regs_len(netdev);
        drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
 }
index 5c9a8403668b87e1bc711e654f3dad6be6b0854c..cf7e3c09447757573342aea7715993d0e8db1c60 100644 (file)
@@ -448,7 +448,6 @@ void e1000_io_write(struct e1000_hw *hw, unsigned long port, u32 value);
 #define E1000_DEV_ID_INTEL_CE4100_GBE    0x2E6E
 
 #define NODE_ADDRESS_SIZE 6
-#define ETH_LENGTH_OF_ADDRESS 6
 
 /* MAC decode size is 128K - This is the size of BAR0 */
 #define MAC_DECODE_SIZE (128 * 1024)
index cf480b55462273d51d4272d61af4e5521d53a379..82f4ef142259070b64317955c111b19875024c65 100644 (file)
@@ -167,7 +167,8 @@ static int e1000_82547_fifo_workaround(struct e1000_adapter *adapter,
                                        struct sk_buff *skb);
 
 static bool e1000_vlan_used(struct e1000_adapter *adapter);
-static void e1000_vlan_mode(struct net_device *netdev, u32 features);
+static void e1000_vlan_mode(struct net_device *netdev,
+                           netdev_features_t features);
 static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid);
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
@@ -806,7 +807,8 @@ static int e1000_is_need_ioport(struct pci_dev *pdev)
        }
 }
 
-static u32 e1000_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t e1000_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -820,10 +822,11 @@ static u32 e1000_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int e1000_set_features(struct net_device *netdev, u32 features)
+static int e1000_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                e1000_vlan_mode(netdev, features);
@@ -4577,7 +4580,8 @@ static void e1000_vlan_filter_on_off(struct e1000_adapter *adapter,
                e1000_irq_enable(adapter);
 }
 
-static void e1000_vlan_mode(struct net_device *netdev, u32 features)
+static void e1000_vlan_mode(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
index 69c9d2199140a94b4f754bdc1fc43d93bd00b6ea..fb2c28e799a2d6ad80ef5eeb88d2fb6e058ec866 100644 (file)
@@ -579,26 +579,24 @@ static void e1000_get_drvinfo(struct net_device *netdev,
                              struct ethtool_drvinfo *drvinfo)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
 
-       strncpy(drvinfo->driver,  e1000e_driver_name,
-               sizeof(drvinfo->driver) - 1);
-       strncpy(drvinfo->version, e1000e_driver_version,
-               sizeof(drvinfo->version) - 1);
+       strlcpy(drvinfo->driver,  e1000e_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, e1000e_driver_version,
+               sizeof(drvinfo->version));
 
        /*
         * EEPROM image version # is reported as firmware version # for
         * PCI-E controllers
         */
-       snprintf(firmware_version, sizeof(firmware_version), "%d.%d-%d",
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d-%d",
                (adapter->eeprom_vers & 0xF000) >> 12,
                (adapter->eeprom_vers & 0x0FF0) >> 4,
                (adapter->eeprom_vers & 0x000F));
 
-       strncpy(drvinfo->fw_version, firmware_version,
-               sizeof(drvinfo->fw_version) - 1);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               sizeof(drvinfo->bus_info) - 1);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = e1000_get_regs_len(netdev);
        drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
 }
index a855db1ad2495b9c682191b36e82a5b875a981ab..a5bd7a3dafc978d4de17f2e1f2ec83761bb33e4c 100644 (file)
@@ -163,16 +163,13 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
                        regs[n] = __er32(hw, E1000_TARC(n));
                break;
        default:
-               printk(KERN_INFO "%-15s %08x\n",
-                      reginfo->name, __er32(hw, reginfo->ofs));
+               pr_info("%-15s %08x\n",
+                       reginfo->name, __er32(hw, reginfo->ofs));
                return;
        }
 
        snprintf(rname, 16, "%s%s", reginfo->name, "[0-1]");
-       printk(KERN_INFO "%-15s ", rname);
-       for (n = 0; n < 2; n++)
-               printk(KERN_CONT "%08x ", regs[n]);
-       printk(KERN_CONT "\n");
+       pr_info("%-15s %08x %08x\n", rname, regs[0], regs[1]);
 }
 
 /*
@@ -208,16 +205,15 @@ static void e1000e_dump(struct e1000_adapter *adapter)
        /* Print netdevice Info */
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
-               printk(KERN_INFO "Device Name     state            "
-                      "trans_start      last_rx\n");
-               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
-                      netdev->name, netdev->state, netdev->trans_start,
-                      netdev->last_rx);
+               pr_info("Device Name     state            trans_start      last_rx\n");
+               pr_info("%-15s %016lX %016lX %016lX\n",
+                       netdev->name, netdev->state, netdev->trans_start,
+                       netdev->last_rx);
        }
 
        /* Print Registers */
        dev_info(&adapter->pdev->dev, "Register Dump\n");
-       printk(KERN_INFO " Register Name   Value\n");
+       pr_info(" Register Name   Value\n");
        for (reginfo = (struct e1000_reg_info *)e1000_reg_info_tbl;
             reginfo->name; reginfo++) {
                e1000_regdump(hw, reginfo);
@@ -228,15 +224,14 @@ static void e1000e_dump(struct e1000_adapter *adapter)
                goto exit;
 
        dev_info(&adapter->pdev->dev, "Tx Ring Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
-              " leng ntw timestamp\n");
+       pr_info("Queue [NTU] [NTC] [bi(ntc)->dma  ] leng ntw timestamp\n");
        buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
-       printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
-              0, tx_ring->next_to_use, tx_ring->next_to_clean,
-              (unsigned long long)buffer_info->dma,
-              buffer_info->length,
-              buffer_info->next_to_watch,
-              (unsigned long long)buffer_info->time_stamp);
+       pr_info(" %5d %5X %5X %016llX %04X %3X %016llX\n",
+               0, tx_ring->next_to_use, tx_ring->next_to_clean,
+               (unsigned long long)buffer_info->dma,
+               buffer_info->length,
+               buffer_info->next_to_watch,
+               (unsigned long long)buffer_info->time_stamp);
 
        /* Print Tx Ring */
        if (!netif_msg_tx_done(adapter))
@@ -271,37 +266,32 @@ static void e1000e_dump(struct e1000_adapter *adapter)
         *   +----------------------------------------------------------------+
         *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
         */
-       printk(KERN_INFO "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
-              " [bi->dma       ] leng  ntw timestamp        bi->skb "
-              "<-- Legacy format\n");
-       printk(KERN_INFO "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
-              " [bi->dma       ] leng  ntw timestamp        bi->skb "
-              "<-- Ext Context format\n");
-       printk(KERN_INFO "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
-              " [bi->dma       ] leng  ntw timestamp        bi->skb "
-              "<-- Ext Data format\n");
+       pr_info("Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen] [bi->dma       ] leng  ntw timestamp        bi->skb <-- Legacy format\n");
+       pr_info("Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen] [bi->dma       ] leng  ntw timestamp        bi->skb <-- Ext Context format\n");
+       pr_info("Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen] [bi->dma       ] leng  ntw timestamp        bi->skb <-- Ext Data format\n");
        for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+               const char *next_desc;
                tx_desc = E1000_TX_DESC(*tx_ring, i);
                buffer_info = &tx_ring->buffer_info[i];
                u0 = (struct my_u0 *)tx_desc;
-               printk(KERN_INFO "T%c[0x%03X]    %016llX %016llX %016llX "
-                      "%04X  %3X %016llX %p",
-                      (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
-                       ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')), i,
-                      (unsigned long long)le64_to_cpu(u0->a),
-                      (unsigned long long)le64_to_cpu(u0->b),
-                      (unsigned long long)buffer_info->dma,
-                      buffer_info->length, buffer_info->next_to_watch,
-                      (unsigned long long)buffer_info->time_stamp,
-                      buffer_info->skb);
                if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
-                       printk(KERN_CONT " NTC/U\n");
+                       next_desc = " NTC/U";
                else if (i == tx_ring->next_to_use)
-                       printk(KERN_CONT " NTU\n");
+                       next_desc = " NTU";
                else if (i == tx_ring->next_to_clean)
-                       printk(KERN_CONT " NTC\n");
+                       next_desc = " NTC";
                else
-                       printk(KERN_CONT "\n");
+                       next_desc = "";
+               pr_info("T%c[0x%03X]    %016llX %016llX %016llX %04X  %3X %016llX %p%s\n",
+                       (!(le64_to_cpu(u0->b) & (1 << 29)) ? 'l' :
+                        ((le64_to_cpu(u0->b) & (1 << 20)) ? 'd' : 'c')),
+                       i,
+                       (unsigned long long)le64_to_cpu(u0->a),
+                       (unsigned long long)le64_to_cpu(u0->b),
+                       (unsigned long long)buffer_info->dma,
+                       buffer_info->length, buffer_info->next_to_watch,
+                       (unsigned long long)buffer_info->time_stamp,
+                       buffer_info->skb, next_desc);
 
                if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
                        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
@@ -312,9 +302,9 @@ static void e1000e_dump(struct e1000_adapter *adapter)
        /* Print Rx Ring Summary */
 rx_ring_summary:
        dev_info(&adapter->pdev->dev, "Rx Ring Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC]\n");
-       printk(KERN_INFO " %5d %5X %5X\n", 0,
-              rx_ring->next_to_use, rx_ring->next_to_clean);
+       pr_info("Queue [NTU] [NTC]\n");
+       pr_info(" %5d %5X %5X\n",
+               0, rx_ring->next_to_use, rx_ring->next_to_clean);
 
        /* Print Rx Ring */
        if (!netif_msg_rx_status(adapter))
@@ -337,10 +327,7 @@ rx_ring_summary:
                 * 24 |                Buffer Address 3 [63:0]              |
                 *    +-----------------------------------------------------+
                 */
-               printk(KERN_INFO "R  [desc]      [buffer 0 63:0 ] "
-                      "[buffer 1 63:0 ] "
-                      "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
-                      "[bi->skb] <-- Ext Pkt Split format\n");
+               pr_info("R  [desc]      [buffer 0 63:0 ] [buffer 1 63:0 ] [buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] [bi->skb] <-- Ext Pkt Split format\n");
                /* [Extended] Receive Descriptor (Write-Back) Format
                 *
                 *   63       48 47    32 31     13 12    8 7    4 3        0
@@ -352,35 +339,40 @@ rx_ring_summary:
                 *   +------------------------------------------------------+
                 *   63       48 47    32 31            20 19               0
                 */
-               printk(KERN_INFO "RWB[desc]      [ck ipid mrqhsh] "
-                      "[vl   l0 ee  es] "
-                      "[ l3  l2  l1 hs] [reserved      ] ---------------- "
-                      "[bi->skb] <-- Ext Rx Write-Back format\n");
+               pr_info("RWB[desc]      [ck ipid mrqhsh] [vl   l0 ee  es] [ l3  l2  l1 hs] [reserved      ] ---------------- [bi->skb] <-- Ext Rx Write-Back format\n");
                for (i = 0; i < rx_ring->count; i++) {
+                       const char *next_desc;
                        buffer_info = &rx_ring->buffer_info[i];
                        rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
                        u1 = (struct my_u1 *)rx_desc_ps;
                        staterr =
                            le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+
+                       if (i == rx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == rx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                      "%016llX %016llX %016llX "
-                                      "---------------- %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      (unsigned long long)le64_to_cpu(u1->c),
-                                      (unsigned long long)le64_to_cpu(u1->d),
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX %016llX ---------------- %p%s\n",
+                                       "RWB", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       (unsigned long long)le64_to_cpu(u1->c),
+                                       (unsigned long long)le64_to_cpu(u1->d),
+                                       buffer_info->skb, next_desc);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                      "%016llX %016llX %016llX %016llX %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      (unsigned long long)le64_to_cpu(u1->c),
-                                      (unsigned long long)le64_to_cpu(u1->d),
-                                      (unsigned long long)buffer_info->dma,
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX %016llX %016llX %p%s\n",
+                                       "R  ", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       (unsigned long long)le64_to_cpu(u1->c),
+                                       (unsigned long long)le64_to_cpu(u1->d),
+                                       (unsigned long long)buffer_info->dma,
+                                       buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter))
                                        print_hex_dump(KERN_INFO, "",
@@ -388,13 +380,6 @@ rx_ring_summary:
                                                phys_to_virt(buffer_info->dma),
                                                adapter->rx_ps_bsize0, true);
                        }
-
-                       if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
                }
                break;
        default:
@@ -407,9 +392,7 @@ rx_ring_summary:
                 * 8 |                      Reserved                       |
                 *   +-----------------------------------------------------+
                 */
-               printk(KERN_INFO "R  [desc]      [buf addr 63:0 ] "
-                      "[reserved 63:0 ] [bi->dma       ] "
-                      "[bi->skb] <-- Ext (Read) format\n");
+               pr_info("R  [desc]      [buf addr 63:0 ] [reserved 63:0 ] [bi->dma       ] [bi->skb] <-- Ext (Read) format\n");
                /* Extended Receive Descriptor (Write-Back) Format
                 *
                 *   63       48 47    32 31    24 23            4 3        0
@@ -423,29 +406,37 @@ rx_ring_summary:
                 *   +------------------------------------------------------+
                 *   63       48 47    32 31            20 19               0
                 */
-               printk(KERN_INFO "RWB[desc]      [cs ipid    mrq] "
-                      "[vt   ln xe  xs] "
-                      "[bi->skb] <-- Ext (Write-Back) format\n");
+               pr_info("RWB[desc]      [cs ipid    mrq] [vt   ln xe  xs] [bi->skb] <-- Ext (Write-Back) format\n");
 
                for (i = 0; i < rx_ring->count; i++) {
+                       const char *next_desc;
+
                        buffer_info = &rx_ring->buffer_info[i];
                        rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
                        u1 = (struct my_u1 *)rx_desc;
                        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+                       if (i == rx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == rx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                      "%016llX ---------------- %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX ---------------- %p%s\n",
+                                       "RWB", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       buffer_info->skb, next_desc);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                      "%016llX %016llX %p", i,
-                                      (unsigned long long)le64_to_cpu(u1->a),
-                                      (unsigned long long)le64_to_cpu(u1->b),
-                                      (unsigned long long)buffer_info->dma,
-                                      buffer_info->skb);
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX %p%s\n",
+                                       "R  ", i,
+                                       (unsigned long long)le64_to_cpu(u1->a),
+                                       (unsigned long long)le64_to_cpu(u1->b),
+                                       (unsigned long long)buffer_info->dma,
+                                       buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter))
                                        print_hex_dump(KERN_INFO, "",
@@ -456,13 +447,6 @@ rx_ring_summary:
                                                       adapter->rx_buffer_len,
                                                       true);
                        }
-
-                       if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
                }
        }
 
@@ -1222,8 +1206,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                        adapter->flags2 |= FLAG2_IS_DISCARDING;
 
                if (adapter->flags2 & FLAG2_IS_DISCARDING) {
-                       e_dbg("Packet Split buffers didn't pick up the full "
-                             "packet\n");
+                       e_dbg("Packet Split buffers didn't pick up the full packet\n");
                        dev_kfree_skb_irq(skb);
                        if (staterr & E1000_RXD_STAT_EOP)
                                adapter->flags2 &= ~FLAG2_IS_DISCARDING;
@@ -1238,8 +1221,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                length = le16_to_cpu(rx_desc->wb.middle.length0);
 
                if (!length) {
-                       e_dbg("Last part of the packet spanning multiple "
-                             "descriptors\n");
+                       e_dbg("Last part of the packet spanning multiple descriptors\n");
                        dev_kfree_skb_irq(skb);
                        goto next_desc;
                }
@@ -1917,8 +1899,7 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
                                        return;
                        }
                        /* MSI-X failed, so fall through and try MSI */
-                       e_err("Failed to initialize MSI-X interrupts.  "
-                             "Falling back to MSI interrupts.\n");
+                       e_err("Failed to initialize MSI-X interrupts.  Falling back to MSI interrupts.\n");
                        e1000e_reset_interrupt_capability(adapter);
                }
                adapter->int_mode = E1000E_INT_MODE_MSI;
@@ -1928,8 +1909,7 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
                        adapter->flags |= FLAG_MSI_ENABLED;
                } else {
                        adapter->int_mode = E1000E_INT_MODE_LEGACY;
-                       e_err("Failed to initialize MSI interrupts.  Falling "
-                             "back to legacy interrupts.\n");
+                       e_err("Failed to initialize MSI interrupts.  Falling back to legacy interrupts.\n");
                }
                /* Fall through */
        case E1000E_INT_MODE_LEGACY:
@@ -3113,79 +3093,147 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 }
 
 /**
- *  e1000_update_mc_addr_list - Update Multicast addresses
- *  @hw: pointer to the HW structure
- *  @mc_addr_list: array of multicast addresses to program
- *  @mc_addr_count: number of multicast addresses to program
+ * e1000e_write_mc_addr_list - write multicast addresses to MTA
+ * @netdev: network interface device structure
+ *
+ * Writes multicast address list to the MTA hash table.
+ * Returns: -ENOMEM on failure
+ *                0 on no addresses written
+ *                X on writing X addresses to MTA
+ */
+static int e1000e_write_mc_addr_list(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       struct netdev_hw_addr *ha;
+       u8 *mta_list;
+       int i;
+
+       if (netdev_mc_empty(netdev)) {
+               /* nothing to program, so clear mc list */
+               hw->mac.ops.update_mc_addr_list(hw, NULL, 0);
+               return 0;
+       }
+
+       mta_list = kzalloc(netdev_mc_count(netdev) * ETH_ALEN, GFP_ATOMIC);
+       if (!mta_list)
+               return -ENOMEM;
+
+       /* update_mc_addr_list expects a packed array of only addresses. */
+       i = 0;
+       netdev_for_each_mc_addr(ha, netdev)
+               memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
+
+       hw->mac.ops.update_mc_addr_list(hw, mta_list, i);
+       kfree(mta_list);
+
+       return netdev_mc_count(netdev);
+}
+
+/**
+ * e1000e_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
  *
- *  Updates the Multicast Table Array.
- *  The caller must have a packed mc_addr_list of multicast addresses.
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ *                0 on no addresses written
+ *                X on writing X addresses to the RAR table
  **/
-static void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list,
-                                     u32 mc_addr_count)
+static int e1000e_write_uc_addr_list(struct net_device *netdev)
 {
-       hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, mc_addr_count);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       unsigned int rar_entries = hw->mac.rar_entry_count;
+       int count = 0;
+
+       /* save a rar entry for our hardware address */
+       rar_entries--;
+
+       /* save a rar entry for the LAA workaround */
+       if (adapter->flags & FLAG_RESET_OVERWRITES_LAA)
+               rar_entries--;
+
+       /* return ENOMEM indicating insufficient memory for addresses */
+       if (netdev_uc_count(netdev) > rar_entries)
+               return -ENOMEM;
+
+       if (!netdev_uc_empty(netdev) && rar_entries) {
+               struct netdev_hw_addr *ha;
+
+               /*
+                * write the addresses in reverse order to avoid write
+                * combining
+                */
+               netdev_for_each_uc_addr(ha, netdev) {
+                       if (!rar_entries)
+                               break;
+                       e1000e_rar_set(hw, ha->addr, rar_entries--);
+                       count++;
+               }
+       }
+
+       /* zero out the remaining RAR entries not used above */
+       for (; rar_entries > 0; rar_entries--) {
+               ew32(RAH(rar_entries), 0);
+               ew32(RAL(rar_entries), 0);
+       }
+       e1e_flush();
+
+       return count;
 }
 
 /**
- * e1000_set_multi - Multicast and Promiscuous mode set
+ * e1000e_set_rx_mode - secondary unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
  *
- * The set_multi entry point is called whenever the multicast address
- * list or the network interface flags are updated.  This routine is
- * responsible for configuring the hardware for proper multicast,
+ * The ndo_set_rx_mode entry point is called whenever the unicast or multicast
+ * address list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper unicast, multicast,
  * promiscuous mode, and all-multi behavior.
  **/
-static void e1000_set_multi(struct net_device *netdev)
+static void e1000e_set_rx_mode(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct netdev_hw_addr *ha;
-       u8  *mta_list;
        u32 rctl;
 
        /* Check for Promiscuous and All Multicast modes */
-
        rctl = er32(RCTL);
 
+       /* clear the affected bits */
+       rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+
        if (netdev->flags & IFF_PROMISC) {
                rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
-               rctl &= ~E1000_RCTL_VFE;
                /* Do not hardware filter VLANs in promisc mode */
                e1000e_vlan_filter_disable(adapter);
        } else {
+               int count;
                if (netdev->flags & IFF_ALLMULTI) {
                        rctl |= E1000_RCTL_MPE;
-                       rctl &= ~E1000_RCTL_UPE;
                } else {
-                       rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+                       /*
+                        * Write addresses to the MTA, if the attempt fails
+                        * then we should just turn on promiscuous mode so
+                        * that we can at least receive multicast traffic
+                        */
+                       count = e1000e_write_mc_addr_list(netdev);
+                       if (count < 0)
+                               rctl |= E1000_RCTL_MPE;
                }
                e1000e_vlan_filter_enable(adapter);
-       }
-
-       ew32(RCTL, rctl);
-
-       if (!netdev_mc_empty(netdev)) {
-               int i = 0;
-
-               mta_list = kmalloc(netdev_mc_count(netdev) * 6, GFP_ATOMIC);
-               if (!mta_list)
-                       return;
-
-               /* prepare a packed array of only addresses. */
-               netdev_for_each_mc_addr(ha, netdev)
-                       memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
-
-               e1000_update_mc_addr_list(hw, mta_list, i);
-               kfree(mta_list);
-       } else {
                /*
-                * if we're called from probe, we might not have
-                * anything to do here, so clear out the list
+                * Write addresses to available RAR registers, if there is not
+                * sufficient space to store all the addresses then enable
+                * unicast promiscuous mode
                 */
-               e1000_update_mc_addr_list(hw, NULL, 0);
+               count = e1000e_write_uc_addr_list(netdev);
+               if (count < 0)
+                       rctl |= E1000_RCTL_UPE;
        }
 
+       ew32(RCTL, rctl);
+
        if (netdev->features & NETIF_F_HW_VLAN_RX)
                e1000e_vlan_strip_enable(adapter);
        else
@@ -3198,7 +3246,7 @@ static void e1000_set_multi(struct net_device *netdev)
  **/
 static void e1000_configure(struct e1000_adapter *adapter)
 {
-       e1000_set_multi(adapter->netdev);
+       e1000e_set_rx_mode(adapter->netdev);
 
        e1000_restore_vlan(adapter);
        e1000_init_manageability_pt(adapter);
@@ -4168,16 +4216,13 @@ static void e1000_print_link_info(struct e1000_adapter *adapter)
        u32 ctrl = er32(CTRL);
 
        /* Link status message must follow this format for user tools */
-       printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s, "
-              "Flow Control: %s\n",
-              adapter->netdev->name,
-              adapter->link_speed,
-              (adapter->link_duplex == FULL_DUPLEX) ?
-              "Full Duplex" : "Half Duplex",
-              ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
-              "Rx/Tx" :
-              ((ctrl & E1000_CTRL_RFCE) ? "Rx" :
-               ((ctrl & E1000_CTRL_TFCE) ? "Tx" : "None")));
+       printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s Duplex, Flow Control: %s\n",
+               adapter->netdev->name,
+               adapter->link_speed,
+               adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half",
+               (ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE) ? "Rx/Tx" :
+               (ctrl & E1000_CTRL_RFCE) ? "Rx" :
+               (ctrl & E1000_CTRL_TFCE) ? "Tx" : "None");
 }
 
 static bool e1000e_has_link(struct e1000_adapter *adapter)
@@ -4323,10 +4368,7 @@ static void e1000_watchdog_task(struct work_struct *work)
                                e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp);
 
                                if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
-                                       e_info("Autonegotiated half duplex but"
-                                              " link partner cannot autoneg. "
-                                              " Try forcing full duplex if "
-                                              "link gets many collisions.\n");
+                                       e_info("Autonegotiated half duplex but link partner cannot autoneg.  Try forcing full duplex if link gets many collisions.\n");
                        }
 
                        /* adjust timeout factor according to speed/duplex */
@@ -5110,8 +5152,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        if ((adapter->hw.mac.type == e1000_pch2lan) &&
            !(adapter->flags2 & FLAG2_CRC_STRIPPING) &&
            (new_mtu > ETH_DATA_LEN)) {
-               e_err("Jumbo Frames not supported on 82579 when CRC "
-                     "stripping is disabled.\n");
+               e_err("Jumbo Frames not supported on 82579 when CRC stripping is disabled.\n");
                return -EINVAL;
        }
 
@@ -5331,7 +5372,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,
 
        if (wufc) {
                e1000_setup_rctl(adapter);
-               e1000_set_multi(netdev);
+               e1000e_set_rx_mode(netdev);
 
                /* turn on all-multi mode if wake on multicast is enabled */
                if (wufc & E1000_WUFC_MC) {
@@ -5527,8 +5568,8 @@ static int __e1000_resume(struct pci_dev *pdev)
                                phy_data & E1000_WUS_MC ? "Multicast Packet" :
                                phy_data & E1000_WUS_BC ? "Broadcast Packet" :
                                phy_data & E1000_WUS_MAG ? "Magic Packet" :
-                               phy_data & E1000_WUS_LNKC ? "Link Status "
-                               " Change" : "other");
+                               phy_data & E1000_WUS_LNKC ?
+                               "Link Status Change" : "other");
                }
                e1e_wphy(&adapter->hw, BM_WUS, ~0);
        } else {
@@ -5859,10 +5900,11 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
        }
 }
 
-static int e1000_set_features(struct net_device *netdev, u32 features)
+static int e1000_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (changed & (NETIF_F_TSO | NETIF_F_TSO6))
                adapter->flags |= FLAG_TSO_FORCE;
@@ -5884,7 +5926,7 @@ static const struct net_device_ops e1000e_netdev_ops = {
        .ndo_stop               = e1000_close,
        .ndo_start_xmit         = e1000_xmit_frame,
        .ndo_get_stats64        = e1000e_get_stats64,
-       .ndo_set_rx_mode        = e1000_set_multi,
+       .ndo_set_rx_mode        = e1000e_set_rx_mode,
        .ndo_set_mac_address    = e1000_set_mac,
        .ndo_change_mtu         = e1000_change_mtu,
        .ndo_do_ioctl           = e1000_ioctl,
@@ -5949,8 +5991,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                        err = dma_set_coherent_mask(&pdev->dev,
                                                    DMA_BIT_MASK(32));
                        if (err) {
-                               dev_err(&pdev->dev, "No usable DMA "
-                                       "configuration, aborting\n");
+                               dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
                                goto err_dma;
                        }
                }
@@ -6076,6 +6117,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                                  NETIF_F_TSO6 |
                                  NETIF_F_HW_CSUM);
 
+       netdev->priv_flags |= IFF_UNICAST_FLT;
+
        if (pci_using_dac) {
                netdev->features |= NETIF_F_HIGHDMA;
                netdev->vlan_features |= NETIF_F_HIGHDMA;
index 7881fb95a25ba51d6986621e125e0cadc4f09768..b8e20f037d0a8314789f236a31b4f723ef549b72 100644 (file)
@@ -29,6 +29,8 @@
  * e1000_82576
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/if_ether.h>
 
@@ -244,8 +246,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
         * Check for invalid size
         */
        if ((hw->mac.type == e1000_82576) && (size > 15)) {
-               printk("igb: The NVM size is not valid, "
-                       "defaulting to 32K.\n");
+               pr_notice("The NVM size is not valid, defaulting to 32K\n");
                size = 15;
        }
        nvm->word_size = 1 << size;
index 43873eba2f63eaa157980b078e14c6d56f6d2885..e9335efac386bd2faa331f797bc57f0139a0fc09 100644 (file)
@@ -673,25 +673,22 @@ static void igb_get_drvinfo(struct net_device *netdev,
                            struct ethtool_drvinfo *drvinfo)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
        u16 eeprom_data;
 
-       strncpy(drvinfo->driver,  igb_driver_name, sizeof(drvinfo->driver) - 1);
-       strncpy(drvinfo->version, igb_driver_version,
-               sizeof(drvinfo->version) - 1);
+       strlcpy(drvinfo->driver,  igb_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, igb_driver_version, sizeof(drvinfo->version));
 
        /* EEPROM image version # is reported as firmware version # for
         * 82575 controllers */
        adapter->hw.nvm.ops.read(&adapter->hw, 5, 1, &eeprom_data);
-       sprintf(firmware_version, "%d.%d-%d",
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d-%d",
                (eeprom_data & 0xF000) >> 12,
                (eeprom_data & 0x0FF0) >> 4,
                eeprom_data & 0x000F);
 
-       strncpy(drvinfo->fw_version, firmware_version,
-               sizeof(drvinfo->fw_version) - 1);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               sizeof(drvinfo->bus_info) - 1);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IGB_STATS_LEN;
        drvinfo->testinfo_len = IGB_TEST_LEN;
        drvinfo->regdump_len = igb_get_regs_len(netdev);
index ced544499f1b0a8a3e7625dd88719bbc5592563f..bd9b30e6ae9d0bdb0bc74e18c3f109465c14d368 100644 (file)
@@ -25,6 +25,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -145,7 +147,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *, int);
 static int igb_ioctl(struct net_device *, struct ifreq *, int cmd);
 static void igb_tx_timeout(struct net_device *);
 static void igb_reset_task(struct work_struct *);
-static void igb_vlan_mode(struct net_device *netdev, u32 features);
+static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features);
 static void igb_vlan_rx_add_vid(struct net_device *, u16);
 static void igb_vlan_rx_kill_vid(struct net_device *, u16);
 static void igb_restore_vlan(struct igb_adapter *);
@@ -325,16 +327,13 @@ static void igb_regdump(struct e1000_hw *hw, struct igb_reg_info *reginfo)
                        regs[n] = rd32(E1000_TXDCTL(n));
                break;
        default:
-               printk(KERN_INFO "%-15s %08x\n",
-                       reginfo->name, rd32(reginfo->ofs));
+               pr_info("%-15s %08x\n", reginfo->name, rd32(reginfo->ofs));
                return;
        }
 
        snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
-       printk(KERN_INFO "%-15s ", rname);
-       for (n = 0; n < 4; n++)
-               printk(KERN_CONT "%08x ", regs[n]);
-       printk(KERN_CONT "\n");
+       pr_info("%-15s %08x %08x %08x %08x\n", rname, regs[0], regs[1],
+               regs[2], regs[3]);
 }
 
 /*
@@ -359,18 +358,15 @@ static void igb_dump(struct igb_adapter *adapter)
        /* Print netdevice Info */
        if (netdev) {
                dev_info(&adapter->pdev->dev, "Net device Info\n");
-               printk(KERN_INFO "Device Name     state            "
-                       "trans_start      last_rx\n");
-               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
-               netdev->name,
-               netdev->state,
-               netdev->trans_start,
-               netdev->last_rx);
+               pr_info("Device Name     state            trans_start      "
+                       "last_rx\n");
+               pr_info("%-15s %016lX %016lX %016lX\n", netdev->name,
+                       netdev->state, netdev->trans_start, netdev->last_rx);
        }
 
        /* Print Registers */
        dev_info(&adapter->pdev->dev, "Register Dump\n");
-       printk(KERN_INFO " Register Name   Value\n");
+       pr_info(" Register Name   Value\n");
        for (reginfo = (struct igb_reg_info *)igb_reg_info_tbl;
             reginfo->name; reginfo++) {
                igb_regdump(hw, reginfo);
@@ -381,18 +377,17 @@ static void igb_dump(struct igb_adapter *adapter)
                goto exit;
 
        dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
-               " leng ntw timestamp\n");
+       pr_info("Queue [NTU] [NTC] [bi(ntc)->dma  ] leng ntw timestamp\n");
        for (n = 0; n < adapter->num_tx_queues; n++) {
                struct igb_tx_buffer *buffer_info;
                tx_ring = adapter->tx_ring[n];
                buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
-               printk(KERN_INFO " %5d %5X %5X %016llX %04X %p %016llX\n",
-                          n, tx_ring->next_to_use, tx_ring->next_to_clean,
-                          (u64)buffer_info->dma,
-                          buffer_info->length,
-                          buffer_info->next_to_watch,
-                          (u64)buffer_info->time_stamp);
+               pr_info(" %5d %5X %5X %016llX %04X %p %016llX\n",
+                       n, tx_ring->next_to_use, tx_ring->next_to_clean,
+                       (u64)buffer_info->dma,
+                       buffer_info->length,
+                       buffer_info->next_to_watch,
+                       (u64)buffer_info->time_stamp);
        }
 
        /* Print TX Rings */
@@ -414,36 +409,38 @@ static void igb_dump(struct igb_adapter *adapter)
 
        for (n = 0; n < adapter->num_tx_queues; n++) {
                tx_ring = adapter->tx_ring[n];
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "T [desc]     [address 63:0  ] "
-                       "[PlPOCIStDDM Ln] [bi->dma       ] "
-                       "leng  ntw timestamp        bi->skb\n");
+               pr_info("------------------------------------\n");
+               pr_info("TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+               pr_info("------------------------------------\n");
+               pr_info("T [desc]     [address 63:0  ] [PlPOCIStDDM Ln] "
+                       "[bi->dma       ] leng  ntw timestamp        "
+                       "bi->skb\n");
 
                for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+                       const char *next_desc;
                        struct igb_tx_buffer *buffer_info;
                        tx_desc = IGB_TX_DESC(tx_ring, i);
                        buffer_info = &tx_ring->tx_buffer_info[i];
                        u0 = (struct my_u0 *)tx_desc;
-                       printk(KERN_INFO "T [0x%03X]    %016llX %016llX %016llX"
-                               " %04X  %p %016llX %p", i,
+                       if (i == tx_ring->next_to_use &&
+                           i == tx_ring->next_to_clean)
+                               next_desc = " NTC/U";
+                       else if (i == tx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == tx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
+                       pr_info("T [0x%03X]    %016llX %016llX %016llX"
+                               " %04X  %p %016llX %p%s\n", i,
                                le64_to_cpu(u0->a),
                                le64_to_cpu(u0->b),
                                (u64)buffer_info->dma,
                                buffer_info->length,
                                buffer_info->next_to_watch,
                                (u64)buffer_info->time_stamp,
-                               buffer_info->skb);
-                       if (i == tx_ring->next_to_use &&
-                               i == tx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC/U\n");
-                       else if (i == tx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == tx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
+                               buffer_info->skb, next_desc);
 
                        if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
                                print_hex_dump(KERN_INFO, "",
@@ -456,11 +453,11 @@ static void igb_dump(struct igb_adapter *adapter)
        /* Print RX Rings Summary */
 rx_ring_summary:
        dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
-       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       pr_info("Queue [NTU] [NTC]\n");
        for (n = 0; n < adapter->num_rx_queues; n++) {
                rx_ring = adapter->rx_ring[n];
-               printk(KERN_INFO " %5d %5X %5X\n", n,
-                          rx_ring->next_to_use, rx_ring->next_to_clean);
+               pr_info(" %5d %5X %5X\n",
+                       n, rx_ring->next_to_use, rx_ring->next_to_clean);
        }
 
        /* Print RX Rings */
@@ -492,36 +489,43 @@ rx_ring_summary:
 
        for (n = 0; n < adapter->num_rx_queues; n++) {
                rx_ring = adapter->rx_ring[n];
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
-               printk(KERN_INFO "------------------------------------\n");
-               printk(KERN_INFO "R  [desc]      [ PktBuf     A0] "
-                       "[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
-                       "<-- Adv Rx Read format\n");
-               printk(KERN_INFO "RWB[desc]      [PcsmIpSHl PtRs] "
-                       "[vl er S cks ln] ---------------- [bi->skb] "
-                       "<-- Adv Rx Write-Back format\n");
+               pr_info("------------------------------------\n");
+               pr_info("RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+               pr_info("------------------------------------\n");
+               pr_info("R  [desc]      [ PktBuf     A0] [  HeadBuf   DD] "
+                       "[bi->dma       ] [bi->skb] <-- Adv Rx Read format\n");
+               pr_info("RWB[desc]      [PcsmIpSHl PtRs] [vl er S cks ln] -----"
+                       "----------- [bi->skb] <-- Adv Rx Write-Back format\n");
 
                for (i = 0; i < rx_ring->count; i++) {
+                       const char *next_desc;
                        struct igb_rx_buffer *buffer_info;
                        buffer_info = &rx_ring->rx_buffer_info[i];
                        rx_desc = IGB_RX_DESC(rx_ring, i);
                        u0 = (struct my_u0 *)rx_desc;
                        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+
+                       if (i == rx_ring->next_to_use)
+                               next_desc = " NTU";
+                       else if (i == rx_ring->next_to_clean)
+                               next_desc = " NTC";
+                       else
+                               next_desc = "";
+
                        if (staterr & E1000_RXD_STAT_DD) {
                                /* Descriptor Done */
-                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
-                                       "%016llX ---------------- %p", i,
+                               pr_info("%s[0x%03X]     %016llX %016llX -------"
+                                       "--------- %p%s\n", "RWB", i,
                                        le64_to_cpu(u0->a),
                                        le64_to_cpu(u0->b),
-                                       buffer_info->skb);
+                                       buffer_info->skb, next_desc);
                        } else {
-                               printk(KERN_INFO "R  [0x%03X]     %016llX "
-                                       "%016llX %016llX %p", i,
+                               pr_info("%s[0x%03X]     %016llX %016llX %016llX"
+                                       " %p%s\n", "R  ", i,
                                        le64_to_cpu(u0->a),
                                        le64_to_cpu(u0->b),
                                        (u64)buffer_info->dma,
-                                       buffer_info->skb);
+                                       buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter)) {
                                        print_hex_dump(KERN_INFO, "",
@@ -538,14 +542,6 @@ rx_ring_summary:
                                          PAGE_SIZE/2, true);
                                }
                        }
-
-                       if (i == rx_ring->next_to_use)
-                               printk(KERN_CONT " NTU\n");
-                       else if (i == rx_ring->next_to_clean)
-                               printk(KERN_CONT " NTC\n");
-                       else
-                               printk(KERN_CONT "\n");
-
                }
        }
 
@@ -599,10 +595,10 @@ struct net_device *igb_get_hw_dev(struct e1000_hw *hw)
 static int __init igb_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "%s - version %s\n",
+       pr_info("%s - version %s\n",
               igb_driver_string, igb_driver_version);
 
-       printk(KERN_INFO "%s\n", igb_copyright);
+       pr_info("%s\n", igb_copyright);
 
 #ifdef CONFIG_IGB_DCA
        dca_register_notify(&dca_notifier);
@@ -1742,7 +1738,8 @@ void igb_reset(struct igb_adapter *adapter)
        igb_get_phy_info(hw);
 }
 
-static u32 igb_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t igb_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -1756,9 +1753,10 @@ static u32 igb_fix_features(struct net_device *netdev, u32 features)
        return features;
 }
 
-static int igb_set_features(struct net_device *netdev, u32 features)
+static int igb_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                igb_vlan_mode(netdev, features);
@@ -3640,23 +3638,23 @@ static void igb_watchdog_task(struct work_struct *work)
 
                        ctrl = rd32(E1000_CTRL);
                        /* Links status message must follow this format */
-                       printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s, "
-                                "Flow Control: %s\n",
+                       printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s "
+                              "Duplex, Flow Control: %s\n",
                               netdev->name,
                               adapter->link_speed,
                               adapter->link_duplex == FULL_DUPLEX ?
-                                "Full Duplex" : "Half Duplex",
-                              ((ctrl & E1000_CTRL_TFCE) &&
-                               (ctrl & E1000_CTRL_RFCE)) ? "RX/TX" :
-                              ((ctrl & E1000_CTRL_RFCE) ?  "RX" :
-                              ((ctrl & E1000_CTRL_TFCE) ?  "TX" : "None")));
+                              "Full" : "Half",
+                              (ctrl & E1000_CTRL_TFCE) &&
+                              (ctrl & E1000_CTRL_RFCE) ? "RX/TX" :
+                              (ctrl & E1000_CTRL_RFCE) ?  "RX" :
+                              (ctrl & E1000_CTRL_TFCE) ?  "TX" : "None");
 
                        /* check for thermal sensor event */
-                       if (igb_thermal_sensor_event(hw, E1000_THSTAT_LINK_THROTTLE)) {
-                               printk(KERN_INFO "igb: %s The network adapter "
-                                                "link speed was downshifted "
-                                                "because it overheated.\n",
-                                                netdev->name);
+                       if (igb_thermal_sensor_event(hw,
+                           E1000_THSTAT_LINK_THROTTLE)) {
+                               netdev_info(netdev, "The network adapter link "
+                                           "speed was downshifted because it "
+                                           "overheated\n");
                        }
 
                        /* adjust timeout factor according to speed/duplex */
@@ -3686,11 +3684,10 @@ static void igb_watchdog_task(struct work_struct *work)
                        adapter->link_duplex = 0;
 
                        /* check for thermal sensor event */
-                       if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) {
-                               printk(KERN_ERR "igb: %s The network adapter "
-                                               "was stopped because it "
-                                               "overheated.\n",
-                                               netdev->name);
+                       if (igb_thermal_sensor_event(hw,
+                           E1000_THSTAT_PWR_DOWN)) {
+                               netdev_err(netdev, "The network adapter was "
+                                          "stopped because it overheated\n");
                        }
 
                        /* Links status message must follow this format */
@@ -6467,7 +6464,7 @@ s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
        return 0;
 }
 
-static void igb_vlan_mode(struct net_device *netdev, u32 features)
+static void igb_vlan_mode(struct net_device *netdev, netdev_features_t features)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
index 2c25858cc0ff8f26b8000333caf832662edf5fff..e60f1c6957af9396679b40d67489573c732bacd6 100644 (file)
@@ -191,12 +191,14 @@ static void igbvf_get_drvinfo(struct net_device *netdev,
                               struct ethtool_drvinfo *drvinfo)
 {
        struct igbvf_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32] = "N/A";
 
-       strncpy(drvinfo->driver,  igbvf_driver_name, 32);
-       strncpy(drvinfo->version, igbvf_driver_version, 32);
-       strncpy(drvinfo->fw_version, firmware_version, 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  igbvf_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, igbvf_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A",
+               sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = igbvf_get_regs_len(netdev);
        drvinfo->eedump_len = igbvf_get_eeprom_len(netdev);
 }
index cca78124be316b12855a5367425cfd4251df3d55..c358973ce4149940a692b03bb1d5afdb5ed62c02 100644 (file)
@@ -25,6 +25,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -1746,10 +1748,9 @@ void igbvf_update_stats(struct igbvf_adapter *adapter)
 
 static void igbvf_print_link_info(struct igbvf_adapter *adapter)
 {
-       dev_info(&adapter->pdev->dev, "Link is Up %d Mbps %s\n",
-                adapter->link_speed,
-                ((adapter->link_duplex == FULL_DUPLEX) ?
-                 "Full Duplex" : "Half Duplex"));
+       dev_info(&adapter->pdev->dev, "Link is Up %d Mbps %s Duplex\n",
+                adapter->link_speed,
+                adapter->link_duplex == FULL_DUPLEX ? "Full" : "Half");
 }
 
 static bool igbvf_has_link(struct igbvf_adapter *adapter)
@@ -2532,7 +2533,8 @@ static void igbvf_print_device_info(struct igbvf_adapter *adapter)
        dev_info(&pdev->dev, "Address: %pM\n", netdev->dev_addr);
 }
 
-static int igbvf_set_features(struct net_device *netdev, u32 features)
+static int igbvf_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct igbvf_adapter *adapter = netdev_priv(netdev);
 
@@ -2842,9 +2844,8 @@ static struct pci_driver igbvf_driver = {
 static int __init igbvf_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "%s - version %s\n",
-              igbvf_driver_string, igbvf_driver_version);
-       printk(KERN_INFO "%s\n", igbvf_copyright);
+       pr_info("%s - version %s\n", igbvf_driver_string, igbvf_driver_version);
+       pr_info("%s\n", igbvf_copyright);
 
        ret = pci_register_driver(&igbvf_driver);
 
index 9dfce7dff79b8e54c8c710e33f9b7ce1f503b7ea..96fcb0e064503644cdb4affb4377d1e0c8eff247 100644 (file)
@@ -473,10 +473,13 @@ ixgb_get_drvinfo(struct net_device *netdev,
 {
        struct ixgb_adapter *adapter = netdev_priv(netdev);
 
-       strncpy(drvinfo->driver,  ixgb_driver_name, 32);
-       strncpy(drvinfo->version, ixgb_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->driver,  ixgb_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ixgb_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IXGB_STATS_LEN;
        drvinfo->regdump_len = ixgb_get_regs_len(netdev);
        drvinfo->eedump_len = ixgb_get_eeprom_len(netdev);
index e21148f8b1607d02b9054435e3e013c9f6a75374..247cf9219e034817d44cd5e4b6a19e230cb865f2 100644 (file)
@@ -325,8 +325,8 @@ ixgb_reset(struct ixgb_adapter *adapter)
        }
 }
 
-static u32
-ixgb_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t
+ixgb_fix_features(struct net_device *netdev, netdev_features_t features)
 {
        /*
         * Tx VLAN insertion does not work per HW design when Rx stripping is
@@ -339,10 +339,10 @@ ixgb_fix_features(struct net_device *netdev, u32 features)
 }
 
 static int
-ixgb_set_features(struct net_device *netdev, u32 features)
+ixgb_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct ixgb_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_RX)))
                return 0;
index 70d58c3849b0592fa767319a0f14c5551330f15a..91f871b6b3baec62a867333d28f4a979ab4157d5 100644 (file)
@@ -888,23 +888,19 @@ static void ixgbe_get_drvinfo(struct net_device *netdev,
                               struct ethtool_drvinfo *drvinfo)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       char firmware_version[32];
        u32 nvm_track_id;
 
-       strncpy(drvinfo->driver, ixgbe_driver_name,
-               sizeof(drvinfo->driver) - 1);
-       strncpy(drvinfo->version, ixgbe_driver_version,
-               sizeof(drvinfo->version) - 1);
+       strlcpy(drvinfo->driver, ixgbe_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ixgbe_driver_version,
+               sizeof(drvinfo->version));
 
        nvm_track_id = (adapter->eeprom_verh << 16) |
                        adapter->eeprom_verl;
-       snprintf(firmware_version, sizeof(firmware_version), "0x%08x",
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "0x%08x",
                 nvm_track_id);
 
-       strncpy(drvinfo->fw_version, firmware_version,
-               sizeof(drvinfo->fw_version) - 1);
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
-               sizeof(drvinfo->bus_info) - 1);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = IXGBE_STATS_LEN;
        drvinfo->testinfo_len = IXGBE_TEST_LEN;
        drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
index 8ef92d1a6aa126037c3ce9d1049a7fde3f766790..820fc040c241580229e10085fd76ef8f846fef17 100644 (file)
@@ -7174,7 +7174,8 @@ void ixgbe_do_reset(struct net_device *netdev)
                ixgbe_reset(adapter);
 }
 
-static u32 ixgbe_fix_features(struct net_device *netdev, u32 data)
+static netdev_features_t ixgbe_fix_features(struct net_device *netdev,
+       netdev_features_t data)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
 
@@ -7204,7 +7205,8 @@ static u32 ixgbe_fix_features(struct net_device *netdev, u32 data)
        return data;
 }
 
-static int ixgbe_set_features(struct net_device *netdev, u32 data)
+static int ixgbe_set_features(struct net_device *netdev,
+       netdev_features_t data)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        bool need_reset = false;
index 00fcd39ad666b6c289379e401800438347952dd7..cf6812dd1436116ab23beb0cf57b1ab7732c8b38 100644 (file)
@@ -572,7 +572,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
 
                /* reply to reset with ack and vf mac address */
                msgbuf[0] = IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK;
-               memcpy(new_mac, vf_mac, IXGBE_ETH_LENGTH_OF_ADDRESS);
+               memcpy(new_mac, vf_mac, ETH_ALEN);
                /*
                 * Piggyback the multicast filter type so VF can compute the
                 * correct vectors
index 6c5cca808bd7e492894e0225bf800861b4050793..242643a69b3f7cfc915373fce2ac47fe712ff1e7 100644 (file)
@@ -1710,8 +1710,6 @@ enum {
 #define IXGBE_NVM_POLL_WRITE       1  /* Flag for polling for write complete */
 #define IXGBE_NVM_POLL_READ        0  /* Flag for polling for read complete */
 
-#define IXGBE_ETH_LENGTH_OF_ADDRESS   6
-
 #define IXGBE_EEPROM_PAGE_SIZE_MAX       128
 #define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */
 #define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */
@@ -2802,9 +2800,9 @@ struct ixgbe_eeprom_info {
 struct ixgbe_mac_info {
        struct ixgbe_mac_operations     ops;
        enum ixgbe_mac_type             type;
-       u8                              addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
-       u8                              perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
-       u8                              san_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+       u8                              addr[ETH_ALEN];
+       u8                              perm_addr[ETH_ALEN];
+       u8                              san_addr[ETH_ALEN];
        /* prefix for World Wide Node Name (WWNN) */
        u16                             wwnn_prefix;
        /* prefix for World Wide Port Name (WWPN) */
index e5101e91b6b55dbc59b99cf710c3528f36035e34..8cc5eccfd65194a0a738b969f0f9b97529842d9f 100644 (file)
@@ -751,16 +751,20 @@ static s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index)
 {
        u32 macc_reg;
        u32 ledctl_reg;
+       ixgbe_link_speed speed;
+       bool link_up;
 
        /*
-        * In order for the blink bit in the LED control register
-        * to work, link and speed must be forced in the MAC. We
-        * will reverse this when we stop the blinking.
+        * Link should be up in order for the blink bit in the LED control
+        * register to work. Force link and speed in the MAC if link is down.
+        * This will be reversed when we stop the blinking.
         */
-       macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC);
-       macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS;
-       IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg);
-
+       hw->mac.ops.check_link(hw, &speed, &link_up, false);
+       if (link_up == false) {
+               macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC);
+               macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS;
+               IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg);
+       }
        /* Set the LED to LINK_UP + BLINK. */
        ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
        ledctl_reg &= ~IXGBE_LED_MODE_MASK(index);
index 78abb6f1a866d1190b7894b12c411e20c1128005..2eb89cb94a0d4c45a14831cda8e875878a4679e0 100644 (file)
@@ -35,7 +35,6 @@
 #define IXGBE_VF_IRQ_CLEAR_MASK         7
 #define IXGBE_VF_MAX_TX_QUEUES          1
 #define IXGBE_VF_MAX_RX_QUEUES          1
-#define IXGBE_ETH_LENGTH_OF_ADDRESS     6
 
 /* Link speed */
 typedef u32 ixgbe_link_speed;
index e29ba4506b74d4a3605e74bcb10f9262fb70c452..149fa520d7f2100dbb91e7bde9fe602e9f7df593 100644 (file)
@@ -27,6 +27,8 @@
 
 /* ethtool support for ixgbevf */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -549,8 +551,8 @@ static const u32 register_test_patterns[] = {
        writel((W & M), (adapter->hw.hw_addr + R));                           \
        val = readl(adapter->hw.hw_addr + R);                                 \
        if ((W & M) != (val & M)) {                                           \
-               printk(KERN_ERR "set/check reg %04X test failed: got 0x%08X " \
-                                "expected 0x%08X\n", R, (val & M), (W & M)); \
+               pr_err("set/check reg %04X test failed: got 0x%08X expected " \
+                      "0x%08X\n", R, (val & M), (W & M));                    \
                *data = R;                                                    \
                writel(before, (adapter->hw.hw_addr + R));                    \
                return 1;                                                     \
index 4c8e19951d57e58d53dedd3249c72d976413d020..0c39bb1ac3bb4462274779b0803eec5badbd60dc 100644 (file)
@@ -29,6 +29,9 @@
 /******************************************************************************
  Copyright (c)2006 - 2007 Myricom, Inc. for some LRO specific code
 ******************************************************************************/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
@@ -1437,7 +1440,7 @@ static int ixgbevf_write_uc_addr_list(struct net_device *netdev)
        int count = 0;
 
        if ((netdev_uc_count(netdev)) > 10) {
-               printk(KERN_ERR "Too many unicast filters - No Space\n");
+               pr_err("Too many unicast filters - No Space\n");
                return -ENOSPC;
        }
 
@@ -2135,7 +2138,7 @@ static int ixgbevf_init_interrupt_scheme(struct ixgbevf_adapter *adapter)
 
        err = ixgbevf_alloc_queues(adapter);
        if (err) {
-               printk(KERN_ERR "Unable to allocate memory for queues\n");
+               pr_err("Unable to allocate memory for queues\n");
                goto err_alloc_queues;
        }
 
@@ -2189,7 +2192,7 @@ static int __devinit ixgbevf_sw_init(struct ixgbevf_adapter *adapter)
        } else {
                err = hw->mac.ops.init_hw(hw);
                if (err) {
-                       printk(KERN_ERR "init_shared_code failed: %d\n", err);
+                       pr_err("init_shared_code failed: %d\n", err);
                        goto out;
                }
        }
@@ -2630,8 +2633,8 @@ static int ixgbevf_open(struct net_device *netdev)
                 * the vf can't start. */
                if (hw->adapter_stopped) {
                        err = IXGBE_ERR_MBX;
-                       printk(KERN_ERR "Unable to start - perhaps the PF"
-                              " Driver isn't up yet\n");
+                       pr_err("Unable to start - perhaps the PF Driver isn't "
+                              "up yet\n");
                        goto err_setup_reset;
                }
        }
@@ -2842,10 +2845,8 @@ static bool ixgbevf_tx_csum(struct ixgbevf_adapter *adapter,
                                break;
                        default:
                                if (unlikely(net_ratelimit())) {
-                                       printk(KERN_WARNING
-                                              "partial checksum but "
-                                              "proto=%x!\n",
-                                              skb->protocol);
+                                       pr_warn("partial checksum but "
+                                               "proto=%x!\n", skb->protocol);
                                }
                                break;
                        }
@@ -3249,7 +3250,8 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
        return stats;
 }
 
-static int ixgbevf_set_features(struct net_device *netdev, u32 features)
+static int ixgbevf_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 
@@ -3414,7 +3416,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
        memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
 
        if (!is_valid_ether_addr(netdev->dev_addr)) {
-               printk(KERN_ERR "invalid MAC address\n");
+               pr_err("invalid MAC address\n");
                err = -EIO;
                goto err_sw_init;
        }
@@ -3535,10 +3537,10 @@ static struct pci_driver ixgbevf_driver = {
 static int __init ixgbevf_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "ixgbevf: %s - version %s\n", ixgbevf_driver_string,
-              ixgbevf_driver_version);
+       pr_info("%s - version %s\n", ixgbevf_driver_string,
+               ixgbevf_driver_version);
 
-       printk(KERN_INFO "%s\n", ixgbevf_copyright);
+       pr_info("%s\n", ixgbevf_copyright);
 
        ret = pci_register_driver(&ixgbevf_driver);
        return ret;
index aa3682e8c473cc84bcf9c6bc0b7d17a12857854d..21533e300367f78dd4058ee2df7ba31c7df1122c 100644 (file)
@@ -108,7 +108,7 @@ static s32 ixgbevf_reset_hw_vf(struct ixgbe_hw *hw)
        if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK))
                return IXGBE_ERR_INVALID_MAC_ADDR;
 
-       memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+       memcpy(hw->mac.perm_addr, addr, ETH_ALEN);
        hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD];
 
        return 0;
@@ -211,7 +211,7 @@ static s32 ixgbevf_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
  **/
 static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr)
 {
-       memcpy(mac_addr, hw->mac.perm_addr, IXGBE_ETH_LENGTH_OF_ADDRESS);
+       memcpy(mac_addr, hw->mac.perm_addr, ETH_ALEN);
 
        return 0;
 }
index 7becff1f387d7c9d84fb26ab3db6f7299bb64f15..5c0b531949e200b26f8875d2dc46235773e312de 100644 (file)
@@ -1883,7 +1883,7 @@ jme_fill_tx_map(struct pci_dev *pdev,
                struct page *page,
                u32 page_offset,
                u32 len,
-               u8 hidma)
+               bool hidma)
 {
        dma_addr_t dmaaddr;
 
@@ -1917,7 +1917,7 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
        struct jme_ring *txring = &(jme->txring[0]);
        struct txdesc *txdesc = txring->desc, *ctxdesc;
        struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
-       u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
+       bool hidma = jme->dev->features & NETIF_F_HIGHDMA;
        int i, nr_frags = skb_shinfo(skb)->nr_frags;
        int mask = jme->tx_ring_mask;
        const struct skb_frag_struct *frag;
@@ -2292,9 +2292,9 @@ jme_get_drvinfo(struct net_device *netdev,
 {
        struct jme_adapter *jme = netdev_priv(netdev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(jme->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(jme->pdev), sizeof(info->bus_info));
 }
 
 static int
@@ -2620,8 +2620,8 @@ jme_set_msglevel(struct net_device *netdev, u32 value)
        jme->msg_enable = value;
 }
 
-static u32
-jme_fix_features(struct net_device *netdev, u32 features)
+static netdev_features_t
+jme_fix_features(struct net_device *netdev, netdev_features_t features)
 {
        if (netdev->mtu > 1900)
                features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM);
@@ -2629,7 +2629,7 @@ jme_fix_features(struct net_device *netdev, u32 features)
 }
 
 static int
-jme_set_features(struct net_device *netdev, u32 features)
+jme_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct jme_adapter *jme = netdev_priv(netdev);
 
index 194a03113802f80b67139e9c6fcfec6b3f523164..43e3e6102149965988228cb8fa3c3a81542e5e19 100644 (file)
@@ -1502,10 +1502,11 @@ mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 static void mv643xx_eth_get_drvinfo(struct net_device *dev,
                                    struct ethtool_drvinfo *drvinfo)
 {
-       strncpy(drvinfo->driver,  mv643xx_eth_driver_name, 32);
-       strncpy(drvinfo->version, mv643xx_eth_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, "platform", 32);
+       strlcpy(drvinfo->driver, mv643xx_eth_driver_name, sizeof(info->driver));
+       strlcpy(drvinfo->version, mv643xx_eth_driver_version,
+               sizeof(info->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(drvinfo->bus_info, "platform", sizeof(info->bus_info));
        drvinfo->n_stats = ARRAY_SIZE(mv643xx_eth_stats);
 }
 
@@ -1578,10 +1579,10 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
 
 
 static int
-mv643xx_eth_set_features(struct net_device *dev, u32 features)
+mv643xx_eth_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct mv643xx_eth_private *mp = netdev_priv(dev);
-       u32 rx_csum = features & NETIF_F_RXCSUM;
+       bool rx_csum = features & NETIF_F_RXCSUM;
 
        wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000);
 
index c7b60839ac9951caa4b3de0f0577bfd7d39bb1ca..3943f5f7bb4a429829ba8f9a38e088d38cc83f3e 100644 (file)
@@ -394,10 +394,11 @@ static void skge_get_drvinfo(struct net_device *dev,
 {
        struct skge_port *skge = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(skge->hw->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(skge->hw->pdev),
+               sizeof(info->bus_info));
 }
 
 static const struct skge_stat {
index 7803efa46eb26b4b9fb5465ea1cb1df15d26d8ed..ca33908bc7f3337ac34a2a5d0dd8aa6277d190a1 100644 (file)
@@ -1284,7 +1284,7 @@ static const uint32_t rss_init_key[10] = {
 };
 
 /* Enable/disable receive hash calculation (RSS) */
-static void rx_set_rss(struct net_device *dev, u32 features)
+static void rx_set_rss(struct net_device *dev, netdev_features_t features)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
@@ -1402,7 +1402,7 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 #define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO)
 
-static void sky2_vlan_mode(struct net_device *dev, u32 features)
+static void sky2_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
@@ -3643,10 +3643,11 @@ static void sky2_get_drvinfo(struct net_device *dev,
 {
        struct sky2_port *sky2 = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
-       strcpy(info->bus_info, pci_name(sky2->hw->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(sky2->hw->pdev),
+               sizeof(info->bus_info));
 }
 
 static const struct sky2_stat {
@@ -4311,7 +4312,8 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
        return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
-static u32 sky2_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t sky2_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        const struct sky2_port *sky2 = netdev_priv(dev);
        const struct sky2_hw *hw = sky2->hw;
@@ -4335,13 +4337,13 @@ static u32 sky2_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int sky2_set_features(struct net_device *dev, u32 features)
+static int sky2_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (changed & NETIF_F_RXCSUM) {
-               u32 on = features & NETIF_F_RXCSUM;
+               bool on = features & NETIF_F_RXCSUM;
                sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
                             on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
        }
index 74e2a2a8a02bb2e5b9af9d5bbaee623ac1b2e139..ee637a200915701171f39e15ba549a23a8e8f84a 100644 (file)
@@ -45,13 +45,16 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
 
-       strncpy(drvinfo->driver, DRV_NAME, 32);
-       strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32);
-       sprintf(drvinfo->fw_version, "%d.%d.%d",
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")",
+               sizeof(drvinfo->version));
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d",
                (u16) (mdev->dev->caps.fw_ver >> 32),
                (u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff),
                (u16) (mdev->dev->caps.fw_ver & 0xffff));
-       strncpy(drvinfo->bus_info, pci_name(mdev->dev->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(mdev->dev->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
index 7ece990381c8ff957fe4772a85ed4e71444de735..7abd510fe01fdfc70eded4da678c225f040d9645 100644 (file)
 /* Change default LED mode. */
 #define SET_DEFAULT_LED                        LED_SPEED_DUPLEX_ACT
 
-#define MAC_ADDR_LEN                   6
-#define MAC_ADDR_ORDER(i)              (MAC_ADDR_LEN - 1 - (i))
+#define MAC_ADDR_ORDER(i)              (ETH_ALEN - 1 - (i))
 
 #define MAX_ETHERNET_BODY_SIZE         1500
 #define ETHERNET_HEADER_SIZE           14
@@ -1043,7 +1042,7 @@ enum {
  * @valid:     Valid setting indicating the entry is being used.
  */
 struct ksz_mac_table {
-       u8 mac_addr[MAC_ADDR_LEN];
+       u8 mac_addr[ETH_ALEN];
        u16 vid;
        u8 fid;
        u8 ports;
@@ -1187,8 +1186,8 @@ struct ksz_switch {
        u8 diffserv[DIFFSERV_ENTRIES];
        u8 p_802_1p[PRIO_802_1P_ENTRIES];
 
-       u8 br_addr[MAC_ADDR_LEN];
-       u8 other_addr[MAC_ADDR_LEN];
+       u8 br_addr[ETH_ALEN];
+       u8 other_addr[ETH_ALEN];
 
        u8 broad_per;
        u8 member;
@@ -1292,14 +1291,14 @@ struct ksz_hw {
        int tx_int_mask;
        int tx_size;
 
-       u8 perm_addr[MAC_ADDR_LEN];
-       u8 override_addr[MAC_ADDR_LEN];
-       u8 address[ADDITIONAL_ENTRIES][MAC_ADDR_LEN];
+       u8 perm_addr[ETH_ALEN];
+       u8 override_addr[ETH_ALEN];
+       u8 address[ADDITIONAL_ENTRIES][ETH_ALEN];
        u8 addr_list_size;
        u8 mac_override;
        u8 promiscuous;
        u8 all_multi;
-       u8 multi_list[MAX_MULTICAST_LIST][MAC_ADDR_LEN];
+       u8 multi_list[MAX_MULTICAST_LIST][ETH_ALEN];
        u8 multi_bits[HW_MULTICAST_SIZE];
        u8 multi_list_size;
 
@@ -3654,7 +3653,7 @@ static void hw_add_wol_bcast(struct ksz_hw *hw)
        static const u8 mask[] = { 0x3F };
        static const u8 pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
-       hw_set_wol_frame(hw, 2, 1, mask, MAC_ADDR_LEN, pattern);
+       hw_set_wol_frame(hw, 2, 1, mask, ETH_ALEN, pattern);
 }
 
 /**
@@ -3689,7 +3688,7 @@ static void hw_add_wol_ucast(struct ksz_hw *hw)
 {
        static const u8 mask[] = { 0x3F };
 
-       hw_set_wol_frame(hw, 0, 1, mask, MAC_ADDR_LEN, hw->override_addr);
+       hw_set_wol_frame(hw, 0, 1, mask, ETH_ALEN, hw->override_addr);
 }
 
 /**
@@ -4055,7 +4054,7 @@ static void hw_set_addr(struct ksz_hw *hw)
 {
        int i;
 
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                writeb(hw->override_addr[MAC_ADDR_ORDER(i)],
                        hw->io + KS884X_ADDR_0_OFFSET + i);
 
@@ -4072,17 +4071,16 @@ static void hw_read_addr(struct ksz_hw *hw)
 {
        int i;
 
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                hw->perm_addr[MAC_ADDR_ORDER(i)] = readb(hw->io +
                        KS884X_ADDR_0_OFFSET + i);
 
        if (!hw->mac_override) {
-               memcpy(hw->override_addr, hw->perm_addr, MAC_ADDR_LEN);
+               memcpy(hw->override_addr, hw->perm_addr, ETH_ALEN);
                if (empty_addr(hw->override_addr)) {
-                       memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS,
-                               MAC_ADDR_LEN);
+                       memcpy(hw->perm_addr, DEFAULT_MAC_ADDRESS, ETH_ALEN);
                        memcpy(hw->override_addr, DEFAULT_MAC_ADDRESS,
-                               MAC_ADDR_LEN);
+                              ETH_ALEN);
                        hw->override_addr[5] += hw->id;
                        hw_set_addr(hw);
                }
@@ -4130,16 +4128,16 @@ static int hw_add_addr(struct ksz_hw *hw, u8 *mac_addr)
        int i;
        int j = ADDITIONAL_ENTRIES;
 
-       if (!memcmp(hw->override_addr, mac_addr, MAC_ADDR_LEN))
+       if (!memcmp(hw->override_addr, mac_addr, ETH_ALEN))
                return 0;
        for (i = 0; i < hw->addr_list_size; i++) {
-               if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN))
+               if (!memcmp(hw->address[i], mac_addr, ETH_ALEN))
                        return 0;
                if (ADDITIONAL_ENTRIES == j && empty_addr(hw->address[i]))
                        j = i;
        }
        if (j < ADDITIONAL_ENTRIES) {
-               memcpy(hw->address[j], mac_addr, MAC_ADDR_LEN);
+               memcpy(hw->address[j], mac_addr, ETH_ALEN);
                hw_ena_add_addr(hw, j, hw->address[j]);
                return 0;
        }
@@ -4151,8 +4149,8 @@ static int hw_del_addr(struct ksz_hw *hw, u8 *mac_addr)
        int i;
 
        for (i = 0; i < hw->addr_list_size; i++) {
-               if (!memcmp(hw->address[i], mac_addr, MAC_ADDR_LEN)) {
-                       memset(hw->address[i], 0, MAC_ADDR_LEN);
+               if (!memcmp(hw->address[i], mac_addr, ETH_ALEN)) {
+                       memset(hw->address[i], 0, ETH_ALEN);
                        writel(0, hw->io + ADD_ADDR_INCR * i +
                                KS_ADD_ADDR_0_HI);
                        return 0;
@@ -5676,7 +5674,7 @@ static int netdev_set_mac_address(struct net_device *dev, void *addr)
                hw_del_addr(hw, dev->dev_addr);
        else {
                hw->mac_override = 1;
-               memcpy(hw->override_addr, mac->sa_data, MAC_ADDR_LEN);
+               memcpy(hw->override_addr, mac->sa_data, ETH_ALEN);
        }
 
        memcpy(dev->dev_addr, mac->sa_data, MAX_ADDR_LEN);
@@ -5786,7 +5784,7 @@ static void netdev_set_rx_mode(struct net_device *dev)
                netdev_for_each_mc_addr(ha, dev) {
                        if (i >= MAX_MULTICAST_LIST)
                                break;
-                       memcpy(hw->multi_list[i++], ha->addr, MAC_ADDR_LEN);
+                       memcpy(hw->multi_list[i++], ha->addr, ETH_ALEN);
                }
                hw->multi_list_size = (u8) i;
                hw_set_grp_addr(hw);
@@ -6093,9 +6091,10 @@ static void netdev_get_drvinfo(struct net_device *dev,
        struct dev_priv *priv = netdev_priv(dev);
        struct dev_info *hw_priv = priv->adapter;
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(hw_priv->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(hw_priv->pdev),
+               sizeof(info->bus_info));
 }
 
 /**
@@ -6587,7 +6586,8 @@ static void netdev_get_ethtool_stats(struct net_device *dev,
  *
  * Return 0 if successful; otherwise an error code.
  */
-static int netdev_set_features(struct net_device *dev, u32 features)
+static int netdev_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct dev_priv *priv = netdev_priv(dev);
        struct dev_info *hw_priv = priv->adapter;
@@ -6860,7 +6860,7 @@ static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
        int num;
 
        i = j = num = got_num = 0;
-       while (j < MAC_ADDR_LEN) {
+       while (j < ETH_ALEN) {
                if (macaddr[i]) {
                        int digit;
 
@@ -6891,7 +6891,7 @@ static void get_mac_addr(struct dev_info *hw_priv, u8 *macaddr, int port)
                }
                i++;
        }
-       if (MAC_ADDR_LEN == j) {
+       if (ETH_ALEN == j) {
                if (MAIN_PORT == port)
                        hw_priv->hw.mac_override = 1;
        }
@@ -7058,7 +7058,7 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
 
        /* Multiple device interfaces mode requires a second MAC address. */
        if (hw->dev_count > 1) {
-               memcpy(sw->other_addr, hw->override_addr, MAC_ADDR_LEN);
+               memcpy(sw->other_addr, hw->override_addr, ETH_ALEN);
                read_other_addr(hw);
                if (mac1addr[0] != ':')
                        get_mac_addr(hw_priv, mac1addr, OTHER_PORT);
@@ -7108,12 +7108,11 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
                dev->irq = pdev->irq;
                if (MAIN_PORT == i)
                        memcpy(dev->dev_addr, hw_priv->hw.override_addr,
-                               MAC_ADDR_LEN);
+                              ETH_ALEN);
                else {
-                       memcpy(dev->dev_addr, sw->other_addr,
-                               MAC_ADDR_LEN);
+                       memcpy(dev->dev_addr, sw->other_addr, ETH_ALEN);
                        if (!memcmp(sw->other_addr, hw->override_addr,
-                                       MAC_ADDR_LEN))
+                                   ETH_ALEN))
                                dev->dev_addr[5] += port->first_port;
                }
 
index 0778edcf7b9a1ecee3ffcfcfd058043c317ce194..20b72ecb020a5039f86518046f3072845070b770 100644 (file)
@@ -1491,7 +1491,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget)
         * access to avoid theoretical race condition with functions that
         * change NETIF_F_LRO flag at runtime.
         */
-       bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO;
+       bool lro_enabled = !!(ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO);
 
        while (rx_done->entry[idx].length != 0 && work_done < budget) {
                length = ntohs(rx_done->entry[idx].length);
@@ -3149,7 +3149,8 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
        return 0;
 }
 
-static u32 myri10ge_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t myri10ge_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        if (!(features & NETIF_F_RXCSUM))
                features &= ~NETIF_F_LRO;
index 6ca047aab7938f3e0b79a3ceccbd5355491bf503..ac7b16b6e7af34d4ce91e068b47c2216e773f569 100644 (file)
@@ -2555,9 +2555,9 @@ static void set_rx_mode(struct net_device *dev)
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct netdev_private *np = netdev_priv(dev);
-       strncpy(info->driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->bus_info, pci_name(np->pci_dev), ETHTOOL_BUSINFO_LEN);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int get_regs_len(struct net_device *dev)
index 2b8f64ddfb5530ac98ba06dac76dfe40081adde2..c24b46cbfe27af958ffc6a4b1603cfbb4ea74928 100644 (file)
@@ -1364,9 +1364,9 @@ static int ns83820_set_settings(struct net_device *ndev,
 static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
 {
        struct ns83820 *dev = PRIV(ndev);
-       strcpy(info->driver, "ns83820");
-       strcpy(info->version, VERSION);
-       strcpy(info->bus_info, pci_name(dev->pci_dev));
+       strlcpy(info->driver, "ns83820", sizeof(info->driver));
+       strlcpy(info->version, VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(dev->pci_dev), sizeof(info->bus_info));
 }
 
 static u32 ns83820_get_link(struct net_device *ndev)
index c27fb3dda9f49d7dfc6ac9c87c0f9ff6994323cd..76ae476272002522250400b76da95deb6ce7d36c 100644 (file)
@@ -5391,10 +5391,10 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
 {
        struct s2io_nic *sp = netdev_priv(dev);
 
-       strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
-       strncpy(info->version, s2io_driver_version, sizeof(info->version));
-       strncpy(info->fw_version, "", sizeof(info->fw_version));
-       strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
+       strlcpy(info->driver, s2io_driver_name, sizeof(info->driver));
+       strlcpy(info->version, s2io_driver_version, sizeof(info->version));
+       strlcpy(info->fw_version, "", sizeof(info->fw_version));
+       strlcpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
        info->regdump_len = XENA_REG_SPACE;
        info->eedump_len = XENA_EEPROM_SPACE;
 }
@@ -6616,10 +6616,10 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
        }
 }
 
-static int s2io_set_features(struct net_device *dev, u32 features)
+static int s2io_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct s2io_nic *sp = netdev_priv(dev);
-       u32 changed = (features ^ dev->features) & NETIF_F_LRO;
+       netdev_features_t changed = (features ^ dev->features) & NETIF_F_LRO;
 
        if (changed && netif_running(dev)) {
                int rc;
index a83197d757c1e4557dc1b883fa341138d0fd3951..16d4d8e913c38b2da8fcb2bbf7849d902fa476a8 100644 (file)
@@ -2662,9 +2662,10 @@ static void vxge_poll_vp_lockup(unsigned long data)
        mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000);
 }
 
-static u32 vxge_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t vxge_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        /* Enabling RTH requires some of the logic in vxge_device_register and a
         * vpath reset.  Due to these restrictions, only allow modification
@@ -2676,10 +2677,10 @@ static u32 vxge_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int vxge_set_features(struct net_device *dev, u32 features)
+static int vxge_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct vxgedev *vdev = netdev_priv(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
 
        if (!(changed & NETIF_F_RXHASH))
                return 0;
index 1c61d36e657070d16ecf921992e59a883bf574c3..8db0b376d5b793047c3a8f9e9952c20cd316a75f 100644 (file)
@@ -65,7 +65,8 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/prefetch.h>
-#include  <linux/io.h>
+#include <linux/u64_stats_sync.h>
+#include <linux/io.h>
 
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -736,6 +737,16 @@ struct nv_skb_map {
  * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
  *     needs netdev_priv(dev)->lock :-(
  * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
+ *
+ * Hardware stats updates are protected by hwstats_lock:
+ * - updated by nv_do_stats_poll (timer). This is meant to avoid
+ *   integer wraparound in the NIC stats registers, at low frequency
+ *   (0.1 Hz)
+ * - updated by nv_get_ethtool_stats + nv_get_stats64
+ *
+ * Software stats are accessed only through 64b synchronization points
+ * and are not subject to other synchronization techniques (single
+ * update thread on the TX or RX paths).
  */
 
 /* in dev: base, irq */
@@ -745,9 +756,10 @@ struct fe_priv {
        struct net_device *dev;
        struct napi_struct napi;
 
-       /* General data:
-        * Locking: spin_lock(&np->lock); */
+       /* hardware stats are updated in syscall and timer */
+       spinlock_t hwstats_lock;
        struct nv_ethtool_stats estats;
+
        int in_shutdown;
        u32 linkspeed;
        int duplex;
@@ -798,6 +810,13 @@ struct fe_priv {
        u32 nic_poll_irq;
        int rx_ring_size;
 
+       /* RX software stats */
+       struct u64_stats_sync swstats_rx_syncp;
+       u64 stat_rx_packets;
+       u64 stat_rx_bytes; /* not always available in HW */
+       u64 stat_rx_missed_errors;
+       u64 stat_rx_dropped;
+
        /* media detection workaround.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
         */
@@ -820,6 +839,12 @@ struct fe_priv {
        struct nv_skb_map *tx_end_flip;
        int tx_stop;
 
+       /* TX software stats */
+       struct u64_stats_sync swstats_tx_syncp;
+       u64 stat_tx_packets; /* not always available in HW */
+       u64 stat_tx_bytes;
+       u64 stat_tx_dropped;
+
        /* msi/msi-x fields */
        u32 msi_flags;
        struct msix_entry msi_x_entry[NV_MSI_X_MAX_VECTORS];
@@ -891,6 +916,11 @@ enum {
 };
 static int dma_64bit = NV_DMA_64BIT_ENABLED;
 
+/*
+ * Debug output control for tx_timeout
+ */
+static bool debug_tx_timeout = false;
+
 /*
  * Crossover Detection
  * Realtek 8201 phy + some OEM boards do not work properly.
@@ -1630,11 +1660,19 @@ static void nv_mac_reset(struct net_device *dev)
        pci_push(base);
 }
 
-static void nv_get_hw_stats(struct net_device *dev)
+/* Caller must appropriately lock netdev_priv(dev)->hwstats_lock */
+static void nv_update_stats(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
 
+       /* If it happens that this is run in top-half context, then
+        * replace the spin_lock of hwstats_lock with
+        * spin_lock_irqsave() in calling functions. */
+       WARN_ONCE(in_irq(), "forcedeth: estats spin_lock(_bh) from top-half");
+       assert_spin_locked(&np->hwstats_lock);
+
+       /* query hardware */
        np->estats.tx_bytes += readl(base + NvRegTxCnt);
        np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
        np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
@@ -1693,40 +1731,73 @@ static void nv_get_hw_stats(struct net_device *dev)
 }
 
 /*
- * nv_get_stats: dev->get_stats function
+ * nv_get_stats64: dev->ndo_get_stats64 function
  * Get latest stats value from the nic.
  * Called with read_lock(&dev_base_lock) held for read -
  * only synchronized against unregister_netdevice.
  */
-static struct net_device_stats *nv_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64*
+nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
+       __acquires(&netdev_priv(dev)->hwstats_lock)
+       __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct fe_priv *np = netdev_priv(dev);
+       unsigned int syncp_start;
+
+       /*
+        * Note: because HW stats are not always available and for
+        * consistency reasons, the following ifconfig stats are
+        * managed by software: rx_bytes, tx_bytes, rx_packets and
+        * tx_packets. The related hardware stats reported by ethtool
+        * should be equivalent to these ifconfig stats, with 4
+        * additional bytes per packet (Ethernet FCS CRC), except for
+        * tx_packets when TSO kicks in.
+        */
+
+       /* software stats */
+       do {
+               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_rx_syncp);
+               storage->rx_packets       = np->stat_rx_packets;
+               storage->rx_bytes         = np->stat_rx_bytes;
+               storage->rx_dropped       = np->stat_rx_dropped;
+               storage->rx_missed_errors = np->stat_rx_missed_errors;
+       } while (u64_stats_fetch_retry_bh(&np->swstats_rx_syncp, syncp_start));
+
+       do {
+               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_tx_syncp);
+               storage->tx_packets = np->stat_tx_packets;
+               storage->tx_bytes   = np->stat_tx_bytes;
+               storage->tx_dropped = np->stat_tx_dropped;
+       } while (u64_stats_fetch_retry_bh(&np->swstats_tx_syncp, syncp_start));
 
        /* If the nic supports hw counters then retrieve latest values */
-       if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_STATISTICS_V3)) {
-               nv_get_hw_stats(dev);
+       if (np->driver_data & DEV_HAS_STATISTICS_V123) {
+               spin_lock_bh(&np->hwstats_lock);
 
-               /*
-                * Note: because HW stats are not always available and
-                * for consistency reasons, the following ifconfig
-                * stats are managed by software: rx_bytes, tx_bytes,
-                * rx_packets and tx_packets. The related hardware
-                * stats reported by ethtool should be equivalent to
-                * these ifconfig stats, with 4 additional bytes per
-                * packet (Ethernet FCS CRC).
-                */
+               nv_update_stats(dev);
 
-               /* copy to net_device stats */
-               dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
-               dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
-               dev->stats.rx_crc_errors = np->estats.rx_crc_errors;
-               dev->stats.rx_over_errors = np->estats.rx_over_errors;
-               dev->stats.rx_fifo_errors = np->estats.rx_drop_frame;
-               dev->stats.rx_errors = np->estats.rx_errors_total;
-               dev->stats.tx_errors = np->estats.tx_errors_total;
+               /* generic stats */
+               storage->rx_errors = np->estats.rx_errors_total;
+               storage->tx_errors = np->estats.tx_errors_total;
+
+               /* meaningful only when NIC supports stats v3 */
+               storage->multicast = np->estats.rx_multicast;
+
+               /* detailed rx_errors */
+               storage->rx_length_errors = np->estats.rx_length_error;
+               storage->rx_over_errors   = np->estats.rx_over_errors;
+               storage->rx_crc_errors    = np->estats.rx_crc_errors;
+               storage->rx_frame_errors  = np->estats.rx_frame_align_error;
+               storage->rx_fifo_errors   = np->estats.rx_drop_frame;
+
+               /* detailed tx_errors */
+               storage->tx_carrier_errors = np->estats.tx_carrier_errors;
+               storage->tx_fifo_errors    = np->estats.tx_fifo_errors;
+
+               spin_unlock_bh(&np->hwstats_lock);
        }
 
-       return &dev->stats;
+       return storage;
 }
 
 /*
@@ -1759,8 +1830,12 @@ static int nv_alloc_rx(struct net_device *dev)
                                np->put_rx.orig = np->first_rx.orig;
                        if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
                                np->put_rx_ctx = np->first_rx_ctx;
-               } else
+               } else {
+                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                       np->stat_rx_dropped++;
+                       u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
+               }
        }
        return 0;
 }
@@ -1791,8 +1866,12 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
                                np->put_rx.ex = np->first_rx.ex;
                        if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
                                np->put_rx_ctx = np->first_rx_ctx;
-               } else
+               } else {
+                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                       np->stat_rx_dropped++;
+                       u64_stats_update_end(&np->swstats_rx_syncp);
                        return 1;
+               }
        }
        return 0;
 }
@@ -1927,8 +2006,11 @@ static void nv_drain_tx(struct net_device *dev)
                        np->tx_ring.ex[i].bufhigh = 0;
                        np->tx_ring.ex[i].buflow = 0;
                }
-               if (nv_release_txskb(np, &np->tx_skb[i]))
-                       dev->stats.tx_dropped++;
+               if (nv_release_txskb(np, &np->tx_skb[i])) {
+                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                       np->stat_tx_dropped++;
+                       u64_stats_update_end(&np->swstats_tx_syncp);
+               }
                np->tx_skb[i].dma = 0;
                np->tx_skb[i].dma_len = 0;
                np->tx_skb[i].dma_single = 0;
@@ -2385,11 +2467,14 @@ static int nv_tx_done(struct net_device *dev, int limit)
                if (np->desc_ver == DESC_VER_1) {
                        if (flags & NV_TX_LASTPACKET) {
                                if (flags & NV_TX_ERROR) {
-                                       if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK))
+                                       if ((flags & NV_TX_RETRYERROR)
+                                           && !(flags & NV_TX_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
                                } else {
-                                       dev->stats.tx_packets++;
-                                       dev->stats.tx_bytes += np->get_tx_ctx->skb->len;
+                                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                                       np->stat_tx_packets++;
+                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
@@ -2398,11 +2483,14 @@ static int nv_tx_done(struct net_device *dev, int limit)
                } else {
                        if (flags & NV_TX2_LASTPACKET) {
                                if (flags & NV_TX2_ERROR) {
-                                       if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK))
+                                       if ((flags & NV_TX2_RETRYERROR)
+                                           && !(flags & NV_TX2_RETRYCOUNT_MASK))
                                                nv_legacybackoff_reseed(dev);
                                } else {
-                                       dev->stats.tx_packets++;
-                                       dev->stats.tx_bytes += np->get_tx_ctx->skb->len;
+                                       u64_stats_update_begin(&np->swstats_tx_syncp);
+                                       np->stat_tx_packets++;
+                                       np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                                       u64_stats_update_end(&np->swstats_tx_syncp);
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
@@ -2436,15 +2524,18 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit)
 
                if (flags & NV_TX2_LASTPACKET) {
                        if (flags & NV_TX2_ERROR) {
-                               if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) {
+                               if ((flags & NV_TX2_RETRYERROR)
+                                   && !(flags & NV_TX2_RETRYCOUNT_MASK)) {
                                        if (np->driver_data & DEV_HAS_GEAR_MODE)
                                                nv_gear_backoff_reseed(dev);
                                        else
                                                nv_legacybackoff_reseed(dev);
                                }
                        } else {
-                               dev->stats.tx_packets++;
-                               dev->stats.tx_bytes += np->get_tx_ctx->skb->len;
+                               u64_stats_update_begin(&np->swstats_tx_syncp);
+                               np->stat_tx_packets++;
+                               np->stat_tx_bytes += np->get_tx_ctx->skb->len;
+                               u64_stats_update_end(&np->swstats_tx_syncp);
                        }
 
                        dev_kfree_skb_any(np->get_tx_ctx->skb);
@@ -2477,56 +2568,64 @@ static void nv_tx_timeout(struct net_device *dev)
        u32 status;
        union ring_type put_tx;
        int saved_tx_limit;
-       int i;
 
        if (np->msi_flags & NV_MSI_X_ENABLED)
                status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
        else
                status = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
 
-       netdev_info(dev, "Got tx_timeout. irq: %08x\n", status);
+       netdev_warn(dev, "Got tx_timeout. irq status: %08x\n", status);
 
-       netdev_info(dev, "Ring at %lx\n", (unsigned long)np->ring_addr);
-       netdev_info(dev, "Dumping tx registers\n");
-       for (i = 0; i <= np->register_size; i += 32) {
-               netdev_info(dev,
-                           "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
-                           i,
-                           readl(base + i + 0), readl(base + i + 4),
-                           readl(base + i + 8), readl(base + i + 12),
-                           readl(base + i + 16), readl(base + i + 20),
-                           readl(base + i + 24), readl(base + i + 28));
-       }
-       netdev_info(dev, "Dumping tx ring\n");
-       for (i = 0; i < np->tx_ring_size; i += 4) {
-               if (!nv_optimized(np)) {
-                       netdev_info(dev,
-                                   "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
-                                   i,
-                                   le32_to_cpu(np->tx_ring.orig[i].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i].flaglen),
-                                   le32_to_cpu(np->tx_ring.orig[i+1].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
-                                   le32_to_cpu(np->tx_ring.orig[i+2].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
-                                   le32_to_cpu(np->tx_ring.orig[i+3].buf),
-                                   le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
-               } else {
+       if (unlikely(debug_tx_timeout)) {
+               int i;
+
+               netdev_info(dev, "Ring at %lx\n", (unsigned long)np->ring_addr);
+               netdev_info(dev, "Dumping tx registers\n");
+               for (i = 0; i <= np->register_size; i += 32) {
                        netdev_info(dev,
-                                   "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
+                                   "%3x: %08x %08x %08x %08x "
+                                   "%08x %08x %08x %08x\n",
                                    i,
-                                   le32_to_cpu(np->tx_ring.ex[i].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i].flaglen),
-                                   le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i+1].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
-                                   le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i+2].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
-                                   le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
-                                   le32_to_cpu(np->tx_ring.ex[i+3].buflow),
-                                   le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
+                                   readl(base + i + 0), readl(base + i + 4),
+                                   readl(base + i + 8), readl(base + i + 12),
+                                   readl(base + i + 16), readl(base + i + 20),
+                                   readl(base + i + 24), readl(base + i + 28));
+               }
+               netdev_info(dev, "Dumping tx ring\n");
+               for (i = 0; i < np->tx_ring_size; i += 4) {
+                       if (!nv_optimized(np)) {
+                               netdev_info(dev,
+                                           "%03x: %08x %08x // %08x %08x "
+                                           "// %08x %08x // %08x %08x\n",
+                                           i,
+                                           le32_to_cpu(np->tx_ring.orig[i].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i].flaglen),
+                                           le32_to_cpu(np->tx_ring.orig[i+1].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+                                           le32_to_cpu(np->tx_ring.orig[i+2].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+                                           le32_to_cpu(np->tx_ring.orig[i+3].buf),
+                                           le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
+                       } else {
+                               netdev_info(dev,
+                                           "%03x: %08x %08x %08x "
+                                           "// %08x %08x %08x "
+                                           "// %08x %08x %08x "
+                                           "// %08x %08x %08x\n",
+                                           i,
+                                           le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i].flaglen),
+                                           le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+                                           le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+                                           le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+                                           le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+                                           le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
+                       }
                }
        }
 
@@ -2649,8 +2748,11 @@ static int nv_rx_process(struct net_device *dev, int limit)
                                        }
                                        /* the rest are hard errors */
                                        else {
-                                               if (flags & NV_RX_MISSEDFRAME)
-                                                       dev->stats.rx_missed_errors++;
+                                               if (flags & NV_RX_MISSEDFRAME) {
+                                                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                                                       np->stat_rx_missed_errors++;
+                                                       u64_stats_update_end(&np->swstats_rx_syncp);
+                                               }
                                                dev_kfree_skb(skb);
                                                goto next_pkt;
                                        }
@@ -2693,8 +2795,10 @@ static int nv_rx_process(struct net_device *dev, int limit)
                skb_put(skb, len);
                skb->protocol = eth_type_trans(skb, dev);
                napi_gro_receive(&np->napi, skb);
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += len;
+               u64_stats_update_begin(&np->swstats_rx_syncp);
+               np->stat_rx_packets++;
+               np->stat_rx_bytes += len;
+               u64_stats_update_end(&np->swstats_rx_syncp);
 next_pkt:
                if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
                        np->get_rx.orig = np->first_rx.orig;
@@ -2777,8 +2881,10 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                                __vlan_hwaccel_put_tag(skb, vid);
                        }
                        napi_gro_receive(&np->napi, skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += len;
+                       u64_stats_update_begin(&np->swstats_rx_syncp);
+                       np->stat_rx_packets++;
+                       np->stat_rx_bytes += len;
+                       u64_stats_update_end(&np->swstats_rx_syncp);
                } else {
                        dev_kfree_skb(skb);
                }
@@ -3021,6 +3127,73 @@ static void nv_update_pause(struct net_device *dev, u32 pause_flags)
        }
 }
 
+static void nv_force_linkspeed(struct net_device *dev, int speed, int duplex)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+       u32 phyreg, txreg;
+       int mii_status;
+
+       np->linkspeed = NVREG_LINKSPEED_FORCE|speed;
+       np->duplex = duplex;
+
+       /* see if gigabit phy */
+       mii_status = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ);
+       if (mii_status & PHY_GIGABIT) {
+               np->gigabit = PHY_GIGABIT;
+               phyreg = readl(base + NvRegSlotTime);
+               phyreg &= ~(0x3FF00);
+               if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_10)
+                       phyreg |= NVREG_SLOTTIME_10_100_FULL;
+               else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100)
+                       phyreg |= NVREG_SLOTTIME_10_100_FULL;
+               else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000)
+                       phyreg |= NVREG_SLOTTIME_1000_FULL;
+               writel(phyreg, base + NvRegSlotTime);
+       }
+
+       phyreg = readl(base + NvRegPhyInterface);
+       phyreg &= ~(PHY_HALF|PHY_100|PHY_1000);
+       if (np->duplex == 0)
+               phyreg |= PHY_HALF;
+       if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100)
+               phyreg |= PHY_100;
+       else if ((np->linkspeed & NVREG_LINKSPEED_MASK) ==
+                                                       NVREG_LINKSPEED_1000)
+               phyreg |= PHY_1000;
+       writel(phyreg, base + NvRegPhyInterface);
+
+       if (phyreg & PHY_RGMII) {
+               if ((np->linkspeed & NVREG_LINKSPEED_MASK) ==
+                                                       NVREG_LINKSPEED_1000)
+                       txreg = NVREG_TX_DEFERRAL_RGMII_1000;
+               else
+                       txreg = NVREG_TX_DEFERRAL_RGMII_10_100;
+       } else {
+               txreg = NVREG_TX_DEFERRAL_DEFAULT;
+       }
+       writel(txreg, base + NvRegTxDeferral);
+
+       if (np->desc_ver == DESC_VER_1) {
+               txreg = NVREG_TX_WM_DESC1_DEFAULT;
+       } else {
+               if ((np->linkspeed & NVREG_LINKSPEED_MASK) ==
+                                        NVREG_LINKSPEED_1000)
+                       txreg = NVREG_TX_WM_DESC2_3_1000;
+               else
+                       txreg = NVREG_TX_WM_DESC2_3_DEFAULT;
+       }
+       writel(txreg, base + NvRegTxWatermark);
+
+       writel(NVREG_MISC1_FORCE | (np->duplex ? 0 : NVREG_MISC1_HD),
+                       base + NvRegMisc1);
+       pci_push(base);
+       writel(np->linkspeed, base + NvRegLinkSpeed);
+       pci_push(base);
+
+       return;
+}
+
 /**
  * nv_update_linkspeed: Setup the MAC according to the link partner
  * @dev: Network device to be configured
@@ -3042,11 +3215,25 @@ static int nv_update_linkspeed(struct net_device *dev)
        int newls = np->linkspeed;
        int newdup = np->duplex;
        int mii_status;
+       u32 bmcr;
        int retval = 0;
        u32 control_1000, status_1000, phyreg, pause_flags, txreg;
        u32 txrxFlags = 0;
        u32 phy_exp;
 
+       /* If device loopback is enabled, set carrier on and enable max link
+        * speed.
+        */
+       bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+       if (bmcr & BMCR_LOOPBACK) {
+               if (netif_running(dev)) {
+                       nv_force_linkspeed(dev, NVREG_LINKSPEED_1000, 1);
+                       if (!netif_carrier_ok(dev))
+                               netif_carrier_on(dev);
+               }
+               return 1;
+       }
+
        /* BMSR_LSTATUS is latched, read it twice:
         * we want the current value.
         */
@@ -3729,6 +3916,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                writel(0, base + NvRegMSIXMap0);
                                writel(0, base + NvRegMSIXMap1);
                        }
+                       netdev_info(dev, "MSI-X enabled\n");
                }
        }
        if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
@@ -3750,6 +3938,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                        writel(0, base + NvRegMSIMap1);
                        /* enable msi vector 0 */
                        writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
+                       netdev_info(dev, "MSI enabled\n");
                }
        }
        if (ret != 0) {
@@ -3904,11 +4093,18 @@ static void nv_poll_controller(struct net_device *dev)
 #endif
 
 static void nv_do_stats_poll(unsigned long data)
+       __acquires(&netdev_priv(dev)->hwstats_lock)
+       __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
 
-       nv_get_hw_stats(dev);
+       /* If lock is currently taken, the stats are being refreshed
+        * and hence fresh enough */
+       if (spin_trylock(&np->hwstats_lock)) {
+               nv_update_stats(dev);
+               spin_unlock(&np->hwstats_lock);
+       }
 
        if (!np->in_shutdown)
                mod_timer(&np->stats_poll,
@@ -3918,9 +4114,9 @@ static void nv_do_stats_poll(unsigned long data)
 static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct fe_priv *np = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, FORCEDETH_VERSION);
-       strcpy(info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, FORCEDETH_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
@@ -4473,7 +4669,63 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
        return 0;
 }
 
-static u32 nv_fix_features(struct net_device *dev, u32 features)
+static int nv_set_loopback(struct net_device *dev, netdev_features_t features)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       unsigned long flags;
+       u32 miicontrol;
+       int err, retval = 0;
+
+       spin_lock_irqsave(&np->lock, flags);
+       miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+       if (features & NETIF_F_LOOPBACK) {
+               if (miicontrol & BMCR_LOOPBACK) {
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       netdev_info(dev, "Loopback already enabled\n");
+                       return 0;
+               }
+               nv_disable_irq(dev);
+               /* Turn on loopback mode */
+               miicontrol |= BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000;
+               err = mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol);
+               if (err) {
+                       retval = PHY_ERROR;
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       phy_init(dev);
+               } else {
+                       if (netif_running(dev)) {
+                               /* Force 1000 Mbps full-duplex */
+                               nv_force_linkspeed(dev, NVREG_LINKSPEED_1000,
+                                                                        1);
+                               /* Force link up */
+                               netif_carrier_on(dev);
+                       }
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       netdev_info(dev,
+                               "Internal PHY loopback mode enabled.\n");
+               }
+       } else {
+               if (!(miicontrol & BMCR_LOOPBACK)) {
+                       spin_unlock_irqrestore(&np->lock, flags);
+                       netdev_info(dev, "Loopback already disabled\n");
+                       return 0;
+               }
+               nv_disable_irq(dev);
+               /* Turn off loopback */
+               spin_unlock_irqrestore(&np->lock, flags);
+               netdev_info(dev, "Internal PHY loopback mode disabled.\n");
+               phy_init(dev);
+       }
+       msleep(500);
+       spin_lock_irqsave(&np->lock, flags);
+       nv_enable_irq(dev);
+       spin_unlock_irqrestore(&np->lock, flags);
+
+       return retval;
+}
+
+static netdev_features_t nv_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /* vlan is dependent on rx checksum offload */
        if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
@@ -4482,7 +4734,7 @@ static u32 nv_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static void nv_vlan_mode(struct net_device *dev, u32 features)
+static void nv_vlan_mode(struct net_device *dev, netdev_features_t features)
 {
        struct fe_priv *np = get_nvpriv(dev);
 
@@ -4503,11 +4755,18 @@ static void nv_vlan_mode(struct net_device *dev, u32 features)
        spin_unlock_irq(&np->lock);
 }
 
-static int nv_set_features(struct net_device *dev, u32 features)
+static int nv_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       u32 changed = dev->features ^ features;
+       netdev_features_t changed = dev->features ^ features;
+       int retval;
+
+       if ((changed & NETIF_F_LOOPBACK) && netif_running(dev)) {
+               retval = nv_set_loopback(dev, features);
+               if (retval != 0)
+                       return retval;
+       }
 
        if (changed & NETIF_F_RXCSUM) {
                spin_lock_irq(&np->lock);
@@ -4553,14 +4812,18 @@ static int nv_get_sset_count(struct net_device *dev, int sset)
        }
 }
 
-static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer)
+static void nv_get_ethtool_stats(struct net_device *dev,
+                                struct ethtool_stats *estats, u64 *buffer)
+       __acquires(&netdev_priv(dev)->hwstats_lock)
+       __releases(&netdev_priv(dev)->hwstats_lock)
 {
        struct fe_priv *np = netdev_priv(dev);
 
-       /* update stats */
-       nv_get_hw_stats(dev);
-
-       memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
+       spin_lock_bh(&np->hwstats_lock);
+       nv_update_stats(dev);
+       memcpy(buffer, &np->estats,
+              nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
+       spin_unlock_bh(&np->hwstats_lock);
 }
 
 static int nv_link_test(struct net_device *dev)
@@ -5142,6 +5405,12 @@ static int nv_open(struct net_device *dev)
 
        spin_unlock_irq(&np->lock);
 
+       /* If the loopback feature was set while the device was down, make sure
+        * that it's set correctly now.
+        */
+       if (dev->features & NETIF_F_LOOPBACK)
+               nv_set_loopback(dev, dev->features);
+
        return 0;
 out_drain:
        nv_drain_rxtx(dev);
@@ -5198,7 +5467,7 @@ static int nv_close(struct net_device *dev)
 static const struct net_device_ops nv_netdev_ops = {
        .ndo_open               = nv_open,
        .ndo_stop               = nv_close,
-       .ndo_get_stats          = nv_get_stats,
+       .ndo_get_stats64        = nv_get_stats64,
        .ndo_start_xmit         = nv_start_xmit,
        .ndo_tx_timeout         = nv_tx_timeout,
        .ndo_change_mtu         = nv_change_mtu,
@@ -5215,7 +5484,7 @@ static const struct net_device_ops nv_netdev_ops = {
 static const struct net_device_ops nv_netdev_ops_optimized = {
        .ndo_open               = nv_open,
        .ndo_stop               = nv_close,
-       .ndo_get_stats          = nv_get_stats,
+       .ndo_get_stats64        = nv_get_stats64,
        .ndo_start_xmit         = nv_start_xmit_optimized,
        .ndo_tx_timeout         = nv_tx_timeout,
        .ndo_change_mtu         = nv_change_mtu,
@@ -5254,6 +5523,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        np->dev = dev;
        np->pci_dev = pci_dev;
        spin_lock_init(&np->lock);
+       spin_lock_init(&np->hwstats_lock);
        SET_NETDEV_DEV(dev, &pci_dev->dev);
 
        init_timer(&np->oom_kick);
@@ -5262,7 +5532,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        init_timer(&np->nic_poll);
        np->nic_poll.data = (unsigned long) dev;
        np->nic_poll.function = nv_do_nic_poll; /* timer handler */
-       init_timer(&np->stats_poll);
+       init_timer_deferrable(&np->stats_poll);
        np->stats_poll.data = (unsigned long) dev;
        np->stats_poll.function = nv_do_stats_poll;     /* timer handler */
 
@@ -5346,6 +5616,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
        dev->features |= dev->hw_features;
 
+       /* Add loopback capability to the device. */
+       dev->hw_features |= NETIF_F_LOOPBACK;
+
        np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
        if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) ||
            (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) ||
@@ -5621,12 +5894,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n",
                 dev->name, np->phy_oui, np->phyaddr, dev->dev_addr);
 
-       dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
+       dev_info(&pci_dev->dev, "%s%s%s%s%s%s%s%s%s%s%sdesc-v%u\n",
                 dev->features & NETIF_F_HIGHDMA ? "highdma " : "",
                 dev->features & (NETIF_F_IP_CSUM | NETIF_F_SG) ?
                        "csum " : "",
                 dev->features & (NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX) ?
                        "vlan " : "",
+                dev->features & (NETIF_F_LOOPBACK) ?
+                       "loopback " : "",
                 id->driver_data & DEV_HAS_POWER_CNTRL ? "pwrctl " : "",
                 id->driver_data & DEV_HAS_MGMT_UNIT ? "mgmt " : "",
                 id->driver_data & DEV_NEED_TIMERIRQ ? "timirq " : "",
@@ -6000,6 +6275,9 @@ module_param(phy_cross, int, 0);
 MODULE_PARM_DESC(phy_cross, "Phy crossover detection for Realtek 8201 phy is enabled by setting to 1 and disabled by setting to 0.");
 module_param(phy_power_down, int, 0);
 MODULE_PARM_DESC(phy_power_down, "Power down phy and disable link when interface is down (1), or leave phy powered up (0).");
+module_param(debug_tx_timeout, bool, 0);
+MODULE_PARM_DESC(debug_tx_timeout,
+                "Dump tx related registers and ring when tx_timeout happens");
 
 MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
 MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
index 8c8027176bef98cb133b0aa5e7a03f30808df42f..0063194adb9e048bde7e57f8a32f2718d2768ede 100644 (file)
@@ -161,10 +161,11 @@ static void pch_gbe_get_drvinfo(struct net_device *netdev,
 {
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
 
-       strcpy(drvinfo->driver, KBUILD_MODNAME);
-       strcpy(drvinfo->version, pch_driver_version);
-       strcpy(drvinfo->fw_version, "N/A");
-       strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+       strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, pch_driver_version, sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = pch_gbe_get_regs_len(netdev);
 }
 
index 48406ca382f1de638e8938b4732f19406485fc83..964e9c0948bce19cf1a09ca5229575006ed1934f 100644 (file)
@@ -2109,10 +2109,11 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
  * Returns
  *     0:              HW state updated successfully
  */
-static int pch_gbe_set_features(struct net_device *netdev, u32 features)
+static int pch_gbe_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (!(changed & NETIF_F_RXCSUM))
                return 0;
index e09ea83b8c47efe7f7061e2f046b9a45b870b82e..8a371985319f6ef8afed68ae184329bb18aa93ee 100644 (file)
@@ -83,14 +83,18 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        u32 fw_minor = 0;
        u32 fw_build = 0;
 
-       strncpy(drvinfo->driver, netxen_nic_driver_name, 32);
-       strncpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID, 32);
+       strlcpy(drvinfo->driver, netxen_nic_driver_name,
+               sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, NETXEN_NIC_LINUX_VERSIONID,
+               sizeof(drvinfo->version));
        fw_major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
        fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
        fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
-       sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d", fw_major, fw_minor, fw_build);
 
-       strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
        drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
 }
index 8cf3173ba48818edb795536d5accf7b7ff447de4..7dd9a4b107e622980620d231b8f178335b1c526e 100644 (file)
@@ -544,7 +544,8 @@ static void netxen_set_multicast_list(struct net_device *dev)
        adapter->set_multi(dev);
 }
 
-static u32 netxen_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t netxen_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        if (!(features & NETIF_F_RXCSUM)) {
                netdev_info(dev, "disabling LRO as RXCSUM is off\n");
@@ -555,7 +556,8 @@ static u32 netxen_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int netxen_set_features(struct net_device *dev, u32 features)
+static int netxen_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct netxen_adapter *adapter = netdev_priv(dev);
        int hw_lro;
index a4bdff438a5e5a25e6ec9338b8c371bc66ee2548..9416f297100e1a7c0feed05fa793f5fef1aca9b3 100644 (file)
@@ -1735,10 +1735,12 @@ static void ql_get_drvinfo(struct net_device *ndev,
                           struct ethtool_drvinfo *drvinfo)
 {
        struct ql3_adapter *qdev = netdev_priv(ndev);
-       strncpy(drvinfo->driver, ql3xxx_driver_name, 32);
-       strncpy(drvinfo->version, ql3xxx_driver_version, 32);
-       strncpy(drvinfo->fw_version, "N/A", 32);
-       strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+       strlcpy(drvinfo->driver, ql3xxx_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, ql3xxx_driver_version,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(qdev->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->regdump_len = 0;
        drvinfo->eedump_len = 0;
 }
index 7ed53dbb8646fa886e0411c3f6cfba2a372e6bcf..60976fc4ccc67bb4e7131c34d399472a5e9930da 100644 (file)
@@ -1466,8 +1466,9 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
 
 int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
 int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
-u32 qlcnic_fix_features(struct net_device *netdev, u32 features);
-int qlcnic_set_features(struct net_device *netdev, u32 features);
+netdev_features_t qlcnic_fix_features(struct net_device *netdev,
+       netdev_features_t features);
+int qlcnic_set_features(struct net_device *netdev, netdev_features_t features);
 int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
 int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
 int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
index 8aa1c6e8667be48710bd9d1384db92266a6ecd55..cc228cf3d84bcfdf480d85332c4e6ab97ef13713 100644 (file)
@@ -140,11 +140,14 @@ qlcnic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
        fw_major = QLCRD32(adapter, QLCNIC_FW_VERSION_MAJOR);
        fw_minor = QLCRD32(adapter, QLCNIC_FW_VERSION_MINOR);
        fw_build = QLCRD32(adapter, QLCNIC_FW_VERSION_SUB);
-       sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
-
-       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
-       strlcpy(drvinfo->driver, qlcnic_driver_name, 32);
-       strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID, 32);
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+               "%d.%d.%d", fw_major, fw_minor, fw_build);
+
+       strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
+       strlcpy(drvinfo->driver, qlcnic_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, QLCNIC_LINUX_VERSIONID,
+               sizeof(drvinfo->version));
 }
 
 static int
index bcb81e47543a3f47f2e9fd59d61c3a7d2f9d2886..b528e52a8ee1388b3ac1b6aecb5e9ac2005efa08 100644 (file)
@@ -817,12 +817,13 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
 }
 
 
-u32 qlcnic_fix_features(struct net_device *netdev, u32 features)
+netdev_features_t qlcnic_fix_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
 
        if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               u32 changed = features ^ netdev->features;
+               netdev_features_t changed = features ^ netdev->features;
                features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
        }
 
@@ -833,10 +834,10 @@ u32 qlcnic_fix_features(struct net_device *netdev, u32 features)
 }
 
 
-int qlcnic_set_features(struct net_device *netdev, u32 features)
+int qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       u32 changed = netdev->features ^ features;
+       netdev_features_t changed = netdev->features ^ features;
        int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0;
 
        if (!(changed & NETIF_F_LRO))
index 0bd163828e339fbb0c6f290167c74561a55b4471..823f845ddc04c654d021b14168fa36cf0c0f64f4 100644 (file)
@@ -792,7 +792,7 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
                struct qlcnic_esw_func_cfg *esw_cfg)
 {
        struct net_device *netdev = adapter->netdev;
-       unsigned long features, vlan_features;
+       netdev_features_t features, vlan_features;
 
        features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
                        NETIF_F_IPV6_CSUM | NETIF_F_GRO);
index 9b67bfea035ff6082cb05c0a48fcf16f1819d607..8e2c2a74f3a5bbf05a892e30d33b2bf79fd07e5d 100644 (file)
@@ -366,13 +366,16 @@ static void ql_get_drvinfo(struct net_device *ndev,
                           struct ethtool_drvinfo *drvinfo)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
-       strncpy(drvinfo->driver, qlge_driver_name, 32);
-       strncpy(drvinfo->version, qlge_driver_version, 32);
-       snprintf(drvinfo->fw_version, 32, "v%d.%d.%d",
+       strlcpy(drvinfo->driver, qlge_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, qlge_driver_version,
+               sizeof(drvinfo->version));
+       snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
+                "v%d.%d.%d",
                 (qdev->fw_rev_id & 0x00ff0000) >> 16,
                 (qdev->fw_rev_id & 0x0000ff00) >> 8,
                 (qdev->fw_rev_id & 0x000000ff));
-       strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+       strlcpy(drvinfo->bus_info, pci_name(qdev->pdev),
+               sizeof(drvinfo->bus_info));
        drvinfo->n_stats = 0;
        drvinfo->testinfo_len = 0;
        if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
index c92afcd912e23fe48a17c686e9355ba350585f15..1ce4e08037b83abff04b1cda9cd449d347cb998a 100644 (file)
@@ -2307,7 +2307,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-static void qlge_vlan_mode(struct net_device *ndev, u32 features)
+static void qlge_vlan_mode(struct net_device *ndev, netdev_features_t features)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
 
@@ -2323,7 +2323,8 @@ static void qlge_vlan_mode(struct net_device *ndev, u32 features)
        }
 }
 
-static u32 qlge_fix_features(struct net_device *ndev, u32 features)
+static netdev_features_t qlge_fix_features(struct net_device *ndev,
+       netdev_features_t features)
 {
        /*
         * Since there is no support for separate rx/tx vlan accel
@@ -2337,9 +2338,10 @@ static u32 qlge_fix_features(struct net_device *ndev, u32 features)
        return features;
 }
 
-static int qlge_set_features(struct net_device *ndev, u32 features)
+static int qlge_set_features(struct net_device *ndev,
+       netdev_features_t features)
 {
-       u32 changed = ndev->features ^ features;
+       netdev_features_t changed = ndev->features ^ features;
 
        if (changed & NETIF_F_HW_VLAN_RX)
                qlge_vlan_mode(ndev, features);
index ee5da9293ce00f386af069dd0919849eec161480..87cff10f7be7432c167d3c721a2ba5012cb605b5 100644 (file)
@@ -1319,9 +1319,9 @@ static void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct cp_private *cp = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(cp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(cp->pdev), sizeof(info->bus_info));
 }
 
 static void cp_get_ringparam(struct net_device *dev,
@@ -1392,7 +1392,7 @@ static void cp_set_msglevel(struct net_device *dev, u32 value)
        cp->msg_enable = value;
 }
 
-static int cp_set_features(struct net_device *dev, u32 features)
+static int cp_set_features(struct net_device *dev, netdev_features_t features)
 {
        struct cp_private *cp = netdev_priv(dev);
        unsigned long flags;
index 4d6b254fc6c16de399ac168490089c1cd691625f..d9c72273e428891d33eea4be4daf3ebb97ceef9a 100644 (file)
@@ -2330,9 +2330,9 @@ static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct rtl8139_private *tp = netdev_priv(dev);
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(tp->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
        info->regdump_len = tp->regs_len;
 }
 
index 6f06aa10f0d729a040a6e34a244d57338ba3025f..f7bc310f5185126a59e581775fb922b64f5129dc 100644 (file)
@@ -69,9 +69,6 @@
    The RTL chips use a 64 element hash table based on the Ethernet CRC. */
 static const int multicast_filter_limit = 32;
 
-/* MAC address length */
-#define MAC_ADDR_LEN   6
-
 #define MAX_READ_REQUEST_SHIFT 12
 #define TX_DMA_BURST   6       /* Maximum PCI burst, '6' is 1024 */
 #define SafeMtu                0x1c20  /* ... actually life sucks beyond ~7k */
@@ -1404,12 +1401,12 @@ static void rtl8169_get_drvinfo(struct net_device *dev,
        struct rtl8169_private *tp = netdev_priv(dev);
        struct rtl_fw *rtl_fw = tp->rtl_fw;
 
-       strcpy(info->driver, MODULENAME);
-       strcpy(info->version, RTL8169_VERSION);
-       strcpy(info->bus_info, pci_name(tp->pci_dev));
+       strlcpy(info->driver, MODULENAME, sizeof(info->driver));
+       strlcpy(info->version, RTL8169_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(tp->pci_dev), sizeof(info->bus_info));
        BUILD_BUG_ON(sizeof(info->fw_version) < sizeof(rtl_fw->version));
-       strcpy(info->fw_version, IS_ERR_OR_NULL(rtl_fw) ? "N/A" :
-              rtl_fw->version);
+       strlcpy(info->fw_version, IS_ERR_OR_NULL(rtl_fw) ? "N/A" :
+              rtl_fw->version, sizeof(info->fw_version));
 }
 
 static int rtl8169_get_regs_len(struct net_device *dev)
@@ -1553,7 +1550,8 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        return ret;
 }
 
-static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t rtl8169_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
 
@@ -1567,7 +1565,8 @@ static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int rtl8169_set_features(struct net_device *dev, u32 features)
+static int rtl8169_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
@@ -4099,7 +4098,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        spin_lock_init(&tp->lock);
 
        /* Get MAC address */
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
index d5731f1fe6d67dc3713070ec4e7733f4788cc35a..14e134d3b4d716704855fb23efa03d0375a8a80f 100644 (file)
@@ -1900,7 +1900,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
        /* Otherwise efx_start_port() will do this */
 }
 
-static int efx_set_features(struct net_device *net_dev, u32 data)
+static int efx_set_features(struct net_device *net_dev, netdev_features_t data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
 
index b8e251a1ee48694063693698d83a25527b3c1f7c..c49502bab6a3a06803ce9dc9950220c9bd371355 100644 (file)
@@ -908,7 +908,7 @@ struct efx_nic_type {
        unsigned int phys_addr_channels;
        unsigned int tx_dc_base;
        unsigned int rx_dc_base;
-       u32 offload_features;
+       netdev_features_t offload_features;
 };
 
 /**************************************************************************
index 1b4658c99391a4edbc09670f0145ec6d8bcbe31f..5b118cd5bf942c48e5d6be5ecf3e8f5b9c4c9559 100644 (file)
@@ -47,8 +47,6 @@
 #define sis190_rx_skb                  netif_rx
 #define sis190_rx_quota(count, quota)  count
 
-#define MAC_ADDR_LEN           6
-
 #define NUM_TX_DESC            64      /* [8..1024] */
 #define NUM_RX_DESC            64      /* [8..8192] */
 #define TX_RING_BYTES          (NUM_TX_DESC * sizeof(struct TxDesc))
@@ -1601,7 +1599,7 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev,
        }
 
        /* Get MAC address from EEPROM */
-       for (i = 0; i < MAC_ADDR_LEN / 2; i++) {
+       for (i = 0; i < ETH_ALEN / 2; i++) {
                u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i);
 
                ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(w);
@@ -1653,7 +1651,7 @@ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev,
        udelay(50);
        pci_read_config_byte(isa_bridge, 0x48, &reg);
 
-        for (i = 0; i < MAC_ADDR_LEN; i++) {
+        for (i = 0; i < ETH_ALEN; i++) {
                 outb(0x9 + i, 0x78);
                 dev->dev_addr[i] = inb(0x79);
         }
@@ -1692,7 +1690,7 @@ static inline void sis190_init_rxfilter(struct net_device *dev)
         */
        SIS_W16(RxMacControl, ctl & ~0x0f00);
 
-       for (i = 0; i < MAC_ADDR_LEN; i++)
+       for (i = 0; i < ETH_ALEN; i++)
                SIS_W8(RxMacAddr + i, dev->dev_addr[i]);
 
        SIS_W16(RxMacControl, ctl);
@@ -1760,9 +1758,10 @@ static void sis190_get_drvinfo(struct net_device *dev,
 {
        struct sis190_private *tp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(tp->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(tp->pci_dev),
+               sizeof(info->bus_info));
 }
 
 static int sis190_get_regs_len(struct net_device *dev)
index a184abc5ef11802afcefc86300d3fda2be7b763f..c8efc708c792a63d47bb608d1ff16659613bd0c5 100644 (file)
@@ -1991,9 +1991,10 @@ static void sis900_get_drvinfo(struct net_device *net_dev,
 {
        struct sis900_private *sis_priv = netdev_priv(net_dev);
 
-       strcpy (info->driver, SIS900_MODULE_NAME);
-       strcpy (info->version, SIS900_DRV_VERSION);
-       strcpy (info->bus_info, pci_name(sis_priv->pci_dev));
+       strlcpy(info->driver, SIS900_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, SIS900_DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(sis_priv->pci_dev),
+               sizeof(info->bus_info));
 }
 
 static u32 sis900_get_msglevel(struct net_device *net_dev)
index 0a5dfb814157f66343af36f4724718aa3503d4c0..2c077ce0b6d6416d56f200ba1b62a080ce1ac11e 100644 (file)
@@ -1414,9 +1414,9 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *
 {
        struct epic_private *np = netdev_priv(dev);
 
-       strcpy (info->driver, DRV_NAME);
-       strcpy (info->version, DRV_VERSION);
-       strcpy (info->bus_info, pci_name(np->pci_dev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index cbfa981871314a4e5605117b88b275df9eb215ff..ada927aba7a517f64804b06852e33f1f4c2ede39 100644 (file)
@@ -1909,8 +1909,8 @@ static int check_if_running(struct net_device *dev)
 
 static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 }
 
 static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
index edb24b0e337be8d27af132519d771e1f58aa36ac..a9efbdfe5302df8cc22829b37ed53cef6aa653b8 100644 (file)
@@ -279,9 +279,10 @@ static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev,
 {
        struct smsc9420_pdata *pd = netdev_priv(netdev);
 
-       strcpy(drvinfo->driver, DRV_NAME);
-       strcpy(drvinfo->bus_info, pci_name(pd->pdev));
-       strcpy(drvinfo->version, DRV_VERSION);
+       strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->bus_info, pci_name(pd->pdev),
+               sizeof(drvinfo->bus_info));
+       strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
 }
 
 static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev)
index 0395f9eba801e9281f6af9a9fca8dc12057b55e4..ed83c4c47b8a273383b489106c1f73a74144988c 100644 (file)
@@ -185,9 +185,10 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
        struct stmmac_priv *priv = netdev_priv(dev);
 
        if (priv->plat->has_gmac)
-               strcpy(info->driver, GMAC_ETHTOOL_NAME);
+               strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver));
        else
-               strcpy(info->driver, MAC100_ETHTOOL_NAME);
+               strlcpy(info->driver, MAC100_ETHTOOL_NAME,
+                       sizeof(info->driver));
 
        strcpy(info->version, DRV_MODULE_VERSION);
        info->fw_version[0] = '\0';
index 8ea770a89f2556b8c762f2af345e5044d45ff9ba..de71859bb2954ac0812156be940e6727d9db393b 100644 (file)
@@ -1466,7 +1466,8 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static u32 stmmac_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t stmmac_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
index fd40988c19a66af818bb006bee438fd5426f861a..f10665f594c4f8aaaf37b1e81632e80513f28447 100644 (file)
@@ -4532,10 +4532,9 @@ static void cas_set_multicast(struct net_device *dev)
 static void cas_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct cas *cp = netdev_priv(dev);
-       strncpy(info->driver, DRV_MODULE_NAME, ETHTOOL_BUSINFO_LEN);
-       strncpy(info->version, DRV_MODULE_VERSION, ETHTOOL_BUSINFO_LEN);
-       info->fw_version[0] = '\0';
-       strncpy(info->bus_info, pci_name(cp->pdev), ETHTOOL_BUSINFO_LEN);
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(cp->pdev), sizeof(info->bus_info));
        info->regdump_len = cp->casreg_len < CAS_MAX_REGS ?
                cp->casreg_len : CAS_MAX_REGS;
        info->n_stats = CAS_NUM_STAT_KEYS;
index 73c708107a379543b8695dd470a771f47b30feac..9997be525089d4c0f4b75797379907d9b98a8690 100644 (file)
@@ -1151,19 +1151,8 @@ static int link_status_mii(struct niu *np, int *link_up_p)
                supported |= SUPPORTED_1000baseT_Full;
        lp->supported = supported;
 
-       advertising = 0;
-       if (advert & ADVERTISE_10HALF)
-               advertising |= ADVERTISED_10baseT_Half;
-       if (advert & ADVERTISE_10FULL)
-               advertising |= ADVERTISED_10baseT_Full;
-       if (advert & ADVERTISE_100HALF)
-               advertising |= ADVERTISED_100baseT_Half;
-       if (advert & ADVERTISE_100FULL)
-               advertising |= ADVERTISED_100baseT_Full;
-       if (ctrl1000 & ADVERTISE_1000HALF)
-               advertising |= ADVERTISED_1000baseT_Half;
-       if (ctrl1000 & ADVERTISE_1000FULL)
-               advertising |= ADVERTISED_1000baseT_Full;
+       advertising = mii_adv_to_ethtool_100bt(advert);
+       advertising |= mii_adv_to_ethtool_1000T(ctrl1000);
 
        if (bmcr & BMCR_ANENABLE) {
                int neg, neg1000;
@@ -6823,12 +6812,13 @@ static void niu_get_drvinfo(struct net_device *dev,
        struct niu *np = netdev_priv(dev);
        struct niu_vpd *vpd = &np->vpd;
 
-       strcpy(info->driver, DRV_MODULE_NAME);
-       strcpy(info->version, DRV_MODULE_VERSION);
-       sprintf(info->fw_version, "%d.%d",
+       strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+       snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d",
                vpd->fcode_major, vpd->fcode_minor);
        if (np->parent->plat_type != PLAT_TYPE_NIU)
-               strcpy(info->bus_info, pci_name(np->pdev));
+               strlcpy(info->bus_info, pci_name(np->pdev),
+                       sizeof(info->bus_info));
 }
 
 static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index ceab215bb4a31f3f50b0c20465e2593f52385b4a..31441a870b0b84bba089b757a12d73d9657e451e 100644 (file)
@@ -2517,9 +2517,9 @@ static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct gem *gp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(gp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(gp->pdev), sizeof(info->bus_info));
 }
 
 static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index cf14ab9db5768f7781f7b9983120c01644fad0aa..eebd52f103657173dc0ddbbdb23d1d4eec845bca 100644 (file)
@@ -2457,11 +2457,11 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct happy_meal *hp = netdev_priv(dev);
 
-       strcpy(info->driver, "sunhme");
-       strcpy(info->version, "2.02");
+       strlcpy(info->driver, "sunhme", sizeof(info->driver));
+       strlcpy(info->version, "2.02", sizeof(info->version));
        if (hp->happy_flags & HFLAG_PCI) {
                struct pci_dev *pdev = hp->happy_dev;
-               strcpy(info->bus_info, pci_name(pdev));
+               strlcpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info));
        }
 #ifdef CONFIG_SBUS
        else {
@@ -2469,7 +2469,8 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
                struct platform_device *op = hp->happy_dev;
                regs = of_get_property(op->dev.of_node, "regs", NULL);
                if (regs)
-                       sprintf(info->bus_info, "SBUS:%d",
+                       snprintf(info->bus_info, sizeof(info->bus_info),
+                               "SBUS:%d",
                                regs->which_io);
        }
 #endif
index f34dd99fe57917c546414c47607180bee2e59467..5587ecdf32e322b71f952d947c3d8498918309a2 100644 (file)
@@ -2009,9 +2009,9 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
 {
        struct rhine_private *rp = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->bus_info, pci_name(rp->pdev));
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(rp->pdev), sizeof(info->bus_info));
 }
 
 static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
index 4535d7cc848edb5a4d775c562e75eaae9b2032d2..59bb5fd56afe60e0c3ed00b738575b9f64ec159d 100644 (file)
@@ -3270,9 +3270,9 @@ static int velocity_set_settings(struct net_device *dev,
 static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        struct velocity_info *vptr = netdev_priv(dev);
-       strcpy(info->driver, VELOCITY_NAME);
-       strcpy(info->version, VELOCITY_VERSION);
-       strcpy(info->bus_info, pci_name(vptr->pdev));
+       strlcpy(info->driver, VELOCITY_NAME, sizeof(info->driver));
+       strlcpy(info->version, VELOCITY_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, pci_name(vptr->pdev), sizeof(info->bus_info));
 }
 
 static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
index 2681b53820eefaf3edaa8e6e336b9b6de12d8bf0..1ade9e18d29937f2554507fcdac9ede165eacba8 100644 (file)
@@ -920,12 +920,26 @@ temac_poll_controller(struct net_device *ndev)
 }
 #endif
 
+static int temac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+       struct temac_local *lp = netdev_priv(ndev);
+
+       if (!netif_running(ndev))
+               return -EINVAL;
+
+       if (!lp->phy_dev)
+               return -EINVAL;
+
+       return phy_mii_ioctl(lp->phy_dev, rq, cmd);
+}
+
 static const struct net_device_ops temac_netdev_ops = {
        .ndo_open = temac_open,
        .ndo_stop = temac_stop,
        .ndo_start_xmit = temac_start_xmit,
        .ndo_set_mac_address = netdev_set_mac_address,
        .ndo_validate_addr = eth_validate_addr,
+       .ndo_do_ioctl = temac_ioctl,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = temac_poll_controller,
 #endif
index bbe8b7dbf3f381aadba59d6900c9aca7002adc6d..33979c3ac943ebff6c106cb1fb787aca07ea57d4 100644 (file)
@@ -1411,7 +1411,7 @@ do_open(struct net_device *dev)
 static void netdev_get_drvinfo(struct net_device *dev,
                               struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "xirc2ps_cs");
+       strlcpy(info->driver, "xirc2ps_cs", sizeof(info->driver));
        sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
 }
 
index 46b5f5fd686bab98b98aff86fbf3e43b0702ddb8..e05b645bbc323559b39e6d42c69744159774767d 100644 (file)
@@ -164,7 +164,7 @@ static const struct net_device_ops ifb_netdev_ops = {
        .ndo_validate_addr = eth_validate_addr,
 };
 
-#define IFB_FEATURES (NETIF_F_NO_CSUM | NETIF_F_SG  | NETIF_F_FRAGLIST | \
+#define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG  | NETIF_F_FRAGLIST | \
                      NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6      | \
                      NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX)
 
index 4ce9e5f2c069876a0fd4ec6d1446c25408411a33..b71998d0b5b495132b4e07e80f7fae6a93f634ef 100644 (file)
@@ -169,7 +169,7 @@ static void loopback_setup(struct net_device *dev)
        dev->features           = NETIF_F_SG | NETIF_F_FRAGLIST
                | NETIF_F_ALL_TSO
                | NETIF_F_UFO
-               | NETIF_F_NO_CSUM
+               | NETIF_F_HW_CSUM
                | NETIF_F_RXCSUM
                | NETIF_F_HIGHDMA
                | NETIF_F_LLTX
index c62e7816d54864d317b1c646c00c18bc78b97ead..d0a29627271331cded0fe4020ce2b81ce6aac009 100644 (file)
@@ -41,20 +41,8 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
        advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
        if (advert & LPA_LPACK)
                result |= ADVERTISED_Autoneg;
-       if (advert & ADVERTISE_10HALF)
-               result |= ADVERTISED_10baseT_Half;
-       if (advert & ADVERTISE_10FULL)
-               result |= ADVERTISED_10baseT_Full;
-       if (advert & ADVERTISE_100HALF)
-               result |= ADVERTISED_100baseT_Half;
-       if (advert & ADVERTISE_100FULL)
-               result |= ADVERTISED_100baseT_Full;
-       if (advert & ADVERTISE_PAUSE_CAP)
-               result |= ADVERTISED_Pause;
-       if (advert & ADVERTISE_PAUSE_ASYM)
-               result |= ADVERTISED_Asym_Pause;
-
-       return result;
+
+       return result | mii_adv_to_ethtool_100bt(advert);
 }
 
 /**
@@ -104,19 +92,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
                ecmd->autoneg = AUTONEG_ENABLE;
 
                ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
-               if (ctrl1000 & ADVERTISE_1000HALF)
-                       ecmd->advertising |= ADVERTISED_1000baseT_Half;
-               if (ctrl1000 & ADVERTISE_1000FULL)
-                       ecmd->advertising |= ADVERTISED_1000baseT_Full;
+               if (mii->supports_gmii)
+                       ecmd->advertising |= mii_adv_to_ethtool_1000T(ctrl1000);
 
                if (bmsr & BMSR_ANEGCOMPLETE) {
                        ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
-                       if (stat1000 & LPA_1000HALF)
-                               ecmd->lp_advertising |=
-                                       ADVERTISED_1000baseT_Half;
-                       if (stat1000 & LPA_1000FULL)
-                               ecmd->lp_advertising |=
-                                       ADVERTISED_1000baseT_Full;
+                       ecmd->lp_advertising |=
+                                            mii_lpa_to_ethtool_1000T(stat1000);
                } else {
                        ecmd->lp_advertising = 0;
                }
@@ -204,20 +186,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
                        advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
                        tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
                }
-               if (ecmd->advertising & ADVERTISED_10baseT_Half)
-                       tmp |= ADVERTISE_10HALF;
-               if (ecmd->advertising & ADVERTISED_10baseT_Full)
-                       tmp |= ADVERTISE_10FULL;
-               if (ecmd->advertising & ADVERTISED_100baseT_Half)
-                       tmp |= ADVERTISE_100HALF;
-               if (ecmd->advertising & ADVERTISED_100baseT_Full)
-                       tmp |= ADVERTISE_100FULL;
-               if (mii->supports_gmii) {
-                       if (ecmd->advertising & ADVERTISED_1000baseT_Half)
-                               tmp2 |= ADVERTISE_1000HALF;
-                       if (ecmd->advertising & ADVERTISED_1000baseT_Full)
-                               tmp2 |= ADVERTISE_1000FULL;
-               }
+               tmp |= ethtool_adv_to_mii_100bt(ecmd->advertising);
+
+               if (mii->supports_gmii)
+                       tmp2 |= ethtool_adv_to_mii_1000T(ecmd->advertising);
                if (advert != tmp) {
                        mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
                        mii->advertising = tmp;
index 65391891d8c41a180592d500825df75f67b44e4c..daec9b05d168ca4f0f103f3638fcc3259e9ea304 100644 (file)
@@ -202,6 +202,14 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
        return 0;
 }
 
+static int mdiobb_reset(struct mii_bus *bus)
+{
+       struct mdiobb_ctrl *ctrl = bus->priv;
+       if (ctrl->reset)
+               ctrl->reset(bus);
+       return 0;
+}
+
 struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 {
        struct mii_bus *bus;
@@ -214,6 +222,7 @@ struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
 
        bus->read = mdiobb_read;
        bus->write = mdiobb_write;
+       bus->reset = mdiobb_reset;
        bus->priv = ctrl;
 
        return bus;
index 2843c90f712f40c27c0688cb336dc87dbede054e..89c5a3eccc12daa760fa0e1e6c73e392c0a81f3e 100644 (file)
@@ -95,6 +95,7 @@ static struct mii_bus * __devinit mdio_gpio_bus_init(struct device *dev,
                goto out;
 
        bitbang->ctrl.ops = &mdio_gpio_ops;
+       bitbang->ctrl.reset = pdata->reset;
        bitbang->mdc = pdata->mdc;
        bitbang->mdio = pdata->mdio;
 
index 83a5a5afec67f942f4a627cc0cd1b0f752325966..edb905f80115a4f484485ffbb9168163d487a093 100644 (file)
@@ -563,20 +563,9 @@ static int genphy_config_advert(struct phy_device *phydev)
        if (adv < 0)
                return adv;
 
-       adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | 
+       adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
                 ADVERTISE_PAUSE_ASYM);
-       if (advertise & ADVERTISED_10baseT_Half)
-               adv |= ADVERTISE_10HALF;
-       if (advertise & ADVERTISED_10baseT_Full)
-               adv |= ADVERTISE_10FULL;
-       if (advertise & ADVERTISED_100baseT_Half)
-               adv |= ADVERTISE_100HALF;
-       if (advertise & ADVERTISED_100baseT_Full)
-               adv |= ADVERTISE_100FULL;
-       if (advertise & ADVERTISED_Pause)
-               adv |= ADVERTISE_PAUSE_CAP;
-       if (advertise & ADVERTISED_Asym_Pause)
-               adv |= ADVERTISE_PAUSE_ASYM;
+       adv |= ethtool_adv_to_mii_100bt(advertise);
 
        if (adv != oldadv) {
                err = phy_write(phydev, MII_ADVERTISE, adv);
@@ -595,10 +584,7 @@ static int genphy_config_advert(struct phy_device *phydev)
                        return adv;
 
                adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
-               if (advertise & SUPPORTED_1000baseT_Half)
-                       adv |= ADVERTISE_1000HALF;
-               if (advertise & SUPPORTED_1000baseT_Full)
-                       adv |= ADVERTISE_1000FULL;
+               adv |= ethtool_adv_to_mii_1000T(advertise);
 
                if (adv != oldadv) {
                        err = phy_write(phydev, MII_CTRL1000, adv);
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
new file mode 100644 (file)
index 0000000..248a144
--- /dev/null
@@ -0,0 +1,43 @@
+menuconfig NET_TEAM
+       tristate "Ethernet team driver support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       ---help---
+         This allows one to create virtual interfaces that teams together
+         multiple ethernet devices.
+
+         Team devices can be added using the "ip" command from the
+         iproute2 package:
+
+         "ip link add link [ address MAC ] [ NAME ] type team"
+
+         To compile this driver as a module, choose M here: the module
+         will be called team.
+
+if NET_TEAM
+
+config NET_TEAM_MODE_ROUNDROBIN
+       tristate "Round-robin mode support"
+       depends on NET_TEAM
+       ---help---
+         Basic mode where port used for transmitting packets is selected in
+         round-robin fashion using packet counter.
+
+         All added ports are setup to have bond's mac address.
+
+         To compile this team mode as a module, choose M here: the module
+         will be called team_mode_roundrobin.
+
+config NET_TEAM_MODE_ACTIVEBACKUP
+       tristate "Active-backup mode support"
+       depends on NET_TEAM
+       ---help---
+         Only one port is active at a time and the rest of ports are used
+         for backup.
+
+         Mac addresses of ports are not modified. Userspace is responsible
+         to do so.
+
+         To compile this team mode as a module, choose M here: the module
+         will be called team_mode_activebackup.
+
+endif # NET_TEAM
diff --git a/drivers/net/team/Makefile b/drivers/net/team/Makefile
new file mode 100644 (file)
index 0000000..85f2028
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the network team driver
+#
+
+obj-$(CONFIG_NET_TEAM) += team.o
+obj-$(CONFIG_NET_TEAM_MODE_ROUNDROBIN) += team_mode_roundrobin.o
+obj-$(CONFIG_NET_TEAM_MODE_ACTIVEBACKUP) += team_mode_activebackup.o
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
new file mode 100644 (file)
index 0000000..064155d
--- /dev/null
@@ -0,0 +1,1661 @@
+/*
+ * net/drivers/team/team.c - Network team device driver
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/rcupdate.h>
+#include <linux/errno.h>
+#include <linux/ctype.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/socket.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/rtnetlink.h>
+#include <net/genetlink.h>
+#include <net/netlink.h>
+#include <linux/if_team.h>
+
+#define DRV_NAME "team"
+
+
+/**********
+ * Helpers
+ **********/
+
+#define team_port_exists(dev) (dev->priv_flags & IFF_TEAM_PORT)
+
+static struct team_port *team_port_get_rcu(const struct net_device *dev)
+{
+       struct team_port *port = rcu_dereference(dev->rx_handler_data);
+
+       return team_port_exists(dev) ? port : NULL;
+}
+
+static struct team_port *team_port_get_rtnl(const struct net_device *dev)
+{
+       struct team_port *port = rtnl_dereference(dev->rx_handler_data);
+
+       return team_port_exists(dev) ? port : NULL;
+}
+
+/*
+ * Since the ability to change mac address for open port device is tested in
+ * team_port_add, this function can be called without control of return value
+ */
+static int __set_port_mac(struct net_device *port_dev,
+                         const unsigned char *dev_addr)
+{
+       struct sockaddr addr;
+
+       memcpy(addr.sa_data, dev_addr, ETH_ALEN);
+       addr.sa_family = ARPHRD_ETHER;
+       return dev_set_mac_address(port_dev, &addr);
+}
+
+int team_port_set_orig_mac(struct team_port *port)
+{
+       return __set_port_mac(port->dev, port->orig.dev_addr);
+}
+
+int team_port_set_team_mac(struct team_port *port)
+{
+       return __set_port_mac(port->dev, port->team->dev->dev_addr);
+}
+EXPORT_SYMBOL(team_port_set_team_mac);
+
+
+/*******************
+ * Options handling
+ *******************/
+
+struct team_option *__team_find_option(struct team *team, const char *opt_name)
+{
+       struct team_option *option;
+
+       list_for_each_entry(option, &team->option_list, list) {
+               if (strcmp(option->name, opt_name) == 0)
+                       return option;
+       }
+       return NULL;
+}
+
+int team_options_register(struct team *team,
+                         const struct team_option *option,
+                         size_t option_count)
+{
+       int i;
+       struct team_option **dst_opts;
+       int err;
+
+       dst_opts = kzalloc(sizeof(struct team_option *) * option_count,
+                          GFP_KERNEL);
+       if (!dst_opts)
+               return -ENOMEM;
+       for (i = 0; i < option_count; i++, option++) {
+               if (__team_find_option(team, option->name)) {
+                       err = -EEXIST;
+                       goto rollback;
+               }
+               dst_opts[i] = kmemdup(option, sizeof(*option), GFP_KERNEL);
+               if (!dst_opts[i]) {
+                       err = -ENOMEM;
+                       goto rollback;
+               }
+       }
+
+       for (i = 0; i < option_count; i++)
+               list_add_tail(&dst_opts[i]->list, &team->option_list);
+
+       kfree(dst_opts);
+       return 0;
+
+rollback:
+       for (i = 0; i < option_count; i++)
+               kfree(dst_opts[i]);
+
+       kfree(dst_opts);
+       return err;
+}
+
+EXPORT_SYMBOL(team_options_register);
+
+static void __team_options_change_check(struct team *team,
+                                       struct team_option *changed_option);
+
+static void __team_options_unregister(struct team *team,
+                                     const struct team_option *option,
+                                     size_t option_count)
+{
+       int i;
+
+       for (i = 0; i < option_count; i++, option++) {
+               struct team_option *del_opt;
+
+               del_opt = __team_find_option(team, option->name);
+               if (del_opt) {
+                       list_del(&del_opt->list);
+                       kfree(del_opt);
+               }
+       }
+}
+
+void team_options_unregister(struct team *team,
+                            const struct team_option *option,
+                            size_t option_count)
+{
+       __team_options_unregister(team, option, option_count);
+       __team_options_change_check(team, NULL);
+}
+EXPORT_SYMBOL(team_options_unregister);
+
+static int team_option_get(struct team *team, struct team_option *option,
+                          void *arg)
+{
+       return option->getter(team, arg);
+}
+
+static int team_option_set(struct team *team, struct team_option *option,
+                          void *arg)
+{
+       int err;
+
+       err = option->setter(team, arg);
+       if (err)
+               return err;
+
+       __team_options_change_check(team, option);
+       return err;
+}
+
+/****************
+ * Mode handling
+ ****************/
+
+static LIST_HEAD(mode_list);
+static DEFINE_SPINLOCK(mode_list_lock);
+
+static struct team_mode *__find_mode(const char *kind)
+{
+       struct team_mode *mode;
+
+       list_for_each_entry(mode, &mode_list, list) {
+               if (strcmp(mode->kind, kind) == 0)
+                       return mode;
+       }
+       return NULL;
+}
+
+static bool is_good_mode_name(const char *name)
+{
+       while (*name != '\0') {
+               if (!isalpha(*name) && !isdigit(*name) && *name != '_')
+                       return false;
+               name++;
+       }
+       return true;
+}
+
+int team_mode_register(struct team_mode *mode)
+{
+       int err = 0;
+
+       if (!is_good_mode_name(mode->kind) ||
+           mode->priv_size > TEAM_MODE_PRIV_SIZE)
+               return -EINVAL;
+       spin_lock(&mode_list_lock);
+       if (__find_mode(mode->kind)) {
+               err = -EEXIST;
+               goto unlock;
+       }
+       list_add_tail(&mode->list, &mode_list);
+unlock:
+       spin_unlock(&mode_list_lock);
+       return err;
+}
+EXPORT_SYMBOL(team_mode_register);
+
+int team_mode_unregister(struct team_mode *mode)
+{
+       spin_lock(&mode_list_lock);
+       list_del_init(&mode->list);
+       spin_unlock(&mode_list_lock);
+       return 0;
+}
+EXPORT_SYMBOL(team_mode_unregister);
+
+static struct team_mode *team_mode_get(const char *kind)
+{
+       struct team_mode *mode;
+
+       spin_lock(&mode_list_lock);
+       mode = __find_mode(kind);
+       if (!mode) {
+               spin_unlock(&mode_list_lock);
+               request_module("team-mode-%s", kind);
+               spin_lock(&mode_list_lock);
+               mode = __find_mode(kind);
+       }
+       if (mode)
+               if (!try_module_get(mode->owner))
+                       mode = NULL;
+
+       spin_unlock(&mode_list_lock);
+       return mode;
+}
+
+static void team_mode_put(const struct team_mode *mode)
+{
+       module_put(mode->owner);
+}
+
+static bool team_dummy_transmit(struct team *team, struct sk_buff *skb)
+{
+       dev_kfree_skb_any(skb);
+       return false;
+}
+
+rx_handler_result_t team_dummy_receive(struct team *team,
+                                      struct team_port *port,
+                                      struct sk_buff *skb)
+{
+       return RX_HANDLER_ANOTHER;
+}
+
+static void team_adjust_ops(struct team *team)
+{
+       /*
+        * To avoid checks in rx/tx skb paths, ensure here that non-null and
+        * correct ops are always set.
+        */
+
+       if (list_empty(&team->port_list) ||
+           !team->mode || !team->mode->ops->transmit)
+               team->ops.transmit = team_dummy_transmit;
+       else
+               team->ops.transmit = team->mode->ops->transmit;
+
+       if (list_empty(&team->port_list) ||
+           !team->mode || !team->mode->ops->receive)
+               team->ops.receive = team_dummy_receive;
+       else
+               team->ops.receive = team->mode->ops->receive;
+}
+
+/*
+ * We can benefit from the fact that it's ensured no port is present
+ * at the time of mode change. Therefore no packets are in fly so there's no
+ * need to set mode operations in any special way.
+ */
+static int __team_change_mode(struct team *team,
+                             const struct team_mode *new_mode)
+{
+       /* Check if mode was previously set and do cleanup if so */
+       if (team->mode) {
+               void (*exit_op)(struct team *team) = team->ops.exit;
+
+               /* Clear ops area so no callback is called any longer */
+               memset(&team->ops, 0, sizeof(struct team_mode_ops));
+               team_adjust_ops(team);
+
+               if (exit_op)
+                       exit_op(team);
+               team_mode_put(team->mode);
+               team->mode = NULL;
+               /* zero private data area */
+               memset(&team->mode_priv, 0,
+                      sizeof(struct team) - offsetof(struct team, mode_priv));
+       }
+
+       if (!new_mode)
+               return 0;
+
+       if (new_mode->ops->init) {
+               int err;
+
+               err = new_mode->ops->init(team);
+               if (err)
+                       return err;
+       }
+
+       team->mode = new_mode;
+       memcpy(&team->ops, new_mode->ops, sizeof(struct team_mode_ops));
+       team_adjust_ops(team);
+
+       return 0;
+}
+
+static int team_change_mode(struct team *team, const char *kind)
+{
+       struct team_mode *new_mode;
+       struct net_device *dev = team->dev;
+       int err;
+
+       if (!list_empty(&team->port_list)) {
+               netdev_err(dev, "No ports can be present during mode change\n");
+               return -EBUSY;
+       }
+
+       if (team->mode && strcmp(team->mode->kind, kind) == 0) {
+               netdev_err(dev, "Unable to change to the same mode the team is in\n");
+               return -EINVAL;
+       }
+
+       new_mode = team_mode_get(kind);
+       if (!new_mode) {
+               netdev_err(dev, "Mode \"%s\" not found\n", kind);
+               return -EINVAL;
+       }
+
+       err = __team_change_mode(team, new_mode);
+       if (err) {
+               netdev_err(dev, "Failed to change to mode \"%s\"\n", kind);
+               team_mode_put(new_mode);
+               return err;
+       }
+
+       netdev_info(dev, "Mode changed to \"%s\"\n", kind);
+       return 0;
+}
+
+
+/************************
+ * Rx path frame handler
+ ************************/
+
+/* note: already called with rcu_read_lock */
+static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
+{
+       struct sk_buff *skb = *pskb;
+       struct team_port *port;
+       struct team *team;
+       rx_handler_result_t res;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               return RX_HANDLER_CONSUMED;
+
+       *pskb = skb;
+
+       port = team_port_get_rcu(skb->dev);
+       team = port->team;
+
+       res = team->ops.receive(team, port, skb);
+       if (res == RX_HANDLER_ANOTHER) {
+               struct team_pcpu_stats *pcpu_stats;
+
+               pcpu_stats = this_cpu_ptr(team->pcpu_stats);
+               u64_stats_update_begin(&pcpu_stats->syncp);
+               pcpu_stats->rx_packets++;
+               pcpu_stats->rx_bytes += skb->len;
+               if (skb->pkt_type == PACKET_MULTICAST)
+                       pcpu_stats->rx_multicast++;
+               u64_stats_update_end(&pcpu_stats->syncp);
+
+               skb->dev = team->dev;
+       } else {
+               this_cpu_inc(team->pcpu_stats->rx_dropped);
+       }
+
+       return res;
+}
+
+
+/****************
+ * Port handling
+ ****************/
+
+static bool team_port_find(const struct team *team,
+                          const struct team_port *port)
+{
+       struct team_port *cur;
+
+       list_for_each_entry(cur, &team->port_list, list)
+               if (cur == port)
+                       return true;
+       return false;
+}
+
+/*
+ * Add/delete port to the team port list. Write guarded by rtnl_lock.
+ * Takes care of correct port->index setup (might be racy).
+ */
+static void team_port_list_add_port(struct team *team,
+                                   struct team_port *port)
+{
+       port->index = team->port_count++;
+       hlist_add_head_rcu(&port->hlist,
+                          team_port_index_hash(team, port->index));
+       list_add_tail_rcu(&port->list, &team->port_list);
+}
+
+static void __reconstruct_port_hlist(struct team *team, int rm_index)
+{
+       int i;
+       struct team_port *port;
+
+       for (i = rm_index + 1; i < team->port_count; i++) {
+               port = team_get_port_by_index(team, i);
+               hlist_del_rcu(&port->hlist);
+               port->index--;
+               hlist_add_head_rcu(&port->hlist,
+                                  team_port_index_hash(team, port->index));
+       }
+}
+
+static void team_port_list_del_port(struct team *team,
+                                  struct team_port *port)
+{
+       int rm_index = port->index;
+
+       hlist_del_rcu(&port->hlist);
+       list_del_rcu(&port->list);
+       __reconstruct_port_hlist(team, rm_index);
+       team->port_count--;
+}
+
+#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
+                           NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
+                           NETIF_F_HIGHDMA | NETIF_F_LRO)
+
+static void __team_compute_features(struct team *team)
+{
+       struct team_port *port;
+       u32 vlan_features = TEAM_VLAN_FEATURES;
+       unsigned short max_hard_header_len = ETH_HLEN;
+
+       list_for_each_entry(port, &team->port_list, list) {
+               vlan_features = netdev_increment_features(vlan_features,
+                                       port->dev->vlan_features,
+                                       TEAM_VLAN_FEATURES);
+
+               if (port->dev->hard_header_len > max_hard_header_len)
+                       max_hard_header_len = port->dev->hard_header_len;
+       }
+
+       team->dev->vlan_features = vlan_features;
+       team->dev->hard_header_len = max_hard_header_len;
+
+       netdev_change_features(team->dev);
+}
+
+static void team_compute_features(struct team *team)
+{
+       mutex_lock(&team->lock);
+       __team_compute_features(team);
+       mutex_unlock(&team->lock);
+}
+
+static int team_port_enter(struct team *team, struct team_port *port)
+{
+       int err = 0;
+
+       dev_hold(team->dev);
+       port->dev->priv_flags |= IFF_TEAM_PORT;
+       if (team->ops.port_enter) {
+               err = team->ops.port_enter(team, port);
+               if (err) {
+                       netdev_err(team->dev, "Device %s failed to enter team mode\n",
+                                  port->dev->name);
+                       goto err_port_enter;
+               }
+       }
+
+       return 0;
+
+err_port_enter:
+       port->dev->priv_flags &= ~IFF_TEAM_PORT;
+       dev_put(team->dev);
+
+       return err;
+}
+
+static void team_port_leave(struct team *team, struct team_port *port)
+{
+       if (team->ops.port_leave)
+               team->ops.port_leave(team, port);
+       port->dev->priv_flags &= ~IFF_TEAM_PORT;
+       dev_put(team->dev);
+}
+
+static void __team_port_change_check(struct team_port *port, bool linkup);
+
+static int team_port_add(struct team *team, struct net_device *port_dev)
+{
+       struct net_device *dev = team->dev;
+       struct team_port *port;
+       char *portname = port_dev->name;
+       int err;
+
+       if (port_dev->flags & IFF_LOOPBACK ||
+           port_dev->type != ARPHRD_ETHER) {
+               netdev_err(dev, "Device %s is of an unsupported type\n",
+                          portname);
+               return -EINVAL;
+       }
+
+       if (team_port_exists(port_dev)) {
+               netdev_err(dev, "Device %s is already a port "
+                               "of a team device\n", portname);
+               return -EBUSY;
+       }
+
+       if (port_dev->flags & IFF_UP) {
+               netdev_err(dev, "Device %s is up. Set it down before adding it as a team port\n",
+                          portname);
+               return -EBUSY;
+       }
+
+       port = kzalloc(sizeof(struct team_port), GFP_KERNEL);
+       if (!port)
+               return -ENOMEM;
+
+       port->dev = port_dev;
+       port->team = team;
+
+       port->orig.mtu = port_dev->mtu;
+       err = dev_set_mtu(port_dev, dev->mtu);
+       if (err) {
+               netdev_dbg(dev, "Error %d calling dev_set_mtu\n", err);
+               goto err_set_mtu;
+       }
+
+       memcpy(port->orig.dev_addr, port_dev->dev_addr, ETH_ALEN);
+
+       err = team_port_enter(team, port);
+       if (err) {
+               netdev_err(dev, "Device %s failed to enter team mode\n",
+                          portname);
+               goto err_port_enter;
+       }
+
+       err = dev_open(port_dev);
+       if (err) {
+               netdev_dbg(dev, "Device %s opening failed\n",
+                          portname);
+               goto err_dev_open;
+       }
+
+       err = netdev_set_master(port_dev, dev);
+       if (err) {
+               netdev_err(dev, "Device %s failed to set master\n", portname);
+               goto err_set_master;
+       }
+
+       err = netdev_rx_handler_register(port_dev, team_handle_frame,
+                                        port);
+       if (err) {
+               netdev_err(dev, "Device %s failed to register rx_handler\n",
+                          portname);
+               goto err_handler_register;
+       }
+
+       team_port_list_add_port(team, port);
+       team_adjust_ops(team);
+       __team_compute_features(team);
+       __team_port_change_check(port, !!netif_carrier_ok(port_dev));
+
+       netdev_info(dev, "Port device %s added\n", portname);
+
+       return 0;
+
+err_handler_register:
+       netdev_set_master(port_dev, NULL);
+
+err_set_master:
+       dev_close(port_dev);
+
+err_dev_open:
+       team_port_leave(team, port);
+       team_port_set_orig_mac(port);
+
+err_port_enter:
+       dev_set_mtu(port_dev, port->orig.mtu);
+
+err_set_mtu:
+       kfree(port);
+
+       return err;
+}
+
+static int team_port_del(struct team *team, struct net_device *port_dev)
+{
+       struct net_device *dev = team->dev;
+       struct team_port *port;
+       char *portname = port_dev->name;
+
+       port = team_port_get_rtnl(port_dev);
+       if (!port || !team_port_find(team, port)) {
+               netdev_err(dev, "Device %s does not act as a port of this team\n",
+                          portname);
+               return -ENOENT;
+       }
+
+       __team_port_change_check(port, false);
+       team_port_list_del_port(team, port);
+       team_adjust_ops(team);
+       netdev_rx_handler_unregister(port_dev);
+       netdev_set_master(port_dev, NULL);
+       dev_close(port_dev);
+       team_port_leave(team, port);
+       team_port_set_orig_mac(port);
+       dev_set_mtu(port_dev, port->orig.mtu);
+       synchronize_rcu();
+       kfree(port);
+       netdev_info(dev, "Port device %s removed\n", portname);
+       __team_compute_features(team);
+
+       return 0;
+}
+
+
+/*****************
+ * Net device ops
+ *****************/
+
+static const char team_no_mode_kind[] = "*NOMODE*";
+
+static int team_mode_option_get(struct team *team, void *arg)
+{
+       const char **str = arg;
+
+       *str = team->mode ? team->mode->kind : team_no_mode_kind;
+       return 0;
+}
+
+static int team_mode_option_set(struct team *team, void *arg)
+{
+       const char **str = arg;
+
+       return team_change_mode(team, *str);
+}
+
+static const struct team_option team_options[] = {
+       {
+               .name = "mode",
+               .type = TEAM_OPTION_TYPE_STRING,
+               .getter = team_mode_option_get,
+               .setter = team_mode_option_set,
+       },
+};
+
+static int team_init(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       int i;
+       int err;
+
+       team->dev = dev;
+       mutex_init(&team->lock);
+
+       team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
+       if (!team->pcpu_stats)
+               return -ENOMEM;
+
+       for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
+               INIT_HLIST_HEAD(&team->port_hlist[i]);
+       INIT_LIST_HEAD(&team->port_list);
+
+       team_adjust_ops(team);
+
+       INIT_LIST_HEAD(&team->option_list);
+       err = team_options_register(team, team_options, ARRAY_SIZE(team_options));
+       if (err)
+               goto err_options_register;
+       netif_carrier_off(dev);
+
+       return 0;
+
+err_options_register:
+       free_percpu(team->pcpu_stats);
+
+       return err;
+}
+
+static void team_uninit(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       struct team_port *tmp;
+
+       mutex_lock(&team->lock);
+       list_for_each_entry_safe(port, tmp, &team->port_list, list)
+               team_port_del(team, port->dev);
+
+       __team_change_mode(team, NULL); /* cleanup */
+       __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+       mutex_unlock(&team->lock);
+}
+
+static void team_destructor(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+
+       free_percpu(team->pcpu_stats);
+       free_netdev(dev);
+}
+
+static int team_open(struct net_device *dev)
+{
+       netif_carrier_on(dev);
+       return 0;
+}
+
+static int team_close(struct net_device *dev)
+{
+       netif_carrier_off(dev);
+       return 0;
+}
+
+/*
+ * note: already called with rcu_read_lock
+ */
+static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       bool tx_success = false;
+       unsigned int len = skb->len;
+
+       tx_success = team->ops.transmit(team, skb);
+       if (tx_success) {
+               struct team_pcpu_stats *pcpu_stats;
+
+               pcpu_stats = this_cpu_ptr(team->pcpu_stats);
+               u64_stats_update_begin(&pcpu_stats->syncp);
+               pcpu_stats->tx_packets++;
+               pcpu_stats->tx_bytes += len;
+               u64_stats_update_end(&pcpu_stats->syncp);
+       } else {
+               this_cpu_inc(team->pcpu_stats->tx_dropped);
+       }
+
+       return NETDEV_TX_OK;
+}
+
+static void team_change_rx_flags(struct net_device *dev, int change)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       int inc;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               if (change & IFF_PROMISC) {
+                       inc = dev->flags & IFF_PROMISC ? 1 : -1;
+                       dev_set_promiscuity(port->dev, inc);
+               }
+               if (change & IFF_ALLMULTI) {
+                       inc = dev->flags & IFF_ALLMULTI ? 1 : -1;
+                       dev_set_allmulti(port->dev, inc);
+               }
+       }
+       rcu_read_unlock();
+}
+
+static void team_set_rx_mode(struct net_device *dev)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               dev_uc_sync(port->dev, dev);
+               dev_mc_sync(port->dev, dev);
+       }
+       rcu_read_unlock();
+}
+
+static int team_set_mac_address(struct net_device *dev, void *p)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       struct sockaddr *addr = p;
+
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list)
+               if (team->ops.port_change_mac)
+                       team->ops.port_change_mac(team, port);
+       rcu_read_unlock();
+       return 0;
+}
+
+static int team_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+       int err;
+
+       /*
+        * Alhough this is reader, it's guarded by team lock. It's not possible
+        * to traverse list in reverse under rcu_read_lock
+        */
+       mutex_lock(&team->lock);
+       list_for_each_entry(port, &team->port_list, list) {
+               err = dev_set_mtu(port->dev, new_mtu);
+               if (err) {
+                       netdev_err(dev, "Device %s failed to change mtu",
+                                  port->dev->name);
+                       goto unwind;
+               }
+       }
+       mutex_unlock(&team->lock);
+
+       dev->mtu = new_mtu;
+
+       return 0;
+
+unwind:
+       list_for_each_entry_continue_reverse(port, &team->port_list, list)
+               dev_set_mtu(port->dev, dev->mtu);
+       mutex_unlock(&team->lock);
+
+       return err;
+}
+
+static struct rtnl_link_stats64 *
+team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_pcpu_stats *p;
+       u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
+       u32 rx_dropped = 0, tx_dropped = 0;
+       unsigned int start;
+       int i;
+
+       for_each_possible_cpu(i) {
+               p = per_cpu_ptr(team->pcpu_stats, i);
+               do {
+                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       rx_packets      = p->rx_packets;
+                       rx_bytes        = p->rx_bytes;
+                       rx_multicast    = p->rx_multicast;
+                       tx_packets      = p->tx_packets;
+                       tx_bytes        = p->tx_bytes;
+               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+
+               stats->rx_packets       += rx_packets;
+               stats->rx_bytes         += rx_bytes;
+               stats->multicast        += rx_multicast;
+               stats->tx_packets       += tx_packets;
+               stats->tx_bytes         += tx_bytes;
+               /*
+                * rx_dropped & tx_dropped are u32, updated
+                * without syncp protection.
+                */
+               rx_dropped      += p->rx_dropped;
+               tx_dropped      += p->tx_dropped;
+       }
+       stats->rx_dropped       = rx_dropped;
+       stats->tx_dropped       = tx_dropped;
+       return stats;
+}
+
+static void team_vlan_rx_add_vid(struct net_device *dev, uint16_t vid)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               const struct net_device_ops *ops = port->dev->netdev_ops;
+
+               if (ops->ndo_vlan_rx_add_vid)
+                       ops->ndo_vlan_rx_add_vid(port->dev, vid);
+       }
+       rcu_read_unlock();
+}
+
+static void team_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+       struct team *team = netdev_priv(dev);
+       struct team_port *port;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               const struct net_device_ops *ops = port->dev->netdev_ops;
+
+               if (ops->ndo_vlan_rx_kill_vid)
+                       ops->ndo_vlan_rx_kill_vid(port->dev, vid);
+       }
+       rcu_read_unlock();
+}
+
+static int team_add_slave(struct net_device *dev, struct net_device *port_dev)
+{
+       struct team *team = netdev_priv(dev);
+       int err;
+
+       mutex_lock(&team->lock);
+       err = team_port_add(team, port_dev);
+       mutex_unlock(&team->lock);
+       return err;
+}
+
+static int team_del_slave(struct net_device *dev, struct net_device *port_dev)
+{
+       struct team *team = netdev_priv(dev);
+       int err;
+
+       mutex_lock(&team->lock);
+       err = team_port_del(team, port_dev);
+       mutex_unlock(&team->lock);
+       return err;
+}
+
+static netdev_features_t team_fix_features(struct net_device *dev,
+                                          netdev_features_t features)
+{
+       struct team_port *port;
+       struct team *team = netdev_priv(dev);
+       netdev_features_t mask;
+
+       mask = features;
+       features &= ~NETIF_F_ONE_FOR_ALL;
+       features |= NETIF_F_ALL_FOR_ALL;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               features = netdev_increment_features(features,
+                                                    port->dev->features,
+                                                    mask);
+       }
+       rcu_read_unlock();
+       return features;
+}
+
+static const struct net_device_ops team_netdev_ops = {
+       .ndo_init               = team_init,
+       .ndo_uninit             = team_uninit,
+       .ndo_open               = team_open,
+       .ndo_stop               = team_close,
+       .ndo_start_xmit         = team_xmit,
+       .ndo_change_rx_flags    = team_change_rx_flags,
+       .ndo_set_rx_mode        = team_set_rx_mode,
+       .ndo_set_mac_address    = team_set_mac_address,
+       .ndo_change_mtu         = team_change_mtu,
+       .ndo_get_stats64        = team_get_stats64,
+       .ndo_vlan_rx_add_vid    = team_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = team_vlan_rx_kill_vid,
+       .ndo_add_slave          = team_add_slave,
+       .ndo_del_slave          = team_del_slave,
+       .ndo_fix_features       = team_fix_features,
+};
+
+
+/***********************
+ * rt netlink interface
+ ***********************/
+
+static void team_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+
+       dev->netdev_ops = &team_netdev_ops;
+       dev->destructor = team_destructor;
+       dev->tx_queue_len = 0;
+       dev->flags |= IFF_MULTICAST;
+       dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
+
+       /*
+        * Indicate we support unicast address filtering. That way core won't
+        * bring us to promisc mode in case a unicast addr is added.
+        * Let this up to underlay drivers.
+        */
+       dev->priv_flags |= IFF_UNICAST_FLT;
+
+       dev->features |= NETIF_F_LLTX;
+       dev->features |= NETIF_F_GRO;
+       dev->hw_features = NETIF_F_HW_VLAN_TX |
+                          NETIF_F_HW_VLAN_RX |
+                          NETIF_F_HW_VLAN_FILTER;
+
+       dev->features |= dev->hw_features;
+}
+
+static int team_newlink(struct net *src_net, struct net_device *dev,
+                       struct nlattr *tb[], struct nlattr *data[])
+{
+       int err;
+
+       if (tb[IFLA_ADDRESS] == NULL)
+               random_ether_addr(dev->dev_addr);
+
+       err = register_netdevice(dev);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int team_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       if (tb[IFLA_ADDRESS]) {
+               if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+                       return -EINVAL;
+               if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+                       return -EADDRNOTAVAIL;
+       }
+       return 0;
+}
+
+static struct rtnl_link_ops team_link_ops __read_mostly = {
+       .kind           = DRV_NAME,
+       .priv_size      = sizeof(struct team),
+       .setup          = team_setup,
+       .newlink        = team_newlink,
+       .validate       = team_validate,
+};
+
+
+/***********************************
+ * Generic netlink custom interface
+ ***********************************/
+
+static struct genl_family team_nl_family = {
+       .id             = GENL_ID_GENERATE,
+       .name           = TEAM_GENL_NAME,
+       .version        = TEAM_GENL_VERSION,
+       .maxattr        = TEAM_ATTR_MAX,
+       .netnsok        = true,
+};
+
+static const struct nla_policy team_nl_policy[TEAM_ATTR_MAX + 1] = {
+       [TEAM_ATTR_UNSPEC]                      = { .type = NLA_UNSPEC, },
+       [TEAM_ATTR_TEAM_IFINDEX]                = { .type = NLA_U32 },
+       [TEAM_ATTR_LIST_OPTION]                 = { .type = NLA_NESTED },
+       [TEAM_ATTR_LIST_PORT]                   = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = {
+       [TEAM_ATTR_OPTION_UNSPEC]               = { .type = NLA_UNSPEC, },
+       [TEAM_ATTR_OPTION_NAME] = {
+               .type = NLA_STRING,
+               .len = TEAM_STRING_MAX_LEN,
+       },
+       [TEAM_ATTR_OPTION_CHANGED]              = { .type = NLA_FLAG },
+       [TEAM_ATTR_OPTION_TYPE]                 = { .type = NLA_U8 },
+       [TEAM_ATTR_OPTION_DATA] = {
+               .type = NLA_BINARY,
+               .len = TEAM_STRING_MAX_LEN,
+       },
+};
+
+static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
+{
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                         &team_nl_family, 0, TEAM_CMD_NOOP);
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto err_msg_put;
+       }
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
+
+err_msg_put:
+       nlmsg_free(msg);
+
+       return err;
+}
+
+/*
+ * Netlink cmd functions should be locked by following two functions.
+ * Since dev gets held here, that ensures dev won't disappear in between.
+ */
+static struct team *team_nl_team_get(struct genl_info *info)
+{
+       struct net *net = genl_info_net(info);
+       int ifindex;
+       struct net_device *dev;
+       struct team *team;
+
+       if (!info->attrs[TEAM_ATTR_TEAM_IFINDEX])
+               return NULL;
+
+       ifindex = nla_get_u32(info->attrs[TEAM_ATTR_TEAM_IFINDEX]);
+       dev = dev_get_by_index(net, ifindex);
+       if (!dev || dev->netdev_ops != &team_netdev_ops) {
+               if (dev)
+                       dev_put(dev);
+               return NULL;
+       }
+
+       team = netdev_priv(dev);
+       mutex_lock(&team->lock);
+       return team;
+}
+
+static void team_nl_team_put(struct team *team)
+{
+       mutex_unlock(&team->lock);
+       dev_put(team->dev);
+}
+
+static int team_nl_send_generic(struct genl_info *info, struct team *team,
+                               int (*fill_func)(struct sk_buff *skb,
+                                                struct genl_info *info,
+                                                int flags, struct team *team))
+{
+       struct sk_buff *skb;
+       int err;
+
+       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       err = fill_func(skb, info, NLM_F_ACK, team);
+       if (err < 0)
+               goto err_fill;
+
+       err = genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
+       return err;
+
+err_fill:
+       nlmsg_free(skb);
+       return err;
+}
+
+static int team_nl_fill_options_get_changed(struct sk_buff *skb,
+                                           u32 pid, u32 seq, int flags,
+                                           struct team *team,
+                                           struct team_option *changed_option)
+{
+       struct nlattr *option_list;
+       void *hdr;
+       struct team_option *option;
+
+       hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+                         TEAM_CMD_OPTIONS_GET);
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
+
+       NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
+       option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
+       if (!option_list)
+               return -EMSGSIZE;
+
+       list_for_each_entry(option, &team->option_list, list) {
+               struct nlattr *option_item;
+               long arg;
+
+               option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
+               if (!option_item)
+                       goto nla_put_failure;
+               NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_NAME, option->name);
+               if (option == changed_option)
+                       NLA_PUT_FLAG(skb, TEAM_ATTR_OPTION_CHANGED);
+               switch (option->type) {
+               case TEAM_OPTION_TYPE_U32:
+                       NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_U32);
+                       team_option_get(team, option, &arg);
+                       NLA_PUT_U32(skb, TEAM_ATTR_OPTION_DATA, arg);
+                       break;
+               case TEAM_OPTION_TYPE_STRING:
+                       NLA_PUT_U8(skb, TEAM_ATTR_OPTION_TYPE, NLA_STRING);
+                       team_option_get(team, option, &arg);
+                       NLA_PUT_STRING(skb, TEAM_ATTR_OPTION_DATA,
+                                      (char *) arg);
+                       break;
+               default:
+                       BUG();
+               }
+               nla_nest_end(skb, option_item);
+       }
+
+       nla_nest_end(skb, option_list);
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       genlmsg_cancel(skb, hdr);
+       return -EMSGSIZE;
+}
+
+static int team_nl_fill_options_get(struct sk_buff *skb,
+                                   struct genl_info *info, int flags,
+                                   struct team *team)
+{
+       return team_nl_fill_options_get_changed(skb, info->snd_pid,
+                                               info->snd_seq, NLM_F_ACK,
+                                               team, NULL);
+}
+
+static int team_nl_cmd_options_get(struct sk_buff *skb, struct genl_info *info)
+{
+       struct team *team;
+       int err;
+
+       team = team_nl_team_get(info);
+       if (!team)
+               return -EINVAL;
+
+       err = team_nl_send_generic(info, team, team_nl_fill_options_get);
+
+       team_nl_team_put(team);
+
+       return err;
+}
+
+static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
+{
+       struct team *team;
+       int err = 0;
+       int i;
+       struct nlattr *nl_option;
+
+       team = team_nl_team_get(info);
+       if (!team)
+               return -EINVAL;
+
+       err = -EINVAL;
+       if (!info->attrs[TEAM_ATTR_LIST_OPTION]) {
+               err = -EINVAL;
+               goto team_put;
+       }
+
+       nla_for_each_nested(nl_option, info->attrs[TEAM_ATTR_LIST_OPTION], i) {
+               struct nlattr *mode_attrs[TEAM_ATTR_OPTION_MAX + 1];
+               enum team_option_type opt_type;
+               struct team_option *option;
+               char *opt_name;
+               bool opt_found = false;
+
+               if (nla_type(nl_option) != TEAM_ATTR_ITEM_OPTION) {
+                       err = -EINVAL;
+                       goto team_put;
+               }
+               err = nla_parse_nested(mode_attrs, TEAM_ATTR_OPTION_MAX,
+                                      nl_option, team_nl_option_policy);
+               if (err)
+                       goto team_put;
+               if (!mode_attrs[TEAM_ATTR_OPTION_NAME] ||
+                   !mode_attrs[TEAM_ATTR_OPTION_TYPE] ||
+                   !mode_attrs[TEAM_ATTR_OPTION_DATA]) {
+                       err = -EINVAL;
+                       goto team_put;
+               }
+               switch (nla_get_u8(mode_attrs[TEAM_ATTR_OPTION_TYPE])) {
+               case NLA_U32:
+                       opt_type = TEAM_OPTION_TYPE_U32;
+                       break;
+               case NLA_STRING:
+                       opt_type = TEAM_OPTION_TYPE_STRING;
+                       break;
+               default:
+                       goto team_put;
+               }
+
+               opt_name = nla_data(mode_attrs[TEAM_ATTR_OPTION_NAME]);
+               list_for_each_entry(option, &team->option_list, list) {
+                       long arg;
+                       struct nlattr *opt_data_attr;
+
+                       if (option->type != opt_type ||
+                           strcmp(option->name, opt_name))
+                               continue;
+                       opt_found = true;
+                       opt_data_attr = mode_attrs[TEAM_ATTR_OPTION_DATA];
+                       switch (opt_type) {
+                       case TEAM_OPTION_TYPE_U32:
+                               arg = nla_get_u32(opt_data_attr);
+                               break;
+                       case TEAM_OPTION_TYPE_STRING:
+                               arg = (long) nla_data(opt_data_attr);
+                               break;
+                       default:
+                               BUG();
+                       }
+                       err = team_option_set(team, option, &arg);
+                       if (err)
+                               goto team_put;
+               }
+               if (!opt_found) {
+                       err = -ENOENT;
+                       goto team_put;
+               }
+       }
+
+team_put:
+       team_nl_team_put(team);
+
+       return err;
+}
+
+static int team_nl_fill_port_list_get_changed(struct sk_buff *skb,
+                                             u32 pid, u32 seq, int flags,
+                                             struct team *team,
+                                             struct team_port *changed_port)
+{
+       struct nlattr *port_list;
+       void *hdr;
+       struct team_port *port;
+
+       hdr = genlmsg_put(skb, pid, seq, &team_nl_family, flags,
+                         TEAM_CMD_PORT_LIST_GET);
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
+
+       NLA_PUT_U32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex);
+       port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
+       if (!port_list)
+               return -EMSGSIZE;
+
+       list_for_each_entry(port, &team->port_list, list) {
+               struct nlattr *port_item;
+
+               port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
+               if (!port_item)
+                       goto nla_put_failure;
+               NLA_PUT_U32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex);
+               if (port == changed_port)
+                       NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_CHANGED);
+               if (port->linkup)
+                       NLA_PUT_FLAG(skb, TEAM_ATTR_PORT_LINKUP);
+               NLA_PUT_U32(skb, TEAM_ATTR_PORT_SPEED, port->speed);
+               NLA_PUT_U8(skb, TEAM_ATTR_PORT_DUPLEX, port->duplex);
+               nla_nest_end(skb, port_item);
+       }
+
+       nla_nest_end(skb, port_list);
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       genlmsg_cancel(skb, hdr);
+       return -EMSGSIZE;
+}
+
+static int team_nl_fill_port_list_get(struct sk_buff *skb,
+                                     struct genl_info *info, int flags,
+                                     struct team *team)
+{
+       return team_nl_fill_port_list_get_changed(skb, info->snd_pid,
+                                                 info->snd_seq, NLM_F_ACK,
+                                                 team, NULL);
+}
+
+static int team_nl_cmd_port_list_get(struct sk_buff *skb,
+                                    struct genl_info *info)
+{
+       struct team *team;
+       int err;
+
+       team = team_nl_team_get(info);
+       if (!team)
+               return -EINVAL;
+
+       err = team_nl_send_generic(info, team, team_nl_fill_port_list_get);
+
+       team_nl_team_put(team);
+
+       return err;
+}
+
+static struct genl_ops team_nl_ops[] = {
+       {
+               .cmd = TEAM_CMD_NOOP,
+               .doit = team_nl_cmd_noop,
+               .policy = team_nl_policy,
+       },
+       {
+               .cmd = TEAM_CMD_OPTIONS_SET,
+               .doit = team_nl_cmd_options_set,
+               .policy = team_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = TEAM_CMD_OPTIONS_GET,
+               .doit = team_nl_cmd_options_get,
+               .policy = team_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = TEAM_CMD_PORT_LIST_GET,
+               .doit = team_nl_cmd_port_list_get,
+               .policy = team_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+};
+
+static struct genl_multicast_group team_change_event_mcgrp = {
+       .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
+};
+
+static int team_nl_send_event_options_get(struct team *team,
+                                         struct team_option *changed_option)
+{
+       struct sk_buff *skb;
+       int err;
+       struct net *net = dev_net(team->dev);
+
+       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       err = team_nl_fill_options_get_changed(skb, 0, 0, 0, team,
+                                              changed_option);
+       if (err < 0)
+               goto err_fill;
+
+       err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
+                                     GFP_KERNEL);
+       return err;
+
+err_fill:
+       nlmsg_free(skb);
+       return err;
+}
+
+static int team_nl_send_event_port_list_get(struct team_port *port)
+{
+       struct sk_buff *skb;
+       int err;
+       struct net *net = dev_net(port->team->dev);
+
+       skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       err = team_nl_fill_port_list_get_changed(skb, 0, 0, 0,
+                                                port->team, port);
+       if (err < 0)
+               goto err_fill;
+
+       err = genlmsg_multicast_netns(net, skb, 0, team_change_event_mcgrp.id,
+                                     GFP_KERNEL);
+       return err;
+
+err_fill:
+       nlmsg_free(skb);
+       return err;
+}
+
+static int team_nl_init(void)
+{
+       int err;
+
+       err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
+                                           ARRAY_SIZE(team_nl_ops));
+       if (err)
+               return err;
+
+       err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
+       if (err)
+               goto err_change_event_grp_reg;
+
+       return 0;
+
+err_change_event_grp_reg:
+       genl_unregister_family(&team_nl_family);
+
+       return err;
+}
+
+static void team_nl_fini(void)
+{
+       genl_unregister_family(&team_nl_family);
+}
+
+
+/******************
+ * Change checkers
+ ******************/
+
+static void __team_options_change_check(struct team *team,
+                                       struct team_option *changed_option)
+{
+       int err;
+
+       err = team_nl_send_event_options_get(team, changed_option);
+       if (err)
+               netdev_warn(team->dev, "Failed to send options change via netlink\n");
+}
+
+/* rtnl lock is held */
+static void __team_port_change_check(struct team_port *port, bool linkup)
+{
+       int err;
+
+       if (port->linkup == linkup)
+               return;
+
+       port->linkup = linkup;
+       if (linkup) {
+               struct ethtool_cmd ecmd;
+
+               err = __ethtool_get_settings(port->dev, &ecmd);
+               if (!err) {
+                       port->speed = ethtool_cmd_speed(&ecmd);
+                       port->duplex = ecmd.duplex;
+                       goto send_event;
+               }
+       }
+       port->speed = 0;
+       port->duplex = 0;
+
+send_event:
+       err = team_nl_send_event_port_list_get(port);
+       if (err)
+               netdev_warn(port->team->dev, "Failed to send port change of device %s via netlink\n",
+                           port->dev->name);
+
+}
+
+static void team_port_change_check(struct team_port *port, bool linkup)
+{
+       struct team *team = port->team;
+
+       mutex_lock(&team->lock);
+       __team_port_change_check(port, linkup);
+       mutex_unlock(&team->lock);
+}
+
+/************************************
+ * Net device notifier event handler
+ ************************************/
+
+static int team_device_event(struct notifier_block *unused,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = (struct net_device *) ptr;
+       struct team_port *port;
+
+       port = team_port_get_rtnl(dev);
+       if (!port)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_UP:
+               if (netif_carrier_ok(dev))
+                       team_port_change_check(port, true);
+       case NETDEV_DOWN:
+               team_port_change_check(port, false);
+       case NETDEV_CHANGE:
+               if (netif_running(port->dev))
+                       team_port_change_check(port,
+                                              !!netif_carrier_ok(port->dev));
+               break;
+       case NETDEV_UNREGISTER:
+               team_del_slave(port->team->dev, dev);
+               break;
+       case NETDEV_FEAT_CHANGE:
+               team_compute_features(port->team);
+               break;
+       case NETDEV_CHANGEMTU:
+               /* Forbid to change mtu of underlaying device */
+               return NOTIFY_BAD;
+       case NETDEV_PRE_TYPE_CHANGE:
+               /* Forbid to change type of underlaying device */
+               return NOTIFY_BAD;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block team_notifier_block __read_mostly = {
+       .notifier_call = team_device_event,
+};
+
+
+/***********************
+ * Module init and exit
+ ***********************/
+
+static int __init team_module_init(void)
+{
+       int err;
+
+       register_netdevice_notifier(&team_notifier_block);
+
+       err = rtnl_link_register(&team_link_ops);
+       if (err)
+               goto err_rtnl_reg;
+
+       err = team_nl_init();
+       if (err)
+               goto err_nl_init;
+
+       return 0;
+
+err_nl_init:
+       rtnl_link_unregister(&team_link_ops);
+
+err_rtnl_reg:
+       unregister_netdevice_notifier(&team_notifier_block);
+
+       return err;
+}
+
+static void __exit team_module_exit(void)
+{
+       team_nl_fini();
+       rtnl_link_unregister(&team_link_ops);
+       unregister_netdevice_notifier(&team_notifier_block);
+}
+
+module_init(team_module_init);
+module_exit(team_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Ethernet team device driver");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
diff --git a/drivers/net/team/team_mode_activebackup.c b/drivers/net/team/team_mode_activebackup.c
new file mode 100644 (file)
index 0000000..b344275
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * net/drivers/team/team_mode_activebackup.c - Active-backup mode for team
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <net/rtnetlink.h>
+#include <linux/if_team.h>
+
+struct ab_priv {
+       struct team_port __rcu *active_port;
+};
+
+static struct ab_priv *ab_priv(struct team *team)
+{
+       return (struct ab_priv *) &team->mode_priv;
+}
+
+static rx_handler_result_t ab_receive(struct team *team, struct team_port *port,
+                                     struct sk_buff *skb) {
+       struct team_port *active_port;
+
+       active_port = rcu_dereference(ab_priv(team)->active_port);
+       if (active_port != port)
+               return RX_HANDLER_EXACT;
+       return RX_HANDLER_ANOTHER;
+}
+
+static bool ab_transmit(struct team *team, struct sk_buff *skb)
+{
+       struct team_port *active_port;
+
+       active_port = rcu_dereference(ab_priv(team)->active_port);
+       if (unlikely(!active_port))
+               goto drop;
+       skb->dev = active_port->dev;
+       if (dev_queue_xmit(skb))
+               return false;
+       return true;
+
+drop:
+       dev_kfree_skb_any(skb);
+       return false;
+}
+
+static void ab_port_leave(struct team *team, struct team_port *port)
+{
+       if (ab_priv(team)->active_port == port)
+               rcu_assign_pointer(ab_priv(team)->active_port, NULL);
+}
+
+static int ab_active_port_get(struct team *team, void *arg)
+{
+       u32 *ifindex = arg;
+
+       *ifindex = 0;
+       if (ab_priv(team)->active_port)
+               *ifindex = ab_priv(team)->active_port->dev->ifindex;
+       return 0;
+}
+
+static int ab_active_port_set(struct team *team, void *arg)
+{
+       u32 *ifindex = arg;
+       struct team_port *port;
+
+       list_for_each_entry_rcu(port, &team->port_list, list) {
+               if (port->dev->ifindex == *ifindex) {
+                       rcu_assign_pointer(ab_priv(team)->active_port, port);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static const struct team_option ab_options[] = {
+       {
+               .name = "activeport",
+               .type = TEAM_OPTION_TYPE_U32,
+               .getter = ab_active_port_get,
+               .setter = ab_active_port_set,
+       },
+};
+
+int ab_init(struct team *team)
+{
+       return team_options_register(team, ab_options, ARRAY_SIZE(ab_options));
+}
+
+void ab_exit(struct team *team)
+{
+       team_options_unregister(team, ab_options, ARRAY_SIZE(ab_options));
+}
+
+static const struct team_mode_ops ab_mode_ops = {
+       .init                   = ab_init,
+       .exit                   = ab_exit,
+       .receive                = ab_receive,
+       .transmit               = ab_transmit,
+       .port_leave             = ab_port_leave,
+};
+
+static struct team_mode ab_mode = {
+       .kind           = "activebackup",
+       .owner          = THIS_MODULE,
+       .priv_size      = sizeof(struct ab_priv),
+       .ops            = &ab_mode_ops,
+};
+
+static int __init ab_init_module(void)
+{
+       return team_mode_register(&ab_mode);
+}
+
+static void __exit ab_cleanup_module(void)
+{
+       team_mode_unregister(&ab_mode);
+}
+
+module_init(ab_init_module);
+module_exit(ab_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Active-backup mode for team");
+MODULE_ALIAS("team-mode-activebackup");
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
new file mode 100644 (file)
index 0000000..a0e8f80
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * net/drivers/team/team_mode_roundrobin.c - Round-robin mode for team
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/if_team.h>
+
+struct rr_priv {
+       unsigned int sent_packets;
+};
+
+static struct rr_priv *rr_priv(struct team *team)
+{
+       return (struct rr_priv *) &team->mode_priv;
+}
+
+static struct team_port *__get_first_port_up(struct team *team,
+                                            struct team_port *port)
+{
+       struct team_port *cur;
+
+       if (port->linkup)
+               return port;
+       cur = port;
+       list_for_each_entry_continue_rcu(cur, &team->port_list, list)
+               if (cur->linkup)
+                       return cur;
+       list_for_each_entry_rcu(cur, &team->port_list, list) {
+               if (cur == port)
+                       break;
+               if (cur->linkup)
+                       return cur;
+       }
+       return NULL;
+}
+
+static bool rr_transmit(struct team *team, struct sk_buff *skb)
+{
+       struct team_port *port;
+       int port_index;
+
+       port_index = rr_priv(team)->sent_packets++ % team->port_count;
+       port = team_get_port_by_index_rcu(team, port_index);
+       port = __get_first_port_up(team, port);
+       if (unlikely(!port))
+               goto drop;
+       skb->dev = port->dev;
+       if (dev_queue_xmit(skb))
+               return false;
+       return true;
+
+drop:
+       dev_kfree_skb_any(skb);
+       return false;
+}
+
+static int rr_port_enter(struct team *team, struct team_port *port)
+{
+       return team_port_set_team_mac(port);
+}
+
+static void rr_port_change_mac(struct team *team, struct team_port *port)
+{
+       team_port_set_team_mac(port);
+}
+
+static const struct team_mode_ops rr_mode_ops = {
+       .transmit               = rr_transmit,
+       .port_enter             = rr_port_enter,
+       .port_change_mac        = rr_port_change_mac,
+};
+
+static struct team_mode rr_mode = {
+       .kind           = "roundrobin",
+       .owner          = THIS_MODULE,
+       .priv_size      = sizeof(struct rr_priv),
+       .ops            = &rr_mode_ops,
+};
+
+static int __init rr_init_module(void)
+{
+       return team_mode_register(&rr_mode);
+}
+
+static void __exit rr_cleanup_module(void)
+{
+       team_mode_unregister(&rr_mode);
+}
+
+module_init(rr_init_module);
+module_exit(rr_cleanup_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jiri Pirko <jpirko@redhat.com>");
+MODULE_DESCRIPTION("Round-robin mode for team");
+MODULE_ALIAS("team-mode-roundrobin");
index 7bea9c65119e339326155c45e4af6e268bda0c6c..3dd13d606d00e02e499c9092ec30bfafb2338530 100644 (file)
@@ -123,7 +123,7 @@ struct tun_struct {
        gid_t                   group;
 
        struct net_device       *dev;
-       u32                     set_features;
+       netdev_features_t       set_features;
 #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
                          NETIF_F_TSO6|NETIF_F_UFO)
        struct fasync_struct    *fasync;
@@ -454,7 +454,8 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
-static u32 tun_net_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t tun_net_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct tun_struct *tun = netdev_priv(dev);
 
@@ -1196,7 +1197,7 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun,
  * privs required. */
 static int set_offload(struct tun_struct *tun, unsigned long arg)
 {
-       u32 features = 0;
+       netdev_features_t features = 0;
 
        if (arg & TUN_F_CSUM) {
                features |= NETIF_F_HW_CSUM;
@@ -1589,16 +1590,16 @@ static void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
 {
        struct tun_struct *tun = netdev_priv(dev);
 
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 
        switch (tun->flags & TUN_TYPE_MASK) {
        case TUN_TUN_DEV:
-               strcpy(info->bus_info, "tun");
+               strlcpy(info->bus_info, "tun", sizeof(info->bus_info));
                break;
        case TUN_TAP_DEV:
-               strcpy(info->bus_info, "tap");
+               strlcpy(info->bus_info, "tap", sizeof(info->bus_info));
                break;
        }
 }
index a5b9b12ef268134fef1e978d8e19ce5468c16135..7d62c39f65cf026d200f243eb9146185309501f3 100644 (file)
@@ -728,7 +728,8 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
 }
 
 /* Enable or disable Rx checksum offload engine */
-static int smsc75xx_set_features(struct net_device *netdev, u32 features)
+static int smsc75xx_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct usbnet *dev = netdev_priv(netdev);
        struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
index eff67678c5a6a582aced31aa27c3dcc569aee768..56f3894d701ad62a4ca0f6bb7f87f699f12e84b7 100644 (file)
@@ -516,7 +516,8 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
 }
 
 /* Enable or disable Tx & Rx checksum offload engines */
-static int smsc95xx_set_features(struct net_device *netdev, u32 features)
+static int smsc95xx_set_features(struct net_device *netdev,
+       netdev_features_t features)
 {
        struct usbnet *dev = netdev_priv(netdev);
        u32 read_buf;
index ef883e97cee08a557fd3dcc2546535c1ca487372..b576812bdc5931d7852d2bc1629d65c1bdee7c6c 100644 (file)
@@ -27,8 +27,8 @@
 
 struct veth_net_stats {
        u64                     rx_packets;
-       u64                     tx_packets;
        u64                     rx_bytes;
+       u64                     tx_packets;
        u64                     tx_bytes;
        u64                     rx_dropped;
        struct u64_stats_sync   syncp;
@@ -66,9 +66,9 @@ static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
 static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, DRV_NAME);
-       strcpy(info->version, DRV_VERSION);
-       strcpy(info->fw_version, "N/A");
+       strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+       strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
 }
 
 static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -271,7 +271,7 @@ static void veth_setup(struct net_device *dev)
        dev->features |= NETIF_F_LLTX;
        dev->destructor = veth_dev_free;
 
-       dev->hw_features = NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
+       dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
 }
 
 /*
index 6ee8410443c46312ca62810199dc14ffbaf53966..4dc9d842a7a362957985b68d40b4b01b7eb9c9d0 100644 (file)
@@ -39,6 +39,7 @@ module_param(gso, bool, 0444);
 #define GOOD_COPY_LEN  128
 
 #define VIRTNET_SEND_COMMAND_SG_MAX    2
+#define VIRTNET_DRIVER_VERSION "1.0.0"
 
 struct virtnet_stats {
        struct u64_stats_sync syncp;
@@ -889,7 +890,21 @@ static void virtnet_get_ringparam(struct net_device *dev,
 
 }
 
+
+static void virtnet_get_drvinfo(struct net_device *dev,
+                               struct ethtool_drvinfo *info)
+{
+       struct virtnet_info *vi = netdev_priv(dev);
+       struct virtio_device *vdev = vi->vdev;
+
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, VIRTNET_DRIVER_VERSION, sizeof(info->version));
+       strlcpy(info->bus_info, virtio_bus_name(vdev), sizeof(info->bus_info));
+
+}
+
 static const struct ethtool_ops virtnet_ethtool_ops = {
+       .get_drvinfo = virtnet_get_drvinfo,
        .get_link = ethtool_op_get_link,
        .get_ringparam = virtnet_get_ringparam,
 };
index e662cbc8bfbda34c8f158fd89ffb82ecfacebf61..77f723415c9c747fcfffd1ac18ceb4f948230bfb 100644 (file)
@@ -262,11 +262,11 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
        }
 }
 
-int vmxnet3_set_features(struct net_device *netdev, u32 features)
+int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
        unsigned long flags;
-       u32 changed = features ^ netdev->features;
+       netdev_features_t changed = features ^ netdev->features;
 
        if (changed & (NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_RX)) {
                if (features & NETIF_F_RXCSUM)
index b18eac1dccaa152f6a6dd1c8f0ae63335a710b8a..ed54797db1916d717fe3141559bf95bca2013547 100644 (file)
@@ -401,7 +401,7 @@ void
 vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
 
 int
-vmxnet3_set_features(struct net_device *netdev, u32 features);
+vmxnet3_set_features(struct net_device *netdev, netdev_features_t features);
 
 int
 vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
index 0a304b060b6c5154393bea75bb3d21537b708027..c1c0678b1fb64a8b6e9b56757b48700f095473fa 100644 (file)
@@ -58,6 +58,6 @@ obj-$(CONFIG_WL12XX_PLATFORM_DATA)    += wl12xx/
 obj-$(CONFIG_IWM)      += iwmc3200wifi/
 
 obj-$(CONFIG_MWIFIEX)  += mwifiex/
-obj-$(CONFIG_BRCMFMAC) += brcm80211/
-obj-$(CONFIG_BRCMUMAC) += brcm80211/
-obj-$(CONFIG_BRCMSMAC) += brcm80211/
+
+obj-$(CONFIG_BRCMFMAC) += brcm80211/
+obj-$(CONFIG_BRCMSMAC) += brcm80211/
index 0f9ee46cfc970eb8b898bf215bb48099165758de..4596c33a7a69c462c297d98219e13e3af3c48f37 100644 (file)
@@ -239,6 +239,7 @@ enum ATH_DEBUG {
        ATH_DBG_BTCOEX          = 0x00002000,
        ATH_DBG_WMI             = 0x00004000,
        ATH_DBG_BSTUCK          = 0x00008000,
+       ATH_DBG_MCI             = 0x00010000,
        ATH_DBG_ANY             = 0xffffffff
 };
 
index f517eb8f7b44b6ba13e07bc02a4de80586ef6444..5ac2bc2ebee6e64fe2013fa72ada50884d3132a0 100644 (file)
@@ -1734,7 +1734,8 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, bool no_cck, u64 *cookie)
+                         const u8 *buf, size_t len, bool no_cck,
+                         bool dont_wait_for_ack, u64 *cookie)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        u32 id;
index c1d2366704b5d89ad4dbad2b2a90629e10e6c849..81e0031012caa0c7f8ef7033102abe2ec5348d75 100644 (file)
@@ -1548,7 +1548,8 @@ static int ath6kl_init(struct net_device *dev)
        ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
                         ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
 
-       ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+       ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
+                                 WIPHY_FLAG_HAVE_AP_SME;
 
        status = ath6kl_target_config_wlan_params(ar);
        if (!status)
index d9c08c619a3ab045fe7950aff6dc6f50d1f08b49..7b4c074e12fafde174793dbf50f1f6b9574ee2e8 100644 (file)
@@ -25,6 +25,7 @@ config ATH9K
 
 config ATH9K_PCI
        bool "Atheros ath9k PCI/PCIe bus support"
+       default y
        depends on ATH9K && PCI
        ---help---
          This option enables the PCI bus support in ath9k.
index 36ed3c46fec60afe7634092e90208292af0d423a..49d3f25f509d0a4ed3953cab6b77b7ded0bccfd2 100644 (file)
@@ -4,6 +4,7 @@ ath9k-y +=      beacon.o \
                main.o \
                recv.o \
                xmit.o \
+               mci.o \
 
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
index 3b262ba6b17214e6bba4abc816ab13d716d9ae13..a93bd63ad23bd8834f91fb9af42b76543ec8d666 100644 (file)
@@ -121,10 +121,8 @@ static const struct ar9300_eeprom ar9300_default = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -144,7 +142,7 @@ static const struct ar9300_eeprom ar9300_default = {
         },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -323,10 +321,8 @@ static const struct ar9300_eeprom ar9300_default = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -698,10 +694,8 @@ static const struct ar9300_eeprom ar9300_x113 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -721,7 +715,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -900,10 +894,8 @@ static const struct ar9300_eeprom ar9300_x113 = {
                .spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0xf,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1276,10 +1268,8 @@ static const struct ar9300_eeprom ar9300_h112 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1291,20 +1281,20 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .txEndToRxOn = 0x2,
                .txFrameToXpaOn = 0xe,
                .thresh62 = 28,
-               .papdRateMaskHt20 = LE32(0x80c080),
-               .papdRateMaskHt40 = LE32(0x80c080),
+               .papdRateMaskHt20 = LE32(0x0c80c080),
+               .papdRateMaskHt40 = LE32(0x0080c080),
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0, 0,
                },
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
                FREQ2FBIN(2437, 1),
-               FREQ2FBIN(2472, 1),
+               FREQ2FBIN(2462, 1),
        },
        /* ar9300_cal_data_per_freq_op_loop 2g */
        .calPierData2G = {
@@ -1314,7 +1304,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
        },
        .calTarget_freqbin_Cck = {
                FREQ2FBIN(2412, 1),
-               FREQ2FBIN(2484, 1),
+               FREQ2FBIN(2472, 1),
        },
        .calTarget_freqbin_2G = {
                FREQ2FBIN(2412, 1),
@@ -1478,10 +1468,8 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1515,7 +1503,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
                FREQ2FBIN(5500, 0),
                FREQ2FBIN(5600, 0),
                FREQ2FBIN(5700, 0),
-               FREQ2FBIN(5825, 0)
+               FREQ2FBIN(5785, 0)
        },
        .calPierData5G = {
                {
@@ -1854,10 +1842,8 @@ static const struct ar9300_eeprom ar9300_x112 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1877,7 +1863,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -2056,10 +2042,8 @@ static const struct ar9300_eeprom ar9300_x112 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshch check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2431,10 +2415,8 @@ static const struct ar9300_eeprom ar9300_h116 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2454,12 +2436,12 @@ static const struct ar9300_eeprom ar9300_h116 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
                FREQ2FBIN(2437, 1),
-               FREQ2FBIN(2472, 1),
+               FREQ2FBIN(2462, 1),
         },
        /* ar9300_cal_data_per_freq_op_loop 2g */
        .calPierData2G = {
@@ -2633,10 +2615,8 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2663,7 +2643,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .xatten1MarginHigh = {0, 0, 0}
         },
        .calFreqPier5G = {
-               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5160, 0),
                FREQ2FBIN(5220, 0),
                FREQ2FBIN(5320, 0),
                FREQ2FBIN(5400, 0),
@@ -3023,6 +3003,8 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
                return eep->modalHeader5G.antennaGain;
        case EEP_ANTENNA_GAIN_2G:
                return eep->modalHeader2G.antennaGain;
+       case EEP_QUICK_DROP:
+               return pBase->miscConfiguration & BIT(1);
        default:
                return 0;
        }
@@ -3428,25 +3410,14 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
        PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
        PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
        PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+       PR_EEP("Quick Drop", modal_hdr->quick_drop);
+       PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
        PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
        PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
        PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
        PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
        PR_EEP("txClip", modal_hdr->txClip);
        PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
-       PR_EEP("Chain0 ob", modal_hdr->ob[0]);
-       PR_EEP("Chain1 ob", modal_hdr->ob[1]);
-       PR_EEP("Chain2 ob", modal_hdr->ob[2]);
-
-       PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
-       PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
-       PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
-       PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
-       PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
-       PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
-       PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
-       PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
-       PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
 
        return len;
 }
@@ -3503,6 +3474,7 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
        PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
        PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
+       PR_EEP("Quick Drop", !!(pBase->miscConfiguration & BIT(1)));
        PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
        PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
        PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
@@ -3965,6 +3937,40 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)
        }
 }
 
+static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       int quick_drop = ath9k_hw_ar9300_get_eeprom(ah, EEP_QUICK_DROP);
+       s32 t[3], f[3] = {5180, 5500, 5785};
+
+       if (!quick_drop)
+               return;
+
+       if (freq < 4000)
+               quick_drop = eep->modalHeader2G.quick_drop;
+       else {
+               t[0] = eep->base_ext1.quick_drop_low;
+               t[1] = eep->modalHeader5G.quick_drop;
+               t[2] = eep->base_ext1.quick_drop_high;
+               quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3);
+       }
+       REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop);
+}
+
+static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, u16 freq)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       u32 value;
+
+       value = (freq < 4000) ? eep->modalHeader2G.txEndToXpaOff :
+                               eep->modalHeader5G.txEndToXpaOff;
+
+       REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
+                     AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value);
+       REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
+                     AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value);
+}
+
 static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
                                             struct ath9k_channel *chan)
 {
@@ -3972,10 +3978,12 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
        ar9003_hw_drive_strength_apply(ah);
        ar9003_hw_atten_apply(ah, chan);
+       ar9003_hw_quick_drop_apply(ah, chan->channel);
        if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
                ar9003_hw_internal_regulator_apply(ah);
        if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah))
                ar9003_hw_apply_tuning_caps(ah);
+       ar9003_hw_txend_to_xpa_off_apply(ah, chan->channel);
 }
 
 static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah,
@@ -5051,6 +5059,8 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                        regulatory->max_power_level = targetPowerValT2[i];
        }
 
+       ath9k_hw_update_regulatory_maxpower(ah);
+
        if (test)
                return;
 
index 6335a867527e13db33598f15efe63df3581909c7..bb223fe82816fdc892327b60e6f473f7c254851e 100644 (file)
@@ -216,10 +216,8 @@ struct ar9300_modal_eep_header {
        u8 spurChans[AR_EEPROM_MODAL_SPURS];
        /* 3  Check if the register is per chain */
        int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS];
-       u8 ob[AR9300_MAX_CHAINS];
-       u8 db_stage2[AR9300_MAX_CHAINS];
-       u8 db_stage3[AR9300_MAX_CHAINS];
-       u8 db_stage4[AR9300_MAX_CHAINS];
+       u8 reserved[11];
+       int8_t quick_drop;
        u8 xpaBiasLvl;
        u8 txFrameToDataStart;
        u8 txFrameToPaOn;
@@ -269,7 +267,9 @@ struct cal_ctl_data_5g {
 
 struct ar9300_BaseExtension_1 {
        u8 ant_div_control;
-       u8 future[13];
+       u8 future[11];
+       int8_t quick_drop_low;
+       int8_t quick_drop_high;
 } __packed;
 
 struct ar9300_BaseExtension_2 {
index 2330e7ede19946a88cacdd7359e52192da45bf01..e41d26939ab8799d66d71b30b0699799aad4eca1 100644 (file)
@@ -199,12 +199,14 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
                        synth_freq = chan->channel;
                }
        } else {
-               range = 10;
+               range = AR_SREV_9462(ah) ? 5 : 10;
                max_spur_cnts = 4;
                synth_freq = chan->channel;
        }
 
        for (i = 0; i < max_spur_cnts; i++) {
+               if (AR_SREV_9462(ah) && (i == 0 || i == 3))
+                       continue;
                negative = 0;
                if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah))
                        cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
index 4114fe752c6b4f85485ef13024350dc6b9d55f8f..497d7461838a95a337abff04a2fae61137abfafd 100644 (file)
 #define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
 
 #define AR_PHY_RIFS_INIT_DELAY         0x3ff0000
+#define AR_PHY_AGC_QUICK_DROP       0x03c00000
+#define AR_PHY_AGC_QUICK_DROP_S     22
 #define AR_PHY_AGC_COARSE_LOW       0x00007F80
 #define AR_PHY_AGC_COARSE_LOW_S     7
 #define AR_PHY_AGC_COARSE_HIGH      0x003F8000
index 9c51b395b4ffdb104cce7a5bb1e7176908007d80..259a6f312afba81277e6a8cf4ece24bc315e2925 100644 (file)
@@ -43,16 +43,16 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
-       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x5ac640de},
+       {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x0796be89},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
        {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
        {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
        {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
-       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3039605e, 0x33795d5e},
+       {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x92c84d2e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
@@ -688,8 +688,8 @@ static const u32 ar9462_2p0_mac_postamble_emulation[][5] = {
 static const u32 ar9462_2p0_radio_postamble_sys3ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
@@ -717,8 +717,8 @@ static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = {
@@ -1059,7 +1059,7 @@ static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = {
 
 static const u32 ar9462_2p0_soc_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233},
+       {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033},
 };
 
 static const u32 ar9462_2p0_baseband_core[][2] = {
@@ -1257,8 +1257,8 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
@@ -1850,8 +1850,8 @@ static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
index 1c269f50822b32245eaf596ffdc7f3384afb0277..93b45b4b3033a5b7d90b8e42c3cade525c5d2fec 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "debug.h"
 #include "common.h"
+#include "mci.h"
 
 /*
  * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
@@ -252,6 +253,7 @@ struct ath_node {
 #ifdef CONFIG_ATH9K_DEBUGFS
        struct list_head list; /* for sc->nodes */
        struct ieee80211_sta *sta; /* station struct we're part of */
+       struct ieee80211_vif *vif; /* interface with which we're associated */
 #endif
        struct ath_atx_tid tid[WME_NUM_TID];
        struct ath_atx_ac ac[WME_NUM_AC];
@@ -443,7 +445,9 @@ struct ath_btcoex {
        u32 btcoex_no_stomp; /* in usec */
        u32 btcoex_period; /* in usec */
        u32 btscan_no_stomp; /* in usec */
+       u32 duty_cycle;
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
+       struct ath_mci_profile mci;
 };
 
 int ath_init_btcoex_timer(struct ath_softc *sc);
index 2741203e803f2dadb4204eefae82dd2896e11649..6fb719d85b3748c2cc0704e5214e767e0076e859 100644 (file)
@@ -709,24 +709,29 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf,
 
        len += snprintf(buf + len, size - len,
                        "Stations:\n"
-                       " tid: addr sched paused buf_q-empty an ac\n"
+                       " tid: addr sched paused buf_q-empty an ac baw\n"
                        " ac: addr sched tid_q-empty txq\n");
 
        spin_lock(&sc->nodes_lock);
        list_for_each_entry(an, &sc->nodes, list) {
+               unsigned short ma = an->maxampdu;
+               if (ma == 0)
+                       ma = 65535; /* see ath_lookup_rate */
                len += snprintf(buf + len, size - len,
-                               "%pM\n", an->sta->addr);
+                               "iface: %pM  sta: %pM max-ampdu: %hu mpdu-density: %uus\n",
+                               an->vif->addr, an->sta->addr, ma,
+                               (unsigned int)(an->mpdudensity));
                if (len >= size)
                        goto done;
 
                for (q = 0; q < WME_NUM_TID; q++) {
                        struct ath_atx_tid *tid = &(an->tid[q]);
                        len += snprintf(buf + len, size - len,
-                                       " tid: %p %s %s %i %p %p\n",
+                                       " tid: %p %s %s %i %p %p %hu\n",
                                        tid, tid->sched ? "sched" : "idle",
                                        tid->paused ? "paused" : "running",
                                        skb_queue_empty(&tid->buf_q),
-                                       tid->an, tid->ac);
+                                       tid->an, tid->ac, tid->baw_size);
                        if (len >= size)
                                goto done;
                }
index 49abd34be74182712b644e89c1e2f719189b0902..5ff7ab96512036b35ab74beec9f22ebe78917a7c 100644 (file)
@@ -249,7 +249,8 @@ enum eeprom_param {
        EEP_ANT_DIV_CTL1,
        EEP_CHAIN_MASK_REDUCE,
        EEP_ANTENNA_GAIN_2G,
-       EEP_ANTENNA_GAIN_5G
+       EEP_ANTENNA_GAIN_5G,
+       EEP_QUICK_DROP
 };
 
 enum ar5416_rates {
index 655576c8fdab7276a233b8010f33406de9988e40..2c279dcaf4ba8cb8813997c39472bb4ac869dc7d 100644 (file)
@@ -189,8 +189,8 @@ static void ath_btcoex_period_timer(unsigned long data)
        bool is_btscan;
 
        ath9k_ps_wakeup(sc);
-       ath_detect_bt_priority(sc);
-
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+               ath_detect_bt_priority(sc);
        is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        spin_lock_bh(&btcoex->btcoex_lock);
@@ -212,8 +212,9 @@ static void ath_btcoex_period_timer(unsigned long data)
        }
 
        ath9k_ps_restore(sc);
+       timer_period = btcoex->btcoex_period / 1000;
        mod_timer(&btcoex->period_timer, jiffies +
-                                 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+                                 msecs_to_jiffies(timer_period));
 }
 
 /*
index 2f91acccb7dbc80499e7988b74ac62521bd06799..662ab7e9a0f0e7e7e31d7f1370e8a724ef7084d6 100644 (file)
@@ -2335,7 +2335,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
        if (AR_SREV_9462(ah))
-               pCap->hw_caps |= ATH9K_HW_CAP_RTT;
+               pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI;
 
        return 0;
 }
@@ -2583,7 +2583,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
        struct ath9k_channel *chan = ah->curchan;
        struct ieee80211_channel *channel = chan->chan;
 
-       reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
+       reg->power_limit = min_t(u32, limit, MAX_RATE_POWER);
        if (test)
                channel->max_power = MAX_RATE_POWER / 2;
 
index f389b3c93cf3f4431a8af0ec57f14b332212b7e6..33e8f2f9d4256605e539b5be58eabef6fc850315 100644 (file)
@@ -203,6 +203,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_5GHZ                       = BIT(14),
        ATH9K_HW_CAP_APM                        = BIT(15),
        ATH9K_HW_CAP_RTT                        = BIT(16),
+       ATH9K_HW_CAP_MCI                        = BIT(17),
 };
 
 struct ath9k_hw_capabilities {
@@ -419,6 +420,16 @@ enum ath9k_rx_qtype {
        ATH9K_RX_QUEUE_MAX,
 };
 
+enum ath_mci_gpm_coex_profile_type {
+       MCI_GPM_COEX_PROFILE_UNKNOWN,
+       MCI_GPM_COEX_PROFILE_RFCOMM,
+       MCI_GPM_COEX_PROFILE_A2DP,
+       MCI_GPM_COEX_PROFILE_HID,
+       MCI_GPM_COEX_PROFILE_BNEP,
+       MCI_GPM_COEX_PROFILE_VOICE,
+       MCI_GPM_COEX_PROFILE_MAX
+};
+
 struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
index d4c909f8e474d793d71d52af3bd8d34a9c0f9843..e046de94836a2d6c83ccf2338d1e3d5d78ab9fd7 100644 (file)
@@ -424,6 +424,8 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
                txq = sc->tx.txq_map[WME_AC_BE];
                ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
                sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+               INIT_LIST_HEAD(&sc->btcoex.mci.info);
                break;
        default:
                WARN_ON(1);
@@ -695,6 +697,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
 
        hw->queues = 4;
        hw->max_rates = 4;
index 93fbe6f4089890df98b98904921879ab97835b98..e43c41cff25b87cc9087f6c0a695fb4f9626b06b 100644 (file)
@@ -630,7 +630,8 @@ set_timer:
        }
 }
 
-static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
+static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
+                           struct ieee80211_vif *vif)
 {
        struct ath_node *an;
        an = (struct ath_node *)sta->drv_priv;
@@ -640,6 +641,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
        list_add(&an->list, &sc->nodes);
        spin_unlock(&sc->nodes_lock);
        an->sta = sta;
+       an->vif = vif;
 #endif
        if (sc->sc_flags & SC_OP_TXAGGR) {
                ath_tx_node_init(sc, an);
@@ -1133,8 +1135,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
            !ah->btcoex_hw.enabled) {
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_LOW_WLAN_WGHT);
+               if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+                       ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                                  AR_STOMP_LOW_WLAN_WGHT);
                ath9k_hw_btcoex_enable(ah);
 
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -1237,6 +1240,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
                ath9k_hw_btcoex_disable(ah);
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
                        ath9k_btcoex_timer_pause(sc);
+               ath_mci_flush_profile(&sc->btcoex.mci);
        }
 
        spin_lock_bh(&sc->sc_pcu_lock);
@@ -1798,7 +1802,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
        struct ieee80211_key_conf ps_key = { };
 
-       ath_node_attach(sc, sta);
+       ath_node_attach(sc, sta, vif);
 
        if (vif->type != NL80211_IFTYPE_AP &&
            vif->type != NL80211_IFTYPE_AP_VLAN)
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
new file mode 100644 (file)
index 0000000..0fbb141
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+#include "mci.h"
+
+u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
+
+static struct ath_mci_profile_info*
+ath_mci_find_profile(struct ath_mci_profile *mci,
+                    struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       list_for_each_entry(entry, &mci->info, list) {
+               if (entry->conn_handle == info->conn_handle)
+                       break;
+       }
+       return entry;
+}
+
+static bool ath_mci_add_profile(struct ath_common *common,
+                               struct ath_mci_profile *mci,
+                               struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
+           (info->type == MCI_GPM_COEX_PROFILE_VOICE)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Too many SCO profile, failed to add new profile\n");
+               return false;
+       }
+
+       if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
+           (info->type != MCI_GPM_COEX_PROFILE_VOICE)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Too many ACL profile, failed to add new profile\n");
+               return false;
+       }
+
+       entry = ath_mci_find_profile(mci, info);
+
+       if (entry)
+               memcpy(entry, info, 10);
+       else {
+               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+               if (!entry)
+                       return false;
+
+               memcpy(entry, info, 10);
+               INC_PROF(mci, info);
+               list_add_tail(&info->list, &mci->info);
+       }
+       return true;
+}
+
+static void ath_mci_del_profile(struct ath_common *common,
+                               struct ath_mci_profile *mci,
+                               struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       entry = ath_mci_find_profile(mci, info);
+
+       if (!entry) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Profile to be deleted not found\n");
+               return;
+       }
+       DEC_PROF(mci, entry);
+       list_del(&entry->list);
+       kfree(entry);
+}
+
+void ath_mci_flush_profile(struct ath_mci_profile *mci)
+{
+       struct ath_mci_profile_info *info, *tinfo;
+
+       list_for_each_entry_safe(info, tinfo, &mci->info, list) {
+               list_del(&info->list);
+               DEC_PROF(mci, info);
+               kfree(info);
+       }
+       mci->aggr_limit = 0;
+}
+
+static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
+{
+       struct ath_mci_profile *mci = &btcoex->mci;
+       u32 wlan_airtime = btcoex->btcoex_period *
+                               (100 - btcoex->duty_cycle) / 100;
+
+       /*
+        * Scale: wlan_airtime is in ms, aggr_limit is in 0.25 ms.
+        * When wlan_airtime is less than 4ms, aggregation limit has to be
+        * adjusted half of wlan_airtime to ensure that the aggregation can fit
+        * without collision with BT traffic.
+        */
+       if ((wlan_airtime <= 4) &&
+           (!mci->aggr_limit || (mci->aggr_limit > (2 * wlan_airtime))))
+               mci->aggr_limit = 2 * wlan_airtime;
+}
+
+static void ath_mci_update_scheme(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info *info;
+       u32 num_profile = NUM_PROF(mci);
+
+       if (num_profile == 1) {
+               info = list_first_entry(&mci->info,
+                                       struct ath_mci_profile_info,
+                                       list);
+               if (mci->num_sco && info->T == 12) {
+                       mci->aggr_limit = 8;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Single SCO, aggregation limit 2 ms\n");
+               } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
+                          !info->master) {
+                       btcoex->btcoex_period = 60;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Single slave PAN/FTP, bt period 60 ms\n");
+               } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
+                        (info->T > 0 && info->T < 50) &&
+                        (info->A > 1 || info->W > 1)) {
+                       btcoex->duty_cycle = 30;
+                       mci->aggr_limit = 8;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Multiple attempt/timeout single HID "
+                               "aggregation limit 2 ms dutycycle 30%%\n");
+               }
+       } else if ((num_profile == 2) && (mci->num_hid == 2)) {
+               btcoex->duty_cycle = 30;
+               mci->aggr_limit = 8;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
+       } else if (num_profile > 3) {
+               mci->aggr_limit = 6;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Three or more profiles aggregation limit 1.5 ms\n");
+       }
+
+       if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
+               if (IS_CHAN_HT(sc->sc_ah->curchan))
+                       ath_mci_adjust_aggr_limit(btcoex);
+               else
+                       btcoex->btcoex_period >>= 1;
+       }
+
+       ath9k_hw_btcoex_disable(sc->sc_ah);
+       ath9k_btcoex_timer_pause(sc);
+
+       if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
+               return;
+
+       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
+       if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
+               btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
+
+       btcoex->btcoex_period *= 1000;
+       btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
+                                       (100 - btcoex->duty_cycle) / 100;
+
+       ath9k_hw_btcoex_enable(sc->sc_ah);
+       ath9k_btcoex_timer_resume(sc);
+}
+
+void ath_mci_process_profile(struct ath_softc *sc,
+                            struct ath_mci_profile_info *info)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+
+       if (info->start) {
+               if (!ath_mci_add_profile(common, mci, info))
+                       return;
+       } else
+               ath_mci_del_profile(common, mci, info);
+
+       btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
+       mci->aggr_limit = mci->num_sco ? 6 : 0;
+       if (NUM_PROF(mci)) {
+               btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
+       } else {
+               btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
+                                                       ATH_BTCOEX_STOMP_LOW;
+               btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+       }
+
+       ath_mci_update_scheme(sc);
+}
+
+void ath_mci_process_status(struct ath_softc *sc,
+                           struct ath_mci_profile_status *status)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info info;
+       int i = 0, old_num_mgmt = mci->num_mgmt;
+
+       /* Link status type are not handled */
+       if (status->is_link) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Skip link type status update\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(struct ath_mci_profile_info));
+
+       info.conn_handle = status->conn_handle;
+       if (ath_mci_find_profile(mci, &info)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Skip non link state update for existing profile %d\n",
+                       status->conn_handle);
+               return;
+       }
+       if (status->conn_handle >= ATH_MCI_MAX_PROFILE) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Ignore too many non-link update\n");
+               return;
+       }
+       if (status->is_critical)
+               __set_bit(status->conn_handle, mci->status);
+       else
+               __clear_bit(status->conn_handle, mci->status);
+
+       mci->num_mgmt = 0;
+       do {
+               if (test_bit(i, mci->status))
+                       mci->num_mgmt++;
+       } while (++i < ATH_MCI_MAX_PROFILE);
+
+       if (old_num_mgmt != mci->num_mgmt)
+               ath_mci_update_scheme(sc);
+}
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
new file mode 100644 (file)
index 0000000..9590c61
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MCI_H
+#define MCI_H
+
+#define ATH_MCI_DEF_BT_PERIOD          40
+#define ATH_MCI_BDR_DUTY_CYCLE         20
+#define ATH_MCI_MAX_DUTY_CYCLE         90
+
+#define ATH_MCI_DEF_AGGR_LIMIT         6 /* in 0.24 ms */
+#define ATH_MCI_MAX_ACL_PROFILE                7
+#define ATH_MCI_MAX_SCO_PROFILE                1
+#define ATH_MCI_MAX_PROFILE            (ATH_MCI_MAX_ACL_PROFILE +\
+                                        ATH_MCI_MAX_SCO_PROFILE)
+
+#define INC_PROF(_mci, _info) do {              \
+               switch (_info->type) {           \
+               case MCI_GPM_COEX_PROFILE_RFCOMM:\
+                       _mci->num_other_acl++;   \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_A2DP:  \
+                       _mci->num_a2dp++;        \
+                       if (!_info->edr)         \
+                               _mci->num_bdr++; \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_HID:   \
+                       _mci->num_hid++;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_BNEP:  \
+                       _mci->num_pan++;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_VOICE: \
+                       _mci->num_sco++;         \
+                       break;                   \
+               default:                         \
+                       break;                   \
+               }                                \
+       } while (0)
+
+#define DEC_PROF(_mci, _info) do {              \
+               switch (_info->type) {           \
+               case MCI_GPM_COEX_PROFILE_RFCOMM:\
+                       _mci->num_other_acl--;   \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_A2DP:  \
+                       _mci->num_a2dp--;        \
+                       if (!_info->edr)         \
+                               _mci->num_bdr--; \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_HID:   \
+                       _mci->num_hid--;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_BNEP:  \
+                       _mci->num_pan--;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_VOICE: \
+                       _mci->num_sco--;         \
+                       break;                   \
+               default:                         \
+                       break;                   \
+               }                                \
+       } while (0)
+
+#define NUM_PROF(_mci) (_mci->num_other_acl + _mci->num_a2dp + \
+                        _mci->num_hid + _mci->num_pan + _mci->num_sco)
+
+struct ath_mci_profile_info {
+       u8 type;
+       u8 conn_handle;
+       bool start;
+       bool master;
+       bool edr;
+       u8 voice_type;
+       u16 T;          /* Voice: Tvoice, HID: Tsniff,        in slots */
+       u8 W;           /* Voice: Wvoice, HID: Sniff timeout, in slots */
+       u8 A;           /*                HID: Sniff attempt, in slots */
+       struct list_head list;
+};
+
+struct ath_mci_profile_status {
+       bool is_critical;
+       bool is_link;
+       u8 conn_handle;
+};
+
+struct ath_mci_profile {
+       struct list_head info;
+       DECLARE_BITMAP(status, ATH_MCI_MAX_PROFILE);
+       u16 aggr_limit;
+       u8 num_mgmt;
+       u8 num_sco;
+       u8 num_a2dp;
+       u8 num_hid;
+       u8 num_pan;
+       u8 num_other_acl;
+       u8 num_bdr;
+};
+
+void ath_mci_flush_profile(struct ath_mci_profile *mci);
+void ath_mci_process_profile(struct ath_softc *sc,
+                            struct ath_mci_profile_info *info);
+void ath_mci_process_status(struct ath_softc *sc,
+                           struct ath_mci_profile_status *status);
+#endif
index 03b0a651a591c39e79b331ca3c303cc0f08e6d93..55d077e7135d1549aeed07cb839f84874e4fff96 100644 (file)
@@ -601,6 +601,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
+       struct ath_mci_profile *mci = &sc->btcoex.mci;
        u32 max_4ms_framelen, frmlen;
        u16 aggr_limit, legacy = 0;
        int i;
@@ -645,7 +646,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
                return 0;
 
-       if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
+               aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
+       else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
                aggr_limit = min((max_4ms_framelen * 3) / 8,
                                 (u32)ATH_AMPDU_LIMIT_MAX);
        else
index b44e3094588afcac6abed088a7ba9c7eb5b9775f..d58aa1b0a932de0ed1b095d29c5ece1589492995 100644 (file)
@@ -26,7 +26,8 @@ DHDOFILES = \
        dhd_sdio.o      \
        dhd_linux.o \
        bcmsdh.o \
-       bcmsdh_sdmmc.o
+       bcmsdh_sdmmc.o \
+       sdio_chip.o
 
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += $(DHDOFILES)
index d7d3afd5a10fbb52bc14a2b8d1f2a26df121c3e2..cecb5e5f412ba2007938f7fdacddb160756e50e3 100644 (file)
 #define _bcmchip_h_
 
 /* bcm4329 */
-/* SDIO device core, ID 0x829 */
-#define BCM4329_CORE_BUS_BASE          0x18011000
-/* internal memory core, ID 0x80e */
-#define BCM4329_CORE_SOCRAM_BASE       0x18003000
-/* ARM Cortex M3 core, ID 0x82a */
-#define BCM4329_CORE_ARM_BASE          0x18002000
-#define BCM4329_RAMSIZE                        0x48000
 /* firmware name */
 #define BCM4329_FW_NAME                        "brcm/bcm4329-fullmac-4.bin"
 #define BCM4329_NV_NAME                        "brcm/bcm4329-fullmac-4.txt"
index 4645766b40704c272254928385de8d9e404e69a9..6da519e7578f71a81b5f19d1d7411cb875d04ded 100644 (file)
@@ -87,7 +87,7 @@
 #define TOE_TX_CSUM_OL         0x00000001
 #define TOE_RX_CSUM_OL         0x00000002
 
-#define        BRCMF_BSS_INFO_VERSION  108 /* current ver of brcmf_bss_info struct */
+#define        BRCMF_BSS_INFO_VERSION  108 /* curr ver of brcmf_bss_info_le struct */
 
 /* size of brcmf_scan_params not including variable length array */
 #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
 
 /* For supporting multiple interfaces */
 #define BRCMF_MAX_IFS  16
-#define BRCMF_DEL_IF   -0xe
-#define BRCMF_BAD_IF   -0xf
 
 #define DOT11_BSSTYPE_ANY                      2
 #define DOT11_MAX_DEFAULT_KEYS 4
@@ -365,7 +363,7 @@ struct brcmf_pkt_filter_enable_le {
  * Applications MUST CHECK ie_offset field and length field to access IEs and
  * next bss_info structure in a vector (in struct brcmf_scan_results)
  */
-struct brcmf_bss_info {
+struct brcmf_bss_info_le {
        __le32 version;         /* version field */
        __le32 length;          /* byte length of data in this record,
                                 * starting at version and including IEs
@@ -466,14 +464,13 @@ struct brcmf_scan_results {
        u32 buflen;
        u32 version;
        u32 count;
-       struct brcmf_bss_info bss_info[1];
+       struct brcmf_bss_info_le bss_info_le[];
 };
 
 struct brcmf_scan_results_le {
        __le32 buflen;
        __le32 version;
        __le32 count;
-       struct brcmf_bss_info bss_info[1];
 };
 
 /* used for association with a specific BSSID and chanspec list */
@@ -493,10 +490,6 @@ struct brcmf_join_params {
        struct brcmf_assoc_params_le params_le;
 };
 
-/* size of brcmf_scan_results not including variable length array */
-#define BRCMF_SCAN_RESULTS_FIXED_SIZE \
-       (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info))
-
 /* incremental scan results struct */
 struct brcmf_iscan_results {
        union {
@@ -511,7 +504,7 @@ struct brcmf_iscan_results {
 
 /* size of brcmf_iscan_results not including variable length array */
 #define BRCMF_ISCAN_RESULTS_FIXED_SIZE \
-       (BRCMF_SCAN_RESULTS_FIXED_SIZE + \
+       (sizeof(struct brcmf_scan_results) + \
         offsetof(struct brcmf_iscan_results, results))
 
 struct brcmf_wsec_key {
@@ -734,8 +727,7 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
 extern void brcmf_c_init(void);
 
 extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
-                       struct net_device *ndev, char *name, u8 *mac_addr,
-                       u32 flags, u8 bssidx);
+                       char *name, u8 *mac_addr);
 extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);
 
 /* Send packet to dongle via data channel */
index 891826197f966bd9112c4cf32da8055fe9532682..40928e58b6a615f01463e05a78d2decee9a04ecb 100644 (file)
@@ -488,10 +488,9 @@ brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
 
                if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
                        if (ifevent->action == BRCMF_E_IF_ADD)
-                               brcmf_add_if(drvr_priv, ifevent->ifidx, NULL,
+                               brcmf_add_if(drvr_priv, ifevent->ifidx,
                                             event->ifname,
-                                            pvt_data->eth.h_dest,
-                                            ifevent->flags, ifevent->bssidx);
+                                            pvt_data->eth.h_dest);
                        else
                                brcmf_del_if(drvr_priv, ifevent->ifidx);
                } else {
index 4acbac5a74c6ee41a44981cd886c89172408eb2c..719fd9397eb6f5dc405d8b04783871a50697acb6 100644 (file)
@@ -58,7 +58,6 @@ struct brcmf_if {
        struct net_device *ndev;
        struct net_device_stats stats;
        int idx;                /* iface idx in dongle */
-       int state;              /* interface state */
        u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
 };
 
@@ -80,20 +79,6 @@ struct brcmf_info {
 /* Error bits */
 module_param(brcmf_msg_level, int, 0);
 
-
-static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev)
-{
-       int i = 0;
-
-       while (i < BRCMF_MAX_IFS) {
-               if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev)
-                       return i;
-               i++;
-       }
-
-       return BRCMF_BAD_IF;
-}
-
 int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
 {
        int i = BRCMF_MAX_IFS;
@@ -285,14 +270,9 @@ _brcmf_set_mac_address(struct work_struct *work)
 
 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        struct sockaddr *sa = (struct sockaddr *)addr;
-       int ifidx;
-
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return -1;
 
        memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
        schedule_work(&drvr_priv->setmacaddr_work);
@@ -301,13 +281,8 @@ static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 
 static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
-
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        schedule_work(&drvr_priv->multicast_work);
 }
@@ -341,9 +316,8 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        int ret;
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -355,9 +329,8 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return -ENODEV;
        }
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF) {
-               brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx);
+       if (!drvr_priv->iflist[ifp->idx]) {
+               brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);
                netif_stop_queue(ndev);
                return -ENODEV;
        }
@@ -367,20 +340,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                struct sk_buff *skb2;
 
                brcmf_dbg(INFO, "%s: insufficient headroom\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx));
+                         brcmf_ifname(&drvr_priv->pub, ifp->idx));
                drvr_priv->pub.tx_realloc++;
                skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
                dev_kfree_skb(skb);
                skb = skb2;
                if (skb == NULL) {
                        brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
-                                 brcmf_ifname(&drvr_priv->pub, ifidx));
+                                 brcmf_ifname(&drvr_priv->pub, ifp->idx));
                        ret = -ENOMEM;
                        goto done;
                }
        }
 
-       ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb);
+       ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb);
 
 done:
        if (ret)
@@ -482,12 +455,10 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
                                          skb_mac_header(skb),
                                          &event, &data);
 
-               if (drvr_priv->iflist[ifidx] &&
-                   !drvr_priv->iflist[ifidx]->state)
+               if (drvr_priv->iflist[ifidx]) {
                        ifp = drvr_priv->iflist[ifidx];
-
-               if (ifp->ndev)
                        ifp->ndev->last_rx = jiffies;
+               }
 
                drvr->dstats.rx_bytes += skb->len;
                drvr->rx_packets++;     /* Local count */
@@ -524,19 +495,11 @@ void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       struct brcmf_if *ifp;
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return NULL;
-
-       ifp = drvr_priv->iflist[ifidx];
-
        if (drvr_priv->pub.up)
                /* Use the protocol to get dongle stats */
                brcmf_proto_dstats(&drvr_priv->pub);
@@ -637,8 +600,8 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
 static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
                                    struct ethtool_drvinfo *info)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        sprintf(info->driver, KBUILD_MODNAME);
        sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
@@ -765,14 +728,12 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
 static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
                                    int cmd)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd);
+       brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
 
-       if (ifidx == BRCMF_BAD_IF)
+       if (!drvr_priv->iflist[ifp->idx])
                return -1;
 
        if (cmd == SIOCETHTOOL)
@@ -788,17 +749,14 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
        s32 err = 0;
        int buflen = 0;
        bool is_set_key_cmd;
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        memset(&dcmd, 0, sizeof(dcmd));
        dcmd.cmd = cmd;
        dcmd.buf = arg;
        dcmd.len = len;
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-
        if (dcmd.buf != NULL)
                buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
 
@@ -826,7 +784,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
        if (is_set_key_cmd)
                brcmf_netdev_wait_pend8021x(ndev);
 
-       err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen);
+       err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen);
 
 done:
        if (err > 0)
@@ -837,7 +795,8 @@ done:
 
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
-       struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_pub *drvr = &ifp->info->pub;
 
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_cfg80211_down(drvr->config);
@@ -853,16 +812,14 @@ static int brcmf_netdev_stop(struct net_device *ndev)
 
 static int brcmf_netdev_open(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        u32 toe_ol;
-       int ifidx = brcmf_net2idx(drvr_priv, ndev);
        s32 ret = 0;
 
-       brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
-
-       if (ifidx == 0) {       /* do it only for primary eth0 */
+       brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
+       if (ifp->idx == 0) {    /* do it only for primary eth0 */
                /* try to bring up bus */
                ret = brcmf_bus_start(&drvr_priv->pub);
                if (ret != 0) {
@@ -874,12 +831,12 @@ static int brcmf_netdev_open(struct net_device *ndev)
                memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
 
                /* Get current TOE mode from dongle */
-               if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0
+               if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0
                    && (toe_ol & TOE_TX_CSUM_OL) != 0)
-                       drvr_priv->iflist[ifidx]->ndev->features |=
+                       drvr_priv->iflist[ifp->idx]->ndev->features |=
                                NETIF_F_IP_CSUM;
                else
-                       drvr_priv->iflist[ifidx]->ndev->features &=
+                       drvr_priv->iflist[ifp->idx]->ndev->features &=
                                ~NETIF_F_IP_CSUM;
        }
        /* Allow transmit calls */
@@ -893,75 +850,62 @@ static int brcmf_netdev_open(struct net_device *ndev)
        return ret;
 }
 
+static const struct net_device_ops brcmf_netdev_ops_pri = {
+       .ndo_open = brcmf_netdev_open,
+       .ndo_stop = brcmf_netdev_stop,
+       .ndo_get_stats = brcmf_netdev_get_stats,
+       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
+       .ndo_start_xmit = brcmf_netdev_start_xmit,
+       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
+       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
+};
+
 int
-brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev,
-            char *name, u8 *mac_addr, u32 flags, u8 bssidx)
+brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr)
 {
        struct brcmf_if *ifp;
-       int ret = 0, err = 0;
+       struct net_device *ndev;
 
-       brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev);
+       brcmf_dbg(TRACE, "idx %d\n", ifidx);
 
        ifp = drvr_priv->iflist[ifidx];
-       if (!ifp) {
-               ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
-               if (!ifp)
-                       return -ENOMEM;
+       /*
+        * Delete the existing interface before overwriting it
+        * in case we missed the BRCMF_E_IF_DEL event.
+        */
+       if (ifp) {
+               brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
+                         ifp->ndev->name);
+               netif_stop_queue(ifp->ndev);
+               unregister_netdev(ifp->ndev);
+               free_netdev(ifp->ndev);
+               drvr_priv->iflist[ifidx] = NULL;
+       }
+
+       /* Allocate netdev, including space for private structure */
+       ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
+       if (!ndev) {
+               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
+               return -ENOMEM;
        }
 
-       memset(ifp, 0, sizeof(struct brcmf_if));
+       ifp = netdev_priv(ndev);
+       ifp->ndev = ndev;
        ifp->info = drvr_priv;
        drvr_priv->iflist[ifidx] = ifp;
+       ifp->idx = ifidx;
        if (mac_addr != NULL)
                memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
 
-       if (ndev == NULL) {
-               ifp->state = BRCMF_E_IF_ADD;
-               ifp->idx = ifidx;
-               /*
-                * Delete the existing interface before overwriting it
-                * in case we missed the BRCMF_E_IF_DEL event.
-                */
-               if (ifp->ndev != NULL) {
-                       brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
-                                 ifp->ndev->name);
-                       netif_stop_queue(ifp->ndev);
-                       unregister_netdev(ifp->ndev);
-                       free_netdev(ifp->ndev);
-               }
-
-               /* Allocate netdev, including space for private structure */
-               ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d",
-                                        ether_setup);
-               if (!ifp->ndev) {
-                       brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-                       ret = -ENOMEM;
-               }
-
-               if (ret == 0) {
-                       memcpy(netdev_priv(ifp->ndev), &drvr_priv,
-                              sizeof(drvr_priv));
-                       err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
-                       if (err != 0) {
-                               brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n",
-                                         err);
-                               ret = -EOPNOTSUPP;
-                       } else {
-                               brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
-                                         current->pid, ifp->ndev->name);
-                               ifp->state = 0;
-                       }
-               }
-
-               if (ret < 0) {
-                       if (ifp->ndev)
-                               free_netdev(ifp->ndev);
+       if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) {
+               brcmf_dbg(ERROR, "brcmf_net_attach failed");
+               free_netdev(ifp->ndev);
+               drvr_priv->iflist[ifidx] = NULL;
+               return -EOPNOTSUPP;
+       }
 
-                       drvr_priv->iflist[ifp->idx] = NULL;
-                       kfree(ifp);
-               }
-       } else
-               ifp->ndev = ndev;
+       brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
+                 current->pid, ifp->ndev->name);
 
        return 0;
 }
@@ -977,47 +921,36 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
                brcmf_dbg(ERROR, "Null interface\n");
                return;
        }
+       if (ifp->ndev) {
+               if (ifidx == 0) {
+                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+                               rtnl_lock();
+                               brcmf_netdev_stop(ifp->ndev);
+                               rtnl_unlock();
+                       }
+               } else {
+                       netif_stop_queue(ifp->ndev);
+               }
 
-       ifp->state = BRCMF_E_IF_DEL;
-       ifp->idx = ifidx;
-       if (ifp->ndev != NULL) {
-               netif_stop_queue(ifp->ndev);
                unregister_netdev(ifp->ndev);
-               free_netdev(ifp->ndev);
                drvr_priv->iflist[ifidx] = NULL;
-               kfree(ifp);
+               if (ifidx == 0)
+                       brcmf_cfg80211_detach(drvr_priv->pub.config);
+               free_netdev(ifp->ndev);
        }
 }
 
 struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
 {
        struct brcmf_info *drvr_priv = NULL;
-       struct net_device *ndev;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* Allocate netdev, including space for private structure */
-       ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
-       if (!ndev) {
-               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-               goto fail;
-       }
-
        /* Allocate primary brcmf_info */
        drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
        if (!drvr_priv)
                goto fail;
 
-       /*
-        * Save the brcmf_info into the priv
-        */
-       memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-
-       if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) ==
-           BRCMF_BAD_IF)
-               goto fail;
-
-       ndev->netdev_ops = NULL;
        mutex_init(&drvr_priv->proto_block);
 
        /* Link to info module */
@@ -1033,29 +966,12 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
                goto fail;
        }
 
-       /* Attach and link in the cfg80211 */
-       drvr_priv->pub.config =
-                       brcmf_cfg80211_attach(ndev,
-                                             brcmf_bus_get_device(bus),
-                                             &drvr_priv->pub);
-       if (drvr_priv->pub.config == NULL) {
-               brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
-               goto fail;
-       }
-
        INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
        INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
 
-       /*
-        * Save the brcmf_info into the priv
-        */
-       memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-
        return &drvr_priv->pub;
 
 fail:
-       if (ndev)
-               free_netdev(ndev);
        if (drvr_priv)
                brcmf_detach(&drvr_priv->pub);
 
@@ -1123,16 +1039,6 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
        return 0;
 }
 
-static struct net_device_ops brcmf_netdev_ops_pri = {
-       .ndo_open = brcmf_netdev_open,
-       .ndo_stop = brcmf_netdev_stop,
-       .ndo_get_stats = brcmf_netdev_get_stats,
-       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
-       .ndo_start_xmit = brcmf_netdev_start_xmit,
-       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
-       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
 int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 {
        struct brcmf_info *drvr_priv = drvr->info;
@@ -1169,6 +1075,18 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 
        memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
 
+       /* attach to cfg80211 for primary interface */
+       if (!ifidx) {
+               drvr->config =
+                       brcmf_cfg80211_attach(ndev,
+                                             brcmf_bus_get_device(drvr->bus),
+                                             drvr);
+               if (drvr->config == NULL) {
+                       brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
+                       goto fail;
+               }
+       }
+
        if (register_netdev(ndev) != 0) {
                brcmf_dbg(ERROR, "couldn't register the net device\n");
                goto fail;
@@ -1210,21 +1128,13 @@ void brcmf_detach(struct brcmf_pub *drvr)
        if (drvr) {
                drvr_priv = drvr->info;
                if (drvr_priv) {
-                       struct brcmf_if *ifp;
                        int i;
 
-                       for (i = 1; i < BRCMF_MAX_IFS; i++)
+                       /* make sure primary interface removed last */
+                       for (i = BRCMF_MAX_IFS-1; i > -1; i--)
                                if (drvr_priv->iflist[i])
                                        brcmf_del_if(drvr_priv, i);
 
-                       ifp = drvr_priv->iflist[0];
-                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
-                               rtnl_lock();
-                               brcmf_netdev_stop(ifp->ndev);
-                               rtnl_unlock();
-                               unregister_netdev(ifp->ndev);
-                       }
-
                        cancel_work_sync(&drvr_priv->setmacaddr_work);
                        cancel_work_sync(&drvr_priv->multicast_work);
 
@@ -1233,10 +1143,6 @@ void brcmf_detach(struct brcmf_pub *drvr)
                        if (drvr->prot)
                                brcmf_proto_detach(drvr);
 
-                       brcmf_cfg80211_detach(drvr->config);
-
-                       free_netdev(ifp->ndev);
-                       kfree(ifp);
                        kfree(drvr_priv);
                }
        }
@@ -1302,7 +1208,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
 
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        int timeout = 10 * HZ / 1000;
        int ntimes = MAX_WAIT_FOR_8021X_TX;
        int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
index 313b8bf592d13782df7e3a6905cff60ed0b1be19..22913af26db85156e29418f85bb1e70e99d0a24e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/semaphore.h>
 #include <linux/firmware.h>
 #include <linux/module.h>
+#include <linux/bcma/bcma.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -35,6 +36,7 @@
 #include <brcm_hw_ids.h>
 #include <soc.h>
 #include "sdio_host.h"
+#include "sdio_chip.h"
 
 #define DCMD_RESP_TIMEOUT  2000        /* In milli second */
 
@@ -134,33 +136,6 @@ struct rte_console {
 /*   Force no backplane reset */
 #define SBSDIO_DEVCTL_RST_NOBPRESET    0x20
 
-/* SBSDIO_FUNC1_CHIPCLKCSR */
-
-/* Force ALP request to backplane */
-#define SBSDIO_FORCE_ALP               0x01
-/* Force HT request to backplane */
-#define SBSDIO_FORCE_HT                        0x02
-/* Force ILP request to backplane */
-#define SBSDIO_FORCE_ILP               0x04
-/* Make ALP ready (power up xtal) */
-#define SBSDIO_ALP_AVAIL_REQ           0x08
-/* Make HT ready (power up PLL) */
-#define SBSDIO_HT_AVAIL_REQ            0x10
-/* Squelch clock requests from HW */
-#define SBSDIO_FORCE_HW_CLKREQ_OFF     0x20
-/* Status: ALP is ready */
-#define SBSDIO_ALP_AVAIL               0x40
-/* Status: HT is ready */
-#define SBSDIO_HT_AVAIL                        0x80
-
-#define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
-#define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
-#define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
-#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
-
-#define SBSDIO_CLKAV(regval, alponly) \
-       (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
-
 /* direct(mapped) cis space */
 
 /* MAPPED common CIS address */
@@ -335,50 +310,6 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-/* sbimstate */
-#define        SBIM_IBE                0x20000 /* inbanderror */
-#define        SBIM_TO                 0x40000 /* timeout */
-#define        SBIM_BY                 0x01800000      /* busy (sonics >= 2.3) */
-#define        SBIM_RJ                 0x02000000      /* reject (sonics >= 2.3) */
-
-/* sbtmstatelow */
-
-/* reset */
-#define        SBTML_RESET             0x0001
-/* reject field */
-#define        SBTML_REJ_MASK          0x0006
-/* reject */
-#define        SBTML_REJ               0x0002
-/* temporary reject, for error recovery */
-#define        SBTML_TMPREJ            0x0004
-
-/* Shift to locate the SI control flags in sbtml */
-#define        SBTML_SICF_SHIFT        16
-
-/* sbtmstatehigh */
-#define        SBTMH_SERR              0x0001  /* serror */
-#define        SBTMH_INT               0x0002  /* interrupt */
-#define        SBTMH_BUSY              0x0004  /* busy */
-#define        SBTMH_TO                0x0020  /* timeout (sonics >= 2.3) */
-
-/* Shift to locate the SI status flags in sbtmh */
-#define        SBTMH_SISF_SHIFT        16
-
-/* sbidlow */
-#define        SBIDL_INIT              0x80    /* initiator */
-
-/* sbidhigh */
-#define        SBIDH_RC_MASK           0x000f  /* revision code */
-#define        SBIDH_RCE_MASK          0x7000  /* revision code extension field */
-#define        SBIDH_RCE_SHIFT         8
-#define        SBCOREREV(sbidh) \
-       ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \
-         ((sbidh) & SBIDH_RC_MASK))
-#define        SBIDH_CC_MASK           0x8ff0  /* core code */
-#define        SBIDH_CC_SHIFT          4
-#define        SBIDH_VC_MASK           0xffff0000      /* vendor code */
-#define        SBIDH_VC_SHIFT          16
-
 /*
  * Conversion of 802.1D priority to precedence level
  */
@@ -388,17 +319,6 @@ static uint prio2prec(u32 prio)
               (prio^2) : prio;
 }
 
-/*
- * Core reg address translation.
- * Both macro's returns a 32 bits byte address on the backplane bus.
- */
-#define CORE_CC_REG(base, field) \
-               (base + offsetof(struct chipcregs, field))
-#define CORE_BUS_REG(base, field) \
-               (base + offsetof(struct sdpcmd_regs, field))
-#define CORE_SB(base, field) \
-               (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
-
 /* core registers */
 struct sdpcmd_regs {
        u32 corecontrol;                /* 0x00, rev8 */
@@ -524,21 +444,6 @@ struct sdpcm_shared_le {
 
 
 /* misc chip info needed by some of the routines */
-struct chip_info {
-       u32 chip;
-       u32 chiprev;
-       u32 cccorebase;
-       u32 ccrev;
-       u32 cccaps;
-       u32 buscorebase; /* 32 bits backplane bus address */
-       u32 buscorerev;
-       u32 buscoretype;
-       u32 ramcorebase;
-       u32 armcorebase;
-       u32 pmurev;
-       u32 ramsize;
-};
-
 /* Private data for SDIO bus interaction */
 struct brcmf_bus {
        struct brcmf_pub *drvr;
@@ -574,7 +479,7 @@ struct brcmf_bus {
        uint txminmax;
 
        struct sk_buff *glomd;  /* Packet containing glomming descriptor */
-       struct sk_buff *glom;   /* Packet chain for glommed superframe */
+       struct sk_buff_head glom; /* Packet list for glommed superframe */
        uint glomerr;           /* Glom packet read errors */
 
        u8 *rxbuf;              /* Buffer for receiving control packets */
@@ -663,46 +568,6 @@ struct brcmf_bus {
        u32 fw_ptr;
 };
 
-struct sbconfig {
-       u32 PAD[2];
-       u32 sbipsflag;  /* initiator port ocp slave flag */
-       u32 PAD[3];
-       u32 sbtpsflag;  /* target port ocp slave flag */
-       u32 PAD[11];
-       u32 sbtmerrloga;        /* (sonics >= 2.3) */
-       u32 PAD;
-       u32 sbtmerrlog; /* (sonics >= 2.3) */
-       u32 PAD[3];
-       u32 sbadmatch3; /* address match3 */
-       u32 PAD;
-       u32 sbadmatch2; /* address match2 */
-       u32 PAD;
-       u32 sbadmatch1; /* address match1 */
-       u32 PAD[7];
-       u32 sbimstate;  /* initiator agent state */
-       u32 sbintvec;   /* interrupt mask */
-       u32 sbtmstatelow;       /* target state */
-       u32 sbtmstatehigh;      /* target state */
-       u32 sbbwa0;             /* bandwidth allocation table0 */
-       u32 PAD;
-       u32 sbimconfiglow;      /* initiator configuration */
-       u32 sbimconfighigh;     /* initiator configuration */
-       u32 sbadmatch0; /* address match0 */
-       u32 PAD;
-       u32 sbtmconfiglow;      /* target configuration */
-       u32 sbtmconfighigh;     /* target configuration */
-       u32 sbbconfig;  /* broadcast configuration */
-       u32 PAD;
-       u32 sbbstate;   /* broadcast state */
-       u32 PAD[3];
-       u32 sbactcnfg;  /* activate configuration */
-       u32 PAD[3];
-       u32 sbflagst;   /* current sbflags */
-       u32 PAD[3];
-       u32 sbidlow;            /* identification */
-       u32 sbidhigh;   /* identification */
-};
-
 /* clkstate */
 #define CLK_NONE       0
 #define CLK_SDONLY     1
@@ -750,10 +615,12 @@ static bool data_ok(struct brcmf_bus *bus)
 static void
 r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 {
+       u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
        do {
                *regvar = brcmf_sdcard_reg_read(bus->sdiodev,
-                               bus->ci->buscorebase + reg_offset, sizeof(u32));
+                               bus->ci->c_inf[idx].base + reg_offset,
+                               sizeof(u32));
        } while (brcmf_sdcard_regfail(bus->sdiodev) &&
                 (++(*retryvar) <= retry_limit));
        if (*retryvar) {
@@ -768,10 +635,11 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 static void
 w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
 {
+       u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
        do {
                brcmf_sdcard_reg_write(bus->sdiodev,
-                                      bus->ci->buscorebase + reg_offset,
+                                      bus->ci->c_inf[idx].base + reg_offset,
                                       sizeof(u32), regval);
        } while (brcmf_sdcard_regfail(bus->sdiodev) &&
                 (++(*retryvar) <= retry_limit));
@@ -812,10 +680,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
                clkreq =
                    bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
 
-               if ((bus->ci->chip == BCM4329_CHIP_ID)
-                   && (bus->ci->chiprev == 0))
-                       clkreq |= SBSDIO_FORCE_ALP;
-
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                                       SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
                if (err) {
@@ -823,14 +687,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
                        return -EBADE;
                }
 
-               if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID)
-                              && (bus->ci->buscorerev == 9))) {
-                       u32 dummy, retries;
-                       r_sdreg32(bus, &dummy,
-                                 offsetof(struct sdpcmd_regs, clockctlstatus),
-                                 &retries);
-               }
-
                /* Check current status */
                clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
                                               SBSDIO_FUNC1_CHIPCLKCSR, &err);
@@ -1034,11 +890,9 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
                        SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
 
                /* Isolate the bus */
-               if (bus->ci->chip != BCM4329_CHIP_ID) {
-                       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_DEVICE_CTL,
-                               SBSDIO_DEVCTL_PADS_ISO, NULL);
-               }
+               brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+                       SBSDIO_DEVICE_CTL,
+                       SBSDIO_DEVCTL_PADS_ISO, NULL);
 
                /* Change state */
                bus->sleeping = true;
@@ -1049,13 +903,6 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                        SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
 
-               /* Force pad isolation off if possible
-                        (in case power never toggled) */
-               if ((bus->ci->buscoretype == PCMCIA_CORE_ID)
-                   && (bus->ci->buscorerev >= 10))
-                       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_DEVICE_CTL, 0, NULL);
-
                /* Make sure the controller has the bus up */
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
 
@@ -1222,6 +1069,51 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
                bus->drvr->busstate = BRCMF_BUS_DOWN;
 }
 
+/* copy a buffer into a pkt buffer chain */
+static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len)
+{
+       uint n, ret = 0;
+       struct sk_buff *p;
+       u8 *buf;
+
+       buf = bus->dataptr;
+
+       /* copy the data */
+       skb_queue_walk(&bus->glom, p) {
+               n = min_t(uint, p->len, len);
+               memcpy(p->data, buf, n);
+               buf += n;
+               len -= n;
+               ret += n;
+               if (!len)
+                       break;
+       }
+
+       return ret;
+}
+
+/* return total length of buffer chain */
+static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus)
+{
+       struct sk_buff *p;
+       uint total;
+
+       total = 0;
+       skb_queue_walk(&bus->glom, p)
+               total += p->len;
+       return total;
+}
+
+static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus)
+{
+       struct sk_buff *cur, *next;
+
+       skb_queue_walk_safe(&bus->glom, cur, next) {
+               skb_unlink(cur, &bus->glom);
+               brcmu_pkt_buf_free_skb(cur);
+       }
+}
+
 static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 {
        u16 dlen, totlen;
@@ -1240,7 +1132,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
        /* If packets, issue read(s) and send up packet chain */
        /* Return sequence numbers consumed? */
 
-       brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);
+       brcmf_dbg(TRACE, "start: glomd %p glom %p\n",
+                 bus->glomd, skb_peek(&bus->glom));
 
        /* If there's a descriptor, generate the packet chain */
        if (bus->glomd) {
@@ -1287,12 +1180,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                          num, sublen);
                                break;
                        }
-                       if (!pfirst) {
-                               pfirst = plast = pnext;
-                       } else {
-                               plast->next = pnext;
-                               plast = pnext;
-                       }
+                       skb_queue_tail(&bus->glom, pnext);
 
                        /* Adhere to start alignment requirements */
                        pkt_align(pnext, sublen, BRCMF_SDALIGN);
@@ -1308,12 +1196,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
                                          bus->nextlen, totlen, rxseq);
                        }
-                       bus->glom = pfirst;
                        pfirst = pnext = NULL;
                } else {
-                       if (pfirst)
-                               brcmu_pkt_buf_free_skb(pfirst);
-                       bus->glom = NULL;
+                       brcmf_sdbrcm_free_glom(bus);
                        num = 0;
                }
 
@@ -1325,18 +1210,18 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
        /* Ok -- either we just generated a packet chain,
                 or had one from before */
-       if (bus->glom) {
+       if (!skb_queue_empty(&bus->glom)) {
                if (BRCMF_GLOM_ON()) {
                        brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
-                       for (pnext = bus->glom; pnext; pnext = pnext->next) {
+                       skb_queue_walk(&bus->glom, pnext) {
                                brcmf_dbg(GLOM, "    %p: %p len 0x%04x (%d)\n",
                                          pnext, (u8 *) (pnext->data),
                                          pnext->len, pnext->len);
                        }
                }
 
-               pfirst = bus->glom;
-               dlen = (u16) brcmu_pkttotlen(pfirst);
+               pfirst = skb_peek(&bus->glom);
+               dlen = (u16) brcmf_sdbrcm_glom_len(bus);
 
                /* Do an SDIO read for the superframe.  Configurable iovar to
                 * read directly into the chained packet, or allocate a large
@@ -1354,8 +1239,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                        SDIO_FUNC_2,
                                        F2SYNC, bus->dataptr, dlen,
                                        NULL);
-                       sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
-                                               bus->dataptr);
+                       sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
                        if (sublen != dlen) {
                                brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
                                          dlen, sublen);
@@ -1380,9 +1264,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               brcmu_pkt_buf_free_skb(bus->glom);
                                bus->rxglomfail++;
-                               bus->glom = NULL;
+                               brcmf_sdbrcm_free_glom(bus);
                        }
                        return 0;
                }
@@ -1503,9 +1386,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               brcmu_pkt_buf_free_skb(bus->glom);
                                bus->rxglomfail++;
-                               bus->glom = NULL;
+                               brcmf_sdbrcm_free_glom(bus);
                        }
                        bus->nextlen = 0;
                        return 0;
@@ -1513,7 +1395,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
                /* Basic SD framing looks ok - process each packet (header) */
                save_pfirst = pfirst;
-               bus->glom = NULL;
                plast = NULL;
 
                for (num = 0; pfirst; rxseq++, pfirst = pnext) {
@@ -1850,10 +1731,10 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
             rxseq++, rxleft--) {
 
                /* Handle glomming separately */
-               if (bus->glom || bus->glomd) {
+               if (bus->glomd || !skb_queue_empty(&bus->glom)) {
                        u8 cnt;
                        brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
-                                 bus->glomd, bus->glom);
+                                 bus->glomd, skb_peek(&bus->glom));
                        cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
                        brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
                        rxseq += cnt - 1;
@@ -3210,135 +3091,11 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
        return bcmerror;
 }
 
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
-       u32 regdata;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(corebase, sbtmstatelow), 4);
-       if (regdata & SBTML_RESET)
-               return;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(corebase, sbtmstatelow), 4);
-       if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
-               /*
-                * set target reject and spin until busy is clear
-                * (preserve core-specific bits)
-                */
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
-                                      4, regdata | SBTML_REJ);
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               udelay(1);
-               SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatehigh), 4) &
-                       SBTMH_BUSY), 100000);
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatehigh), 4);
-               if (regdata & SBTMH_BUSY)
-                       brcmf_dbg(ERROR, "ARM core still busy\n");
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbidlow), 4);
-               if (regdata & SBIDL_INIT) {
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) |
-                               SBIM_RJ;
-                       brcmf_sdcard_reg_write(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4,
-                               regdata);
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4);
-                       udelay(1);
-                       SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) &
-                               SBIM_BY), 100000);
-               }
-
-               /* set reset and reject while enabling the clocks */
-               brcmf_sdcard_reg_write(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4,
-                       (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
-                       SBTML_REJ | SBTML_RESET));
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               udelay(10);
-
-               /* clear the initiator reject bit */
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbidlow), 4);
-               if (regdata & SBIDL_INIT) {
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) &
-                               ~SBIM_RJ;
-                       brcmf_sdcard_reg_write(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4,
-                               regdata);
-               }
-       }
-
-       /* leave reset and reject asserted */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SBTML_REJ | SBTML_RESET));
-       udelay(1);
-}
-
-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
-       u32 regdata;
-
-       /*
-        * Must do the disable sequence first to work for
-        * arbitrary current core state.
-        */
-       brcmf_sdbrcm_chip_disablecore(sdiodev, corebase);
-
-       /*
-        * Now do the initialization sequence.
-        * set reset while enabling the clock and
-        * forcing them on throughout the core
-        */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
-               SBTML_RESET);
-       udelay(1);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(corebase, sbtmstatehigh), 4);
-       if (regdata & SBTMH_SERR)
-               brcmf_sdcard_reg_write(sdiodev,
-                                      CORE_SB(corebase, sbtmstatehigh), 4, 0);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(corebase, sbimstate), 4);
-       if (regdata & (SBIM_IBE | SBIM_TO))
-               brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
-                       regdata & ~(SBIM_IBE | SBIM_TO));
-
-       /* clear reset and allow it to propagate throughout the core */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SICF_FGC << SBTML_SICF_SHIFT) |
-               (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-       udelay(1);
-
-       /* leave clock enabled */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-       udelay(1);
-}
-
 static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
 {
        uint retries;
-       u32 regdata;
        int bcmerror = 0;
+       struct chip_info *ci = bus->ci;
 
        /* To enter download state, disable ARM and reset SOCRAM.
         * To exit download state, simply reset ARM (default is RAM boot).
@@ -3346,10 +3103,9 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
        if (enter) {
                bus->alp_only = true;
 
-               brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
-                                             bus->ci->armcorebase);
+               ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
 
-               brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
+               ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
 
                /* Clear the top bit of memory */
                if (bus->ramsize) {
@@ -3358,11 +3114,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                                         (u8 *)&zeros, 4);
                }
        } else {
-               regdata = brcmf_sdcard_reg_read(bus->sdiodev,
-                       CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
-               regdata &= (SBTML_RESET | SBTML_REJ_MASK |
-                       (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-               if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
+               if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
                        brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
                        bcmerror = -EBADE;
                        goto fail;
@@ -3377,7 +3129,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                w_sdreg32(bus, 0xFFFFFFFF,
                          offsetof(struct sdpcmd_regs, intstatus), &retries);
 
-               brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
+               ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
 
                /* Allow HT Clock now that the ARM is running. */
                bus->alp_only = false;
@@ -3661,11 +3413,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
        /* Clear any held glomming stuff */
        if (bus->glomd)
                brcmu_pkt_buf_free_skb(bus->glomd);
-
-       if (bus->glom)
-               brcmu_pkt_buf_free_skb(bus->glom);
-
-       bus->glom = bus->glomd = NULL;
+       brcmf_sdbrcm_free_glom(bus);
 
        /* Clear rx control and wake any waiters */
        bus->rxlen = 0;
@@ -3950,269 +3698,6 @@ fail:
        return false;
 }
 
-/* SDIO Pad drive strength to select value mappings */
-struct sdiod_drive_str {
-       u8 strength;    /* Pad Drive Strength in mA */
-       u8 sel;         /* Chip-specific select value */
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 1 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
-       {
-       4, 0x2}, {
-       2, 0x3}, {
-       1, 0x0}, {
-       0, 0x0}
-       };
-
-/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
-       {
-       12, 0x7}, {
-       10, 0x6}, {
-       8, 0x5}, {
-       6, 0x4}, {
-       4, 0x2}, {
-       2, 0x1}, {
-       0, 0x0}
-       };
-
-/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
-static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
-       {
-       32, 0x7}, {
-       26, 0x6}, {
-       22, 0x5}, {
-       16, 0x4}, {
-       12, 0x3}, {
-       8, 0x2}, {
-       4, 0x1}, {
-       0, 0x0}
-       };
-
-#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
-
-static char *brcmf_chipname(uint chipid, char *buf, uint len)
-{
-       const char *fmt;
-
-       fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
-       snprintf(buf, len, fmt, chipid);
-       return buf;
-}
-
-static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
-                                                  u32 drivestrength) {
-       struct sdiod_drive_str *str_tab = NULL;
-       u32 str_mask = 0;
-       u32 str_shift = 0;
-       char chn[8];
-
-       if (!(bus->ci->cccaps & CC_CAP_PMU))
-               return;
-
-       switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) {
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
-               str_mask = 0x30000000;
-               str_shift = 28;
-               break;
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
-               str_mask = 0x00003800;
-               str_shift = 11;
-               break;
-       case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
-               str_mask = 0x00003800;
-               str_shift = 11;
-               break;
-       default:
-               brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
-                         brcmf_chipname(bus->ci->chip, chn, 8),
-                         bus->ci->chiprev, bus->ci->pmurev);
-               break;
-       }
-
-       if (str_tab != NULL) {
-               u32 drivestrength_sel = 0;
-               u32 cc_data_temp;
-               int i;
-
-               for (i = 0; str_tab[i].strength != 0; i++) {
-                       if (drivestrength >= str_tab[i].strength) {
-                               drivestrength_sel = str_tab[i].sel;
-                               break;
-                       }
-               }
-
-               brcmf_sdcard_reg_write(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
-                       4, 1);
-               cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
-               cc_data_temp &= ~str_mask;
-               drivestrength_sel <<= str_shift;
-               cc_data_temp |= drivestrength_sel;
-               brcmf_sdcard_reg_write(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
-                       4, cc_data_temp);
-
-               brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
-                         drivestrength, cc_data_temp);
-       }
-}
-
-static int
-brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev,
-                             struct chip_info *ci, u32 regs)
-{
-       u32 regdata;
-
-       /*
-        * Get CC core rev
-        * Chipid is assume to be at offset 0 from regs arg
-        * For different chiptypes or old sdio hosts w/o chipcommon,
-        * other ways of recognition should be added here.
-        */
-       ci->cccorebase = regs;
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_CC_REG(ci->cccorebase, chipid), 4);
-       ci->chip = regdata & CID_ID_MASK;
-       ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
-
-       brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
-
-       /* Address of cores for new chips should be added here */
-       switch (ci->chip) {
-       case BCM4329_CHIP_ID:
-               ci->buscorebase = BCM4329_CORE_BUS_BASE;
-               ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
-               ci->armcorebase = BCM4329_CORE_ARM_BASE;
-               ci->ramsize = BCM4329_RAMSIZE;
-               break;
-       default:
-               brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
-               return -ENODEV;
-       }
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(ci->cccorebase, sbidhigh), 4);
-       ci->ccrev = SBCOREREV(regdata);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
-       ci->pmurev = regdata & PCAP_REV_MASK;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(ci->buscorebase, sbidhigh), 4);
-       ci->buscorerev = SBCOREREV(regdata);
-       ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
-
-       brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
-                 ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
-
-       /* get chipcommon capabilites */
-       ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
-               CORE_CC_REG(ci->cccorebase, capabilities), 4);
-
-       return 0;
-}
-
-static int
-brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs)
-{
-       struct chip_info *ci;
-       int err;
-       u8 clkval, clkset;
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       /* alloc chip_info_t */
-       ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
-       if (NULL == ci)
-               return -ENOMEM;
-
-       /* bus/core/clk setup for register access */
-       /* Try forcing SDIO core to do ALPAvail request only */
-       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
-       if (err) {
-               brcmf_dbg(ERROR, "error writing for HT off\n");
-               goto fail;
-       }
-
-       /* If register supported, wait for ALPAvail and then force ALP */
-       /* This may take up to 15 milliseconds */
-       clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                       SBSDIO_FUNC1_CHIPCLKCSR, NULL);
-       if ((clkval & ~SBSDIO_AVBITS) == clkset) {
-               SPINWAIT(((clkval =
-                               brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                                               SBSDIO_FUNC1_CHIPCLKCSR,
-                                               NULL)),
-                               !SBSDIO_ALPAV(clkval)),
-                               PMU_MAX_TRANSITION_DLY);
-               if (!SBSDIO_ALPAV(clkval)) {
-                       brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
-                                 clkval);
-                       err = -EBUSY;
-                       goto fail;
-               }
-               clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
-                               SBSDIO_FORCE_ALP;
-               brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_FUNC1_CHIPCLKCSR,
-                               clkset, &err);
-               udelay(65);
-       } else {
-               brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
-                         clkset, clkval);
-               err = -EACCES;
-               goto fail;
-       }
-
-       /* Also, disable the extra SDIO pull-ups */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
-
-       err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs);
-       if (err)
-               goto fail;
-
-       /*
-        * Make sure any on-chip ARM is off (in case strapping is wrong),
-        * or downloaded code was already running.
-        */
-       brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase);
-
-       brcmf_sdcard_reg_write(bus->sdiodev,
-               CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
-       brcmf_sdcard_reg_write(bus->sdiodev,
-               CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
-
-       /* Disable F2 to clear any intermediate frame state on the dongle */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
-               SDIO_FUNC_ENABLE_1, NULL);
-
-       /* WAR: cmd52 backplane read so core HW will drop ALPReq */
-       clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                       0, NULL);
-
-       /* Done with backplane-dependent accesses, can drop clock... */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
-
-       bus->ci = ci;
-       return 0;
-fail:
-       bus->ci = NULL;
-       kfree(ci);
-       return err;
-}
-
 static bool
 brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
 {
@@ -4220,6 +3705,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
        int err = 0;
        int reg_addr;
        u32 reg_val;
+       u8 idx;
 
        bus->alp_only = true;
 
@@ -4234,7 +3720,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
 #endif                         /* BCMDBG */
 
        /*
-        * Force PLL off until brcmf_sdbrcm_chip_attach()
+        * Force PLL off until brcmf_sdio_chip_attach()
         * programs PLL control regs
         */
 
@@ -4252,8 +3738,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
                goto fail;
        }
 
-       if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
-               brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
+       if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) {
+               brcmf_dbg(ERROR, "brcmf_sdio_chip_attach failed!\n");
                goto fail;
        }
 
@@ -4262,11 +3748,10 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
                goto fail;
        }
 
-       brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH);
+       brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
+                                         SDIO_DRIVE_STRENGTH);
 
-       /* Get info on the ARM and SOCRAM cores... */
-       brcmf_sdcard_reg_read(bus->sdiodev,
-                 CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
+       /* Get info on the SOCRAM cores... */
        bus->ramsize = bus->ci->ramsize;
        if (!(bus->ramsize)) {
                brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
@@ -4274,7 +3759,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
        }
 
        /* Set core control so an SDIO reset does a backplane reset */
-       reg_addr = bus->ci->buscorebase +
+       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+       reg_addr = bus->ci->c_inf[idx].base +
                   offsetof(struct sdpcmd_regs, corecontrol);
        reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
        brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
@@ -4364,15 +3850,6 @@ brcmf_sdbrcm_watchdog(unsigned long data)
        }
 }
 
-static void
-brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       kfree(bus->ci);
-       bus->ci = NULL;
-}
-
 static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
@@ -4380,7 +3857,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
        if (bus->ci) {
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
-               brcmf_sdbrcm_chip_detach(bus);
+               brcmf_sdio_chip_detach(&bus->ci);
                if (bus->vars && bus->varsz)
                        kfree(bus->vars);
                bus->vars = NULL;
@@ -4440,6 +3917,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
 
        bus->sdiodev = sdiodev;
        sdiodev->bus = bus;
+       skb_queue_head_init(&bus->glom);
        bus->txbound = BRCMF_TXBOUND;
        bus->rxbound = BRCMF_RXBOUND;
        bus->txminmax = BRCMF_TXMINMAX;
@@ -4521,9 +3999,10 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
                        goto fail;
                }
        }
-       /* Ok, have the per-port tell the stack we're open for business */
-       if (brcmf_net_attach(bus->drvr, 0) != 0) {
-               brcmf_dbg(ERROR, "Net attach failed!!\n");
+
+       /* add interface and open for business */
+       if (brcmf_add_if((struct brcmf_info *)bus->drvr, 0, "wlan%d", NULL)) {
+               brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
                goto fail;
        }
 
@@ -4554,10 +4033,6 @@ struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
 void
 brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
 {
-       /* don't start the wd until fw is loaded */
-       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
-               return;
-
        /* Totally stop the timer */
        if (!wdtick && bus->wd_timer_valid == true) {
                del_timer_sync(&bus->timer);
@@ -4566,6 +4041,10 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
                return;
        }
 
+       /* don't start the wd until fw is loaded */
+       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
+               return;
+
        if (wdtick) {
                if (bus->save_ms != BRCMF_WD_POLL_MS) {
                        if (bus->wd_timer_valid == true)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
new file mode 100644 (file)
index 0000000..f6b1822
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * 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.
+ */
+/* ***** SDIO interface chip backplane handle functions ***** */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mmc/card.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/bcma/bcma.h>
+
+#include <chipcommon.h>
+#include <brcm_hw_ids.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <soc.h>
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "sdio_host.h"
+#include "sdio_chip.h"
+
+/* chip core base & ramsize */
+/* bcm4329 */
+/* SDIO device core, ID 0x829 */
+#define BCM4329_CORE_BUS_BASE          0x18011000
+/* internal memory core, ID 0x80e */
+#define BCM4329_CORE_SOCRAM_BASE       0x18003000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM4329_CORE_ARM_BASE          0x18002000
+#define BCM4329_RAMSIZE                        0x48000
+
+#define        SBCOREREV(sbidh) \
+       ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
+         ((sbidh) & SSB_IDHIGH_RCLO))
+
+/* SOC Interconnect types (aka chip types) */
+#define SOCI_SB                0
+#define SOCI_AI                1
+
+/* EROM CompIdentB */
+#define CIB_REV_MASK           0xff000000
+#define CIB_REV_SHIFT          24
+
+#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+       u8 strength;    /* Pad Drive Strength in mA */
+       u8 sel;         /* Chip-specific select value */
+};
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
+       {
+       4, 0x2}, {
+       2, 0x3}, {
+       1, 0x0}, {
+       0, 0x0}
+       };
+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
+       {
+       12, 0x7}, {
+       10, 0x6}, {
+       8, 0x5}, {
+       6, 0x4}, {
+       4, 0x2}, {
+       2, 0x1}, {
+       0, 0x0}
+       };
+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
+       {
+       32, 0x7}, {
+       26, 0x6}, {
+       22, 0x5}, {
+       16, 0x4}, {
+       12, 0x3}, {
+       8, 0x2}, {
+       4, 0x1}, {
+       0, 0x0}
+       };
+
+u8
+brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+
+       for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
+               if (coreid == ci->c_inf[idx].id)
+                       return idx;
+
+       return BRCMF_MAX_CORENUM;
+}
+
+static u32
+brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
+                     struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
+       return SBCOREREV(regdata);
+}
+
+static u32
+brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
+                     struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
+}
+
+static bool
+brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
+                      struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
+                   SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
+       return (SSB_TMSLOW_CLOCK == regdata);
+}
+
+static bool
+brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
+                      struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+       bool ret;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                       4);
+       ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
+
+       return ret;
+}
+
+static void
+brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
+                         struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       if (regdata & SSB_TMSLOW_RESET)
+               return;
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
+               /*
+                * set target reject and spin until busy is clear
+                * (preserve core-specific bits)
+                */
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                               4, regdata | SSB_TMSLOW_REJECT);
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               udelay(1);
+               SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
+                       SSB_TMSHIGH_BUSY), 100000);
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+               if (regdata & SSB_TMSHIGH_BUSY)
+                       brcmf_dbg(ERROR, "core state still busy\n");
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+               if (regdata & SSB_IDLOW_INITIATOR) {
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
+                               SSB_IMSTATE_REJECT;
+                       brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                               regdata);
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+                       udelay(1);
+                       SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+                               SSB_IMSTATE_BUSY), 100000);
+               }
+
+               /* set reset and reject while enabling the clocks */
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+                       (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+                       SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               udelay(10);
+
+               /* clear the initiator reject bit */
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+               if (regdata & SSB_IDLOW_INITIATOR) {
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+                               ~SSB_IMSTATE_REJECT;
+                       brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                               regdata);
+               }
+       }
+
+       /* leave reset and reject asserted */
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+               (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+       udelay(1);
+}
+
+static void
+brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
+                         struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+       u32 regdata;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /* if core is already in reset, just return */
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                       4);
+       if ((regdata & BCMA_RESET_CTL_RESET) != 0)
+               return;
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, 0);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       udelay(10);
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                              4, BCMA_RESET_CTL_RESET);
+       udelay(1);
+}
+
+static void
+brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /*
+        * Must do the disable sequence first to work for
+        * arbitrary current core state.
+        */
+       brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
+
+       /*
+        * Now do the initialization sequence.
+        * set reset while enabling the clock and
+        * forcing them on throughout the core
+        */
+       brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+                       SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+
+       /* clear any serror */
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+       if (regdata & SSB_TMSHIGH_SERR)
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+       if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                       regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
+
+       /* clear reset and allow it to propagate throughout the core */
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+               SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+
+       /* leave clock enabled */
+       brcmf_sdcard_reg_write(sdiodev,
+                              CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                              4, SSB_TMSLOW_CLOCK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+}
+
+static void
+brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+       u32 regdata;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /* must disable first to work for arbitrary current core state */
+       brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
+
+       /* now do initialization sequence */
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                              4, 0);
+       udelay(1);
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, BCMA_IOCTL_CLK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       udelay(1);
+}
+
+static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
+                                      struct chip_info *ci, u32 regs)
+{
+       u32 regdata;
+
+       /*
+        * Get CC core rev
+        * Chipid is assume to be at offset 0 from regs arg
+        * For different chiptypes or old sdio hosts w/o chipcommon,
+        * other ways of recognition should be added here.
+        */
+       ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
+       ci->c_inf[0].base = regs;
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
+       ci->chip = regdata & CID_ID_MASK;
+       ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+       ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
+
+       brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
+
+       /* Address of cores for new chips should be added here */
+       switch (ci->chip) {
+       case BCM4329_CHIP_ID:
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
+               ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+               ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
+               ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+               ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
+               ci->ramsize = BCM4329_RAMSIZE;
+               break;
+       default:
+               brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
+               return -ENODEV;
+       }
+
+       switch (ci->socitype) {
+       case SOCI_SB:
+               ci->iscoreup = brcmf_sdio_sb_iscoreup;
+               ci->corerev = brcmf_sdio_sb_corerev;
+               ci->coredisable = brcmf_sdio_sb_coredisable;
+               ci->resetcore = brcmf_sdio_sb_resetcore;
+               break;
+       case SOCI_AI:
+               ci->iscoreup = brcmf_sdio_ai_iscoreup;
+               ci->corerev = brcmf_sdio_ai_corerev;
+               ci->coredisable = brcmf_sdio_ai_coredisable;
+               ci->resetcore = brcmf_sdio_ai_resetcore;
+               break;
+       default:
+               brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int
+brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
+{
+       int err = 0;
+       u8 clkval, clkset;
+
+       /* Try forcing SDIO core to do ALPAvail request only */
+       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       if (err) {
+               brcmf_dbg(ERROR, "error writing for HT off\n");
+               return err;
+       }
+
+       /* If register supported, wait for ALPAvail and then force ALP */
+       /* This may take up to 15 milliseconds */
+       clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
+                                      SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+
+       if ((clkval & ~SBSDIO_AVBITS) != clkset) {
+               brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+                         clkset, clkval);
+               return -EACCES;
+       }
+
+       SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
+                               SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+                       !SBSDIO_ALPAV(clkval)),
+                       PMU_MAX_TRANSITION_DLY);
+       if (!SBSDIO_ALPAV(clkval)) {
+               brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
+                         clkval);
+               return -EBUSY;
+       }
+
+       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       udelay(65);
+
+       /* Also, disable the extra SDIO pull-ups */
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+       return 0;
+}
+
+static void
+brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
+                            struct chip_info *ci)
+{
+       /* get chipcommon rev */
+       ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
+
+       /* get chipcommon capabilites */
+       ci->c_inf[0].caps =
+               brcmf_sdcard_reg_read(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
+
+       /* get pmu caps & rev */
+       if (ci->c_inf[0].caps & CC_CAP_PMU) {
+               ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
+               ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
+       }
+
+       ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
+
+       brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+                 ci->c_inf[0].rev, ci->pmurev,
+                 ci->c_inf[1].rev, ci->c_inf[1].id);
+
+       /*
+        * Make sure any on-chip ARM is off (in case strapping is wrong),
+        * or downloaded code was already running.
+        */
+       ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
+}
+
+int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
+                          struct chip_info **ci_ptr, u32 regs)
+{
+       int ret;
+       struct chip_info *ci;
+
+       brcmf_dbg(TRACE, "Enter\n");
+
+       /* alloc chip_info_t */
+       ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
+       if (!ci)
+               return -ENOMEM;
+
+       ret = brcmf_sdio_chip_buscoreprep(sdiodev);
+       if (ret != 0)
+               goto err;
+
+       ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
+       if (ret != 0)
+               goto err;
+
+       brcmf_sdio_chip_buscoresetup(sdiodev, ci);
+
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
+
+       *ci_ptr = ci;
+       return 0;
+
+err:
+       kfree(ci);
+       return ret;
+}
+
+void
+brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
+{
+       brcmf_dbg(TRACE, "Enter\n");
+
+       kfree(*ci_ptr);
+       *ci_ptr = NULL;
+}
+
+static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
+{
+       const char *fmt;
+
+       fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+       snprintf(buf, len, fmt, chipid);
+       return buf;
+}
+
+void
+brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+                                 struct chip_info *ci, u32 drivestrength)
+{
+       struct sdiod_drive_str *str_tab = NULL;
+       u32 str_mask = 0;
+       u32 str_shift = 0;
+       char chn[8];
+
+       if (!(ci->c_inf[0].caps & CC_CAP_PMU))
+               return;
+
+       switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
+               str_mask = 0x30000000;
+               str_shift = 28;
+               break;
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+       case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+       default:
+               brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+                         brcmf_sdio_chip_name(ci->chip, chn, 8),
+                         ci->chiprev, ci->pmurev);
+               break;
+       }
+
+       if (str_tab != NULL) {
+               u32 drivestrength_sel = 0;
+               u32 cc_data_temp;
+               int i;
+
+               for (i = 0; str_tab[i].strength != 0; i++) {
+                       if (drivestrength >= str_tab[i].strength) {
+                               drivestrength_sel = str_tab[i].sel;
+                               break;
+                       }
+               }
+
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
+                       4, 1);
+               cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
+               cc_data_temp &= ~str_mask;
+               drivestrength_sel <<= str_shift;
+               cc_data_temp |= drivestrength_sel;
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
+                       4, cc_data_temp);
+
+               brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
+                         drivestrength, cc_data_temp);
+       }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
new file mode 100644 (file)
index 0000000..ce974d7
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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 _BRCMFMAC_SDIO_CHIP_H_
+#define _BRCMFMAC_SDIO_CHIP_H_
+
+/*
+ * Core reg address translation.
+ * Both macro's returns a 32 bits byte address on the backplane bus.
+ */
+#define CORE_CC_REG(base, field) \
+               (base + offsetof(struct chipcregs, field))
+#define CORE_BUS_REG(base, field) \
+               (base + offsetof(struct sdpcmd_regs, field))
+#define CORE_SB(base, field) \
+               (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
+
+/* SDIO function 1 register CHIPCLKCSR */
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP               0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT                        0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP               0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ           0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ            0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF     0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL               0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL                        0x80
+#define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+#define SBSDIO_CLKAV(regval, alponly) \
+       (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
+#define BRCMF_MAX_CORENUM      6
+
+struct chip_core_info {
+       u16 id;
+       u16 rev;
+       u32 base;
+       u32 wrapbase;
+       u32 caps;
+       u32 cib;
+};
+
+struct chip_info {
+       u32 chip;
+       u32 chiprev;
+       u32 socitype;
+       /* core info */
+       /* always put chipcommon core at 0, bus core at 1 */
+       struct chip_core_info c_inf[BRCMF_MAX_CORENUM];
+       u32 pmurev;
+       u32 pmucaps;
+       u32 ramsize;
+
+       bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+                        u16 coreid);
+       u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+                        u16 coreid);
+       void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid);
+       void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid);
+};
+
+struct sbconfig {
+       u32 PAD[2];
+       u32 sbipsflag;  /* initiator port ocp slave flag */
+       u32 PAD[3];
+       u32 sbtpsflag;  /* target port ocp slave flag */
+       u32 PAD[11];
+       u32 sbtmerrloga;        /* (sonics >= 2.3) */
+       u32 PAD;
+       u32 sbtmerrlog; /* (sonics >= 2.3) */
+       u32 PAD[3];
+       u32 sbadmatch3; /* address match3 */
+       u32 PAD;
+       u32 sbadmatch2; /* address match2 */
+       u32 PAD;
+       u32 sbadmatch1; /* address match1 */
+       u32 PAD[7];
+       u32 sbimstate;  /* initiator agent state */
+       u32 sbintvec;   /* interrupt mask */
+       u32 sbtmstatelow;       /* target state */
+       u32 sbtmstatehigh;      /* target state */
+       u32 sbbwa0;             /* bandwidth allocation table0 */
+       u32 PAD;
+       u32 sbimconfiglow;      /* initiator configuration */
+       u32 sbimconfighigh;     /* initiator configuration */
+       u32 sbadmatch0; /* address match0 */
+       u32 PAD;
+       u32 sbtmconfiglow;      /* target configuration */
+       u32 sbtmconfighigh;     /* target configuration */
+       u32 sbbconfig;  /* broadcast configuration */
+       u32 PAD;
+       u32 sbbstate;   /* broadcast state */
+       u32 PAD[3];
+       u32 sbactcnfg;  /* activate configuration */
+       u32 PAD[3];
+       u32 sbflagst;   /* current sbflags */
+       u32 PAD[3];
+       u32 sbidlow;            /* identification */
+       u32 sbidhigh;   /* identification */
+};
+
+extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
+                                 struct chip_info **ci_ptr, u32 regs);
+extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
+extern void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+                                             struct chip_info *ci,
+                                             u32 drivestrength);
+extern u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
+
+
+#endif         /* _BRCMFMAC_SDIO_CHIP_H_ */
index 5eddabe5228a9e7a3f1f00b737114f98dc34c2f0..cc19a733ac65f16b370a50a755e5495b764d83db 100644 (file)
@@ -1997,7 +1997,7 @@ done:
 }
 
 static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
-                                  struct brcmf_bss_info *bi)
+                                  struct brcmf_bss_info_le *bi)
 {
        struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
        struct ieee80211_channel *notify_channel;
@@ -2049,18 +2049,27 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
                notify_timestamp, notify_capability, notify_interval, notify_ie,
                notify_ielen, notify_signal, GFP_KERNEL);
 
-       if (!bss) {
-               WL_ERR("cfg80211_inform_bss_frame error\n");
-               return -EINVAL;
-       }
+       if (!bss)
+               return -ENOMEM;
+
+       cfg80211_put_bss(bss);
 
        return err;
 }
 
+static struct brcmf_bss_info_le *
+next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
+{
+       if (bss == NULL)
+               return list->bss_info_le;
+       return (struct brcmf_bss_info_le *)((unsigned long)bss +
+                                           le32_to_cpu(bss->length));
+}
+
 static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
 {
        struct brcmf_scan_results *bss_list;
-       struct brcmf_bss_info *bi = NULL;       /* must be initialized */
+       struct brcmf_bss_info_le *bi = NULL;    /* must be initialized */
        s32 err = 0;
        int i;
 
@@ -2072,7 +2081,7 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
        }
        WL_SCAN("scanned AP count (%d)\n", bss_list->count);
        for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
-               bi = next_bss(bss_list, bi);
+               bi = next_bss_le(bss_list, bi);
                err = brcmf_inform_single_bss(cfg_priv, bi);
                if (err)
                        break;
@@ -2085,8 +2094,9 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
 {
        struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
        struct ieee80211_channel *notify_channel;
-       struct brcmf_bss_info *bi = NULL;
+       struct brcmf_bss_info_le *bi = NULL;
        struct ieee80211_supported_band *band;
+       struct cfg80211_bss *bss;
        u8 *buf = NULL;
        s32 err = 0;
        u16 channel;
@@ -2114,7 +2124,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
                goto CleanUp;
        }
 
-       bi = (struct brcmf_bss_info *)(buf + 4);
+       bi = (struct brcmf_bss_info_le *)(buf + 4);
 
        channel = bi->ctl_ch ? bi->ctl_ch :
                                CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
@@ -2140,10 +2150,17 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
        WL_CONN("signal: %d\n", notify_signal);
        WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
 
-       cfg80211_inform_bss(wiphy, notify_channel, bssid,
+       bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
                notify_timestamp, notify_capability, notify_interval,
                notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
 
+       if (!bss) {
+               err = -ENOMEM;
+               goto CleanUp;
+       }
+
+       cfg80211_put_bss(bss);
+
 CleanUp:
 
        kfree(buf);
@@ -2188,7 +2205,7 @@ static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
 
 static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
 {
-       struct brcmf_bss_info *bi;
+       struct brcmf_bss_info_le *bi;
        struct brcmf_ssid *ssid;
        struct brcmf_tlv *tim;
        u16 beacon_interval;
@@ -2211,7 +2228,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
                goto update_bss_info_out;
        }
 
-       bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4);
+       bi = (struct brcmf_bss_info_le *)(cfg_priv->extra_buf + 4);
        err = brcmf_inform_single_bss(cfg_priv, bi);
        if (err)
                goto update_bss_info_out;
index 62dc46144ede5935de0a8a8d8cf16bdba8b0f003..a613b49cb13f543e66363f5749ac09473a64b4b5 100644 (file)
@@ -352,15 +352,6 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
        return &cfg->conn_info;
 }
 
-static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list,
-                                          struct brcmf_bss_info *bss)
-{
-       return bss = bss ?
-               (struct brcmf_bss_info *)((unsigned long)bss +
-                                      le32_to_cpu(bss->length)) :
-               list->bss_info;
-}
-
 extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
                                                        struct device *busdev,
                                                        void *data);
index 106a7424a7cd4d60ee098d691db77e21067ba77c..b51d1e421e244ca0e92b2326d20c2c6b13fca5dd 100644 (file)
 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
 #define SI_PCIE_DMA_H32                0x80000000
 
-/* core codes */
-#define        NODEV_CORE_ID           0x700   /* Invalid coreid */
-#define        CC_CORE_ID              0x800   /* chipcommon core */
-#define        ILINE20_CORE_ID         0x801   /* iline20 core */
-#define        SRAM_CORE_ID            0x802   /* sram core */
-#define        SDRAM_CORE_ID           0x803   /* sdram core */
-#define        PCI_CORE_ID             0x804   /* pci core */
-#define        MIPS_CORE_ID            0x805   /* mips core */
-#define        ENET_CORE_ID            0x806   /* enet mac core */
-#define        CODEC_CORE_ID           0x807   /* v90 codec core */
-#define        USB_CORE_ID             0x808   /* usb 1.1 host/device core */
-#define        ADSL_CORE_ID            0x809   /* ADSL core */
-#define        ILINE100_CORE_ID        0x80a   /* iline100 core */
-#define        IPSEC_CORE_ID           0x80b   /* ipsec core */
-#define        UTOPIA_CORE_ID          0x80c   /* utopia core */
-#define        PCMCIA_CORE_ID          0x80d   /* pcmcia core */
-#define        SOCRAM_CORE_ID          0x80e   /* internal memory core */
-#define        MEMC_CORE_ID            0x80f   /* memc sdram core */
-#define        OFDM_CORE_ID            0x810   /* OFDM phy core */
-#define        EXTIF_CORE_ID           0x811   /* external interface core */
-#define        D11_CORE_ID             0x812   /* 802.11 MAC core */
-#define        APHY_CORE_ID            0x813   /* 802.11a phy core */
-#define        BPHY_CORE_ID            0x814   /* 802.11b phy core */
-#define        GPHY_CORE_ID            0x815   /* 802.11g phy core */
-#define        MIPS33_CORE_ID          0x816   /* mips3302 core */
-#define        USB11H_CORE_ID          0x817   /* usb 1.1 host core */
-#define        USB11D_CORE_ID          0x818   /* usb 1.1 device core */
-#define        USB20H_CORE_ID          0x819   /* usb 2.0 host core */
-#define        USB20D_CORE_ID          0x81a   /* usb 2.0 device core */
-#define        SDIOH_CORE_ID           0x81b   /* sdio host core */
-#define        ROBO_CORE_ID            0x81c   /* roboswitch core */
-#define        ATA100_CORE_ID          0x81d   /* parallel ATA core */
-#define        SATAXOR_CORE_ID         0x81e   /* serial ATA & XOR DMA core */
-#define        GIGETH_CORE_ID          0x81f   /* gigabit ethernet core */
-#define        PCIE_CORE_ID            0x820   /* pci express core */
-#define        NPHY_CORE_ID            0x821   /* 802.11n 2x2 phy core */
-#define        SRAMC_CORE_ID           0x822   /* SRAM controller core */
-#define        MINIMAC_CORE_ID         0x823   /* MINI MAC/phy core */
-#define        ARM11_CORE_ID           0x824   /* ARM 1176 core */
-#define        ARM7S_CORE_ID           0x825   /* ARM7tdmi-s core */
-#define        LPPHY_CORE_ID           0x826   /* 802.11a/b/g phy core */
-#define        PMU_CORE_ID             0x827   /* PMU core */
-#define        SSNPHY_CORE_ID          0x828   /* 802.11n single-stream phy core */
-#define        SDIOD_CORE_ID           0x829   /* SDIO device core */
-#define        ARMCM3_CORE_ID          0x82a   /* ARM Cortex M3 core */
-#define        HTPHY_CORE_ID           0x82b   /* 802.11n 4x4 phy core */
-#define        MIPS74K_CORE_ID         0x82c   /* mips 74k core */
-#define        GMAC_CORE_ID            0x82d   /* Gigabit MAC core */
-#define        DMEMC_CORE_ID           0x82e   /* DDR1/2 memory controller core */
-#define        PCIERC_CORE_ID          0x82f   /* PCIE Root Complex core */
-#define        OCP_CORE_ID             0x830   /* OCP2OCP bridge core */
-#define        SC_CORE_ID              0x831   /* shared common core */
-#define        AHB_CORE_ID             0x832   /* OCP2AHB bridge core */
-#define        SPIH_CORE_ID            0x833   /* SPI host core */
-#define        I2S_CORE_ID             0x834   /* I2S core */
-#define        DMEMS_CORE_ID           0x835   /* SDR/DDR1 memory controller core */
-#define        DEF_SHIM_COMP           0x837   /* SHIM component in ubus/6362 */
-#define OOB_ROUTER_CORE_ID     0x367   /* OOB router core ID */
-#define        DEF_AI_COMP             0xfff   /* Default component, in ai chips it
-                                        * maps all unused address ranges
-                                        */
-
 /* chipcommon being the first core: */
 #define        SI_CC_IDX               0
 
 /* SOC Interconnect types (aka chip types) */
 #define        SOCI_AI                 1
 
-/* Common core control flags */
-#define        SICF_BIST_EN            0x8000
-#define        SICF_PME_EN             0x4000
-#define        SICF_CORE_BITS          0x3ffc
-#define        SICF_FGC                0x0002
-#define        SICF_CLOCK_EN           0x0001
-
-/* Common core status flags */
-#define        SISF_BIST_DONE          0x8000
-#define        SISF_BIST_ERROR         0x4000
-#define        SISF_GATED_CLK          0x2000
-#define        SISF_DMA64              0x1000
-#define        SISF_CORE_BITS          0x0fff
-
 /* A register that is common to all cores to
  * communicate w/PMU regarding clock control.
  */
index 7f27dbdb6b60943ae058d5f758330032280f237e..43f7a724dda812f1a6c27ba21e3f0184e70b30ce 100644 (file)
@@ -649,7 +649,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                len = roundup(len, 4);
                ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
 
-               dma_len += (u16) brcmu_pkttotlen(p);
+               dma_len += (u16) p->len;
 
                BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
                        " seg_cnt %d null delim %d\n",
@@ -741,9 +741,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                if (p) {
                        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
                            ((u8) (p->priority) == tid)) {
-
-                               plen = brcmu_pkttotlen(p) +
-                                      AMPDU_MAX_MPDU_OVERHEAD;
+                               plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
                                plen = max(scb_ampdu->min_len, plen);
 
                                if ((plen + ampdu_len) > max_ampdu_bytes) {
index 89ad1b7dab8fdd69a60822b80585cef29814af44..55e9f45fce22ec82315bd7559e346d8b02615f33 100644 (file)
@@ -1153,121 +1153,6 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                              &txpwr);
 }
 
-#ifdef POWER_DBG
-static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
-{
-       int i;
-       char buf[80];
-       char fraction[4][4] = { "   ", ".25", ".5 ", ".75" };
-
-       sprintf(buf, "CCK                ");
-       for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz OFDM SISO   ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz OFDM CDD    ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz OFDM SISO   ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_40_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz OFDM CDD    ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_40_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 SISO ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 CDD  ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 STBC ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_stbc[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS8-15 SDM ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_mimo[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 SISO ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 CDD  ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 STBC ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_stbc[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS8-15 SDM ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_mimo[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       }
-       printk(KERN_DEBUG "%s\n", buf);
-
-       printk(KERN_DEBUG "MCS32               %2d%s\n",
-              txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR,
-              fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]);
-}
-#endif                         /* POWER_DBG */
-
 void
 brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                       struct txpwr_limits *txpwr)
@@ -1478,9 +1363,6 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                        txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
        }
 
-#ifdef POWER_DBG
-       wlc_phy_txpower_limits_dump(txpwr);
-#endif
        return;
 }
 
index 6ebec8f42846977439c07844cba9a6f7e429801c..e286fb4d48135eab824546b420be9439c232d5a9 100644 (file)
@@ -14,7 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/slab.h>
-#include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 
@@ -22,6 +21,7 @@
 #include <aiutils.h>
 #include "types.h"
 #include "dma.h"
+#include "soc.h"
 
 /*
  * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
@@ -901,7 +901,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
 
 /*
  * !! rx entry routine
- * returns a pointer to the next frame received, or NULL if there are no more
+ * returns the number packages in the next frame, or 0 if there are no more
  *   if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is
  *   supported with pkts chain
  *   otherwise, it's treated as giant pkt and will be tossed.
@@ -909,38 +909,40 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
  *   buffer data. After it reaches the max size of buffer, the data continues
  *   in next DMA descriptor buffer WITHOUT DMA header
  */
-struct sk_buff *dma_rx(struct dma_pub *pub)
+int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
 {
        struct dma_info *di = (struct dma_info *)pub;
-       struct sk_buff *p, *head, *tail;
+       struct sk_buff_head dma_frames;
+       struct sk_buff *p, *next;
        uint len;
        uint pkt_len;
        int resid = 0;
+       int pktcnt = 1;
 
+       skb_queue_head_init(&dma_frames);
  next_frame:
-       head = _dma_getnextrxp(di, false);
-       if (head == NULL)
-               return NULL;
+       p = _dma_getnextrxp(di, false);
+       if (p == NULL)
+               return 0;
 
-       len = le16_to_cpu(*(__le16 *) (head->data));
+       len = le16_to_cpu(*(__le16 *) (p->data));
        DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
-       dma_spin_for_len(len, head);
+       dma_spin_for_len(len, p);
 
        /* set actual length */
        pkt_len = min((di->rxoffset + len), di->rxbufsize);
-       __skb_trim(head, pkt_len);
+       __skb_trim(p, pkt_len);
+       skb_queue_tail(&dma_frames, p);
        resid = len - (di->rxbufsize - di->rxoffset);
 
        /* check for single or multi-buffer rx */
        if (resid > 0) {
-               tail = head;
                while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
-                       tail->next = p;
                        pkt_len = min_t(uint, resid, di->rxbufsize);
                        __skb_trim(p, pkt_len);
-
-                       tail = p;
+                       skb_queue_tail(&dma_frames, p);
                        resid -= di->rxbufsize;
+                       pktcnt++;
                }
 
 #ifdef BCMDBG
@@ -959,13 +961,18 @@ struct sk_buff *dma_rx(struct dma_pub *pub)
                if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
                        DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n",
                                   di->name, len));
-                       brcmu_pkt_buf_free_skb(head);
+                       skb_queue_walk_safe(&dma_frames, p, next) {
+                               skb_unlink(p, &dma_frames);
+                               brcmu_pkt_buf_free_skb(p);
+                       }
                        di->dma.rxgiants++;
+                       pktcnt = 1;
                        goto next_frame;
                }
        }
 
-       return head;
+       skb_queue_splice_tail(&dma_frames, skb_list);
+       return pktcnt;
 }
 
 static bool dma64_rxidle(struct dma_info *di)
index ebc5bc546f3b8bdd1c42e493554c9ad2c4d6d6e5..d317c7c12f9181738e64681dfb60ba5292e94fa0 100644 (file)
@@ -18,6 +18,7 @@
 #define        _BRCM_DMA_H_
 
 #include <linux/delay.h>
+#include <linux/skbuff.h>
 #include "types.h"             /* forward structure declarations */
 
 /* map/unmap direction */
@@ -80,7 +81,7 @@ extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
                            uint nrxpost, uint rxoffset, uint *msg_level);
 
 void dma_rxinit(struct dma_pub *pub);
-struct sk_buff *dma_rx(struct dma_pub *pub);
+int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list);
 bool dma_rxfill(struct dma_pub *pub);
 bool dma_rxreset(struct dma_pub *pub);
 bool dma_txreset(struct dma_pub *pub);
index 0d8a9cdf897afe3569ea412256a17cf301ffb8b4..8457e969eb4fe418178362ac5f0556772f8b5d2b 100644 (file)
@@ -216,8 +216,7 @@ static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {
        .ht_cap = {
                   /* from include/linux/ieee80211.h */
                   .cap = IEEE80211_HT_CAP_GRN_FLD |
-                  IEEE80211_HT_CAP_SGI_20 |
-                  IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+                         IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -238,8 +237,7 @@ static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {
                        BRCMS_LEGACY_5G_RATE_OFFSET,
        .ht_cap = {
                   .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
-                         IEEE80211_HT_CAP_SGI_40 |
-                         IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+                         IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -287,6 +285,7 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
 {
        struct brcms_info *wl = hw->priv;
        bool blocked;
+       int err;
 
        ieee80211_wake_queues(hw);
        spin_lock_bh(&wl->lock);
@@ -295,57 +294,69 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (!blocked)
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
 
-       return 0;
+       spin_lock_bh(&wl->lock);
+       /* avoid acknowledging frames before a non-monitor device is added */
+       wl->mute_tx = true;
+
+       if (!wl->pub->up)
+               err = brcms_up(wl);
+       else
+               err = -ENODEV;
+       spin_unlock_bh(&wl->lock);
+
+       if (err != 0)
+               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
+                         err);
+       return err;
 }
 
 static void brcms_ops_stop(struct ieee80211_hw *hw)
 {
+       struct brcms_info *wl = hw->priv;
+       int status;
+
        ieee80211_stop_queues(hw);
+
+       if (wl->wlc == NULL)
+               return;
+
+       spin_lock_bh(&wl->lock);
+       status = brcms_c_chipmatch(wl->wlc->hw->vendorid,
+                                  wl->wlc->hw->deviceid);
+       spin_unlock_bh(&wl->lock);
+       if (!status) {
+               wiphy_err(wl->wiphy,
+                         "wl: brcms_ops_stop: chipmatch failed\n");
+               return;
+       }
+
+       /* put driver in down state */
+       spin_lock_bh(&wl->lock);
+       brcms_down(wl);
+       spin_unlock_bh(&wl->lock);
 }
 
 static int
 brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-       int err;
+       struct brcms_info *wl = hw->priv;
 
        /* Just STA for now */
-       if (vif->type != NL80211_IFTYPE_AP &&
-           vif->type != NL80211_IFTYPE_MESH_POINT &&
-           vif->type != NL80211_IFTYPE_STATION &&
-           vif->type != NL80211_IFTYPE_WDS &&
-           vif->type != NL80211_IFTYPE_ADHOC) {
+       if (vif->type != NL80211_IFTYPE_STATION) {
                wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
                          " STA for now\n", __func__, vif->type);
                return -EOPNOTSUPP;
        }
 
-       wl = hw->priv;
-       spin_lock_bh(&wl->lock);
-       if (!wl->pub->up)
-               err = brcms_up(wl);
-       else
-               err = -ENODEV;
-       spin_unlock_bh(&wl->lock);
-
-       if (err != 0)
-               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
-                         err);
+       wl->mute_tx = false;
+       brcms_c_mute(wl->wlc, false);
 
-       return err;
+       return 0;
 }
 
 static void
 brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-
-       wl = hw->priv;
-
-       /* put driver in down state */
-       spin_lock_bh(&wl->lock);
-       brcms_down(wl);
-       spin_unlock_bh(&wl->lock);
 }
 
 static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
@@ -609,13 +620,6 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        wl->pub->global_ampdu->scb = scb;
        wl->pub->global_ampdu->max_pdu = 16;
 
-       sta->ht_cap.ht_supported = true;
-       sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
-       sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
-           IEEE80211_HT_CAP_SGI_20 |
-           IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
-
        /*
         * minstrel_ht initiates addBA on our behalf by calling
         * ieee80211_start_tx_ba_session()
@@ -877,37 +881,18 @@ static void brcms_free(struct brcms_info *wl)
 }
 
 /*
-* called from both kernel as from this kernel module.
+* called from both kernel as from this kernel module (error flow on attach)
 * precondition: perimeter lock is not acquired.
 */
 static void brcms_remove(struct pci_dev *pdev)
 {
-       struct brcms_info *wl;
-       struct ieee80211_hw *hw;
-       int status;
-
-       hw = pci_get_drvdata(pdev);
-       wl = hw->priv;
-       if (!wl) {
-               pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
-               return;
-       }
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct brcms_info *wl = hw->priv;
 
-       spin_lock_bh(&wl->lock);
-       status = brcms_c_chipmatch(pdev->vendor, pdev->device);
-       spin_unlock_bh(&wl->lock);
-       if (!status) {
-               wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
-                                    "failed\n");
-               return;
-       }
        if (wl->wlc) {
                wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
                ieee80211_unregister_hw(hw);
-               spin_lock_bh(&wl->lock);
-               brcms_down(wl);
-               spin_unlock_bh(&wl->lock);
        }
        pci_disable_device(pdev);
 
@@ -1081,9 +1066,6 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
 
        wl->pub->ieee_hw = hw;
 
-       /* disable mpc */
-       brcms_c_set_radio_mpc(wl->wlc, false);
-
        /* register our interrupt handler */
        if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
                wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
@@ -1319,8 +1301,7 @@ void brcms_init(struct brcms_info *wl)
 {
        BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
        brcms_reset(wl);
-
-       brcms_c_init(wl->wlc);
+       brcms_c_init(wl->wlc, wl->mute_tx);
 }
 
 /*
@@ -1337,6 +1318,14 @@ uint brcms_reset(struct brcms_info *wl)
        return 0;
 }
 
+void brcms_fatal_error(struct brcms_info *wl)
+{
+       wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+                 wl->wlc->pub->unit);
+       brcms_reset(wl);
+       ieee80211_restart_hw(wl->pub->ieee_hw);
+}
+
 /*
  * These are interrupt on/off entry points. Disable interrupts
  * during interrupt state transition.
index 177f0e44e4b60c12c4384f893c80067e592cbd3c..6242f188b717d4e6c7a1cf3d7f30043a00fc1c29 100644 (file)
@@ -80,6 +80,7 @@ struct brcms_info {
        struct brcms_firmware fw;
        struct wiphy *wiphy;
        struct brcms_ucode ucode;
+       bool mute_tx;
 };
 
 /* misc callbacks */
@@ -104,5 +105,6 @@ extern bool brcms_del_timer(struct brcms_timer *timer);
 extern void brcms_msleep(struct brcms_info *wl, uint ms);
 extern void brcms_dpc(unsigned long data);
 extern void brcms_timer(struct brcms_timer *t);
+extern void brcms_fatal_error(struct brcms_info *wl);
 
 #endif                         /* _BRCM_MAC80211_IF_H_ */
index 510e9bb5228795c2d453d9eb641cc7084aa63b2b..36e3e06383000fc665a985bac23667e901dccf17 100644 (file)
 #include "mac80211_if.h"
 #include "ucode_loader.h"
 #include "main.h"
+#include "soc.h"
 
 /*
  * Indication for txflowcontrol that all priority bits in
  * TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
  */
-#define ALLPRIO                -1
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN       ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+#define ALLPRIO                                -1
 
 /* watchdog timer, in unit of ms */
-#define        TIMER_INTERVAL_WATCHDOG 1000
+#define TIMER_INTERVAL_WATCHDOG                1000
 /* radio monitor timer, in unit of ms */
-#define        TIMER_INTERVAL_RADIOCHK 800
-
-/* Max MPC timeout, in unit of watchdog */
-#ifndef BRCMS_MPC_MAX_DELAYCNT
-#define        BRCMS_MPC_MAX_DELAYCNT  10
-#endif
-
-/* Min MPC timeout, in unit of watchdog */
-#define        BRCMS_MPC_MIN_DELAYCNT  1
-#define        BRCMS_MPC_THRESHOLD     3       /* MPC count threshold level */
+#define TIMER_INTERVAL_RADIOCHK                800
 
 /* beacon interval, in unit of 1024TU */
-#define        BEACON_INTERVAL_DEFAULT 100
-/* DTIM interval, in unit of beacon interval */
-#define        DTIM_INTERVAL_DEFAULT   3
-
-/* Scale down delays to accommodate QT slow speed */
-/* beacon interval, in unit of 1024TU */
-#define        BEACON_INTERVAL_DEF_QT  20
-/* DTIM interval, in unit of beacon interval */
-#define        DTIM_INTERVAL_DEF_QT    1
-
-#define        TBTT_ALIGN_LEEWAY_US    100     /* min leeway before first TBTT in us */
+#define BEACON_INTERVAL_DEFAULT                100
 
 /* n-mode support capability */
 /* 2x2 includes both 1x1 & 2x2 devices
 #define WL_11N_3x3                     3
 #define WL_11N_4x4                     4
 
-/* define 11n feature disable flags */
-#define WLFEATURE_DISABLE_11N          0x00000001
-#define WLFEATURE_DISABLE_11N_STBC_TX  0x00000002
-#define WLFEATURE_DISABLE_11N_STBC_RX  0x00000004
-#define WLFEATURE_DISABLE_11N_SGI_TX   0x00000008
-#define WLFEATURE_DISABLE_11N_SGI_RX   0x00000010
-#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
-#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
-#define WLFEATURE_DISABLE_11N_GF       0x00000080
-
-#define EDCF_ACI_MASK                0x60
-#define EDCF_ACI_SHIFT               5
-#define EDCF_ECWMIN_MASK             0x0f
-#define EDCF_ECWMAX_SHIFT            4
-#define EDCF_AIFSN_MASK              0x0f
-#define EDCF_AIFSN_MAX               15
-#define EDCF_ECWMAX_MASK             0xf0
-
-#define EDCF_AC_BE_TXOP_STA          0x0000
-#define EDCF_AC_BK_TXOP_STA          0x0000
-#define EDCF_AC_VO_ACI_STA           0x62
-#define EDCF_AC_VO_ECW_STA           0x32
-#define EDCF_AC_VI_ACI_STA           0x42
-#define EDCF_AC_VI_ECW_STA           0x43
-#define EDCF_AC_BK_ECW_STA           0xA4
-#define EDCF_AC_VI_TXOP_STA          0x005e
-#define EDCF_AC_VO_TXOP_STA          0x002f
-#define EDCF_AC_BE_ACI_STA           0x03
-#define EDCF_AC_BE_ECW_STA           0xA4
-#define EDCF_AC_BK_ACI_STA           0x27
-#define EDCF_AC_VO_TXOP_AP           0x002f
-
-#define EDCF_TXOP2USEC(txop)         ((txop) << 5)
-#define EDCF_ECW2CW(exp)             ((1 << (exp)) - 1)
-
-#define APHY_SYMBOL_TIME       4
-#define APHY_PREAMBLE_TIME     16
-#define APHY_SIGNAL_TIME       4
-#define APHY_SIFS_TIME         16
-#define APHY_SERVICE_NBITS     16
-#define APHY_TAIL_NBITS                6
-#define BPHY_SIFS_TIME         10
-#define BPHY_PLCP_SHORT_TIME   96
-
-#define PREN_PREAMBLE          24
-#define PREN_MM_EXT            12
-#define PREN_PREAMBLE_EXT      4
+#define EDCF_ACI_MASK                  0x60
+#define EDCF_ACI_SHIFT                 5
+#define EDCF_ECWMIN_MASK               0x0f
+#define EDCF_ECWMAX_SHIFT              4
+#define EDCF_AIFSN_MASK                        0x0f
+#define EDCF_AIFSN_MAX                 15
+#define EDCF_ECWMAX_MASK               0xf0
+
+#define EDCF_AC_BE_TXOP_STA            0x0000
+#define EDCF_AC_BK_TXOP_STA            0x0000
+#define EDCF_AC_VO_ACI_STA             0x62
+#define EDCF_AC_VO_ECW_STA             0x32
+#define EDCF_AC_VI_ACI_STA             0x42
+#define EDCF_AC_VI_ECW_STA             0x43
+#define EDCF_AC_BK_ECW_STA             0xA4
+#define EDCF_AC_VI_TXOP_STA            0x005e
+#define EDCF_AC_VO_TXOP_STA            0x002f
+#define EDCF_AC_BE_ACI_STA             0x03
+#define EDCF_AC_BE_ECW_STA             0xA4
+#define EDCF_AC_BK_ACI_STA             0x27
+#define EDCF_AC_VO_TXOP_AP             0x002f
+
+#define EDCF_TXOP2USEC(txop)           ((txop) << 5)
+#define EDCF_ECW2CW(exp)               ((1 << (exp)) - 1)
+
+#define APHY_SYMBOL_TIME               4
+#define APHY_PREAMBLE_TIME             16
+#define APHY_SIGNAL_TIME               4
+#define APHY_SIFS_TIME                 16
+#define APHY_SERVICE_NBITS             16
+#define APHY_TAIL_NBITS                        6
+#define BPHY_SIFS_TIME                 10
+#define BPHY_PLCP_SHORT_TIME           96
+
+#define PREN_PREAMBLE                  24
+#define PREN_MM_EXT                    12
+#define PREN_PREAMBLE_EXT              4
 
 #define DOT11_MAC_HDR_LEN              24
-#define        DOT11_ACK_LEN           10
-#define DOT11_BA_LEN           4
+#define DOT11_ACK_LEN                  10
+#define DOT11_BA_LEN                   4
 #define DOT11_OFDM_SIGNAL_EXTENSION    6
 #define DOT11_MIN_FRAG_LEN             256
-#define        DOT11_RTS_LEN           16
-#define        DOT11_CTS_LEN           10
+#define DOT11_RTS_LEN                  16
+#define DOT11_CTS_LEN                  10
 #define DOT11_BA_BITMAP_LEN            128
 #define DOT11_MIN_BEACON_PERIOD                1
 #define DOT11_MAX_BEACON_PERIOD                0xFFFF
-#define        DOT11_MAXNUMFRAGS       16
+#define DOT11_MAXNUMFRAGS              16
 #define DOT11_MAX_FRAG_LEN             2346
 
-#define BPHY_PLCP_TIME         192
-#define RIFS_11N_TIME          2
-
-#define WME_VER                        1
-#define WME_SUBTYPE_PARAM_IE   1
-#define WME_TYPE               2
-#define WME_OUI                        "\x00\x50\xf2"
-
-#define AC_BE                  0
-#define AC_BK                  1
-#define AC_VI                  2
-#define AC_VO                  3
+#define BPHY_PLCP_TIME                 192
+#define RIFS_11N_TIME                  2
 
-#define        BCN_TMPL_LEN            512     /* length of the BCN template area */
+/* length of the BCN template area */
+#define BCN_TMPL_LEN                   512
 
 /* brcms_bss_info flag bit values */
-#define BRCMS_BSS_HT           0x0020  /* BSS is HT (MIMO) capable */
+#define BRCMS_BSS_HT                   0x0020  /* BSS is HT (MIMO) capable */
 
-/* Flags used in brcms_c_txq_info.stopped */
-/* per prio flow control bits */
-#define TXQ_STOP_FOR_PRIOFC_MASK       0x000000FF
-/* stop txq enqueue for packet drain */
-#define TXQ_STOP_FOR_PKT_DRAIN         0x00000100
-/* stop txq enqueue for ampdu flow control */
-#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL  0x00000200
-
-#define        BRCMS_HWRXOFF           38      /* chip rx buffer offset */
-
-/* Find basic rate for a given rate */
-static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
-{
-       if (is_mcs_rate(rspec))
-               return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
-                      .leg_ofdm];
-       return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
-}
-
-static u16 frametype(u32 rspec, u8 mimoframe)
-{
-       if (is_mcs_rate(rspec))
-               return mimoframe;
-       return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
-}
+/* chip rx buffer offset */
+#define BRCMS_HWRXOFF                  38
 
 /* rfdisable delay timer 500 ms, runs of ALP clock */
-#define RFDISABLE_DEFAULT      10000000
+#define RFDISABLE_DEFAULT              10000000
 
 #define BRCMS_TEMPSENSE_PERIOD         10      /* 10 second timeout */
 
@@ -194,87 +129,83 @@ static u16 frametype(u32 rspec, u8 mimoframe)
  * These constants are used ONLY by wlc_prio2prec_map.  Do not use them
  * elsewhere.
  */
-#define        _BRCMS_PREC_NONE                0       /* None = - */
-#define        _BRCMS_PREC_BK          2       /* BK - Background */
-#define        _BRCMS_PREC_BE          4       /* BE - Best-effort */
-#define        _BRCMS_PREC_EE          6       /* EE - Excellent-effort */
-#define        _BRCMS_PREC_CL          8       /* CL - Controlled Load */
-#define        _BRCMS_PREC_VI          10      /* Vi - Video */
-#define        _BRCMS_PREC_VO          12      /* Vo - Voice */
-#define        _BRCMS_PREC_NC          14      /* NC - Network Control */
-
-/* The BSS is generating beacons in HW */
-#define BRCMS_BSSCFG_HW_BCN    0x20
-
-#define        SYNTHPU_DLY_APHY_US     3700    /* a phy synthpu_dly time in us */
-#define        SYNTHPU_DLY_BPHY_US     1050    /* b/g phy synthpu_dly time in us */
-#define        SYNTHPU_DLY_NPHY_US     2048    /* n phy REV3 synthpu_dly time in us */
-#define        SYNTHPU_DLY_LPPHY_US    300     /* lpphy synthpu_dly time in us */
-
-#define        SYNTHPU_DLY_PHY_US_QT   100     /* QT synthpu_dly time in us */
-
-#define        ANTCNT                  10      /* vanilla M_MAX_ANTCNT value */
+#define _BRCMS_PREC_NONE               0       /* None = - */
+#define _BRCMS_PREC_BK                 2       /* BK - Background */
+#define _BRCMS_PREC_BE                 4       /* BE - Best-effort */
+#define _BRCMS_PREC_EE                 6       /* EE - Excellent-effort */
+#define _BRCMS_PREC_CL                 8       /* CL - Controlled Load */
+#define _BRCMS_PREC_VI                 10      /* Vi - Video */
+#define _BRCMS_PREC_VO                 12      /* Vo - Voice */
+#define _BRCMS_PREC_NC                 14      /* NC - Network Control */
+
+/* synthpu_dly times in us */
+#define SYNTHPU_DLY_APHY_US            3700
+#define SYNTHPU_DLY_BPHY_US            1050
+#define SYNTHPU_DLY_NPHY_US            2048
+#define SYNTHPU_DLY_LPPHY_US           300
+
+#define ANTCNT                         10      /* vanilla M_MAX_ANTCNT val */
 
 /* Per-AC retry limit register definitions; uses defs.h bitfield macros */
-#define EDCF_SHORT_S            0
-#define EDCF_SFB_S              4
-#define EDCF_LONG_S             8
-#define EDCF_LFB_S              12
-#define EDCF_SHORT_M            BITFIELD_MASK(4)
-#define EDCF_SFB_M              BITFIELD_MASK(4)
-#define EDCF_LONG_M             BITFIELD_MASK(4)
-#define EDCF_LFB_M              BITFIELD_MASK(4)
+#define EDCF_SHORT_S                   0
+#define EDCF_SFB_S                     4
+#define EDCF_LONG_S                    8
+#define EDCF_LFB_S                     12
+#define EDCF_SHORT_M                   BITFIELD_MASK(4)
+#define EDCF_SFB_M                     BITFIELD_MASK(4)
+#define EDCF_LONG_M                    BITFIELD_MASK(4)
+#define EDCF_LFB_M                     BITFIELD_MASK(4)
 
-#define        RETRY_SHORT_DEF                 7       /* Default Short retry Limit */
-#define        RETRY_SHORT_MAX                 255     /* Maximum Short retry Limit */
-#define        RETRY_LONG_DEF                  4       /* Default Long retry count */
-#define        RETRY_SHORT_FB                  3 /* Short count for fallback rate */
-#define        RETRY_LONG_FB                   2 /* Long count for fallback rate */
+#define RETRY_SHORT_DEF                        7       /* Default Short retry Limit */
+#define RETRY_SHORT_MAX                        255     /* Maximum Short retry Limit */
+#define RETRY_LONG_DEF                 4       /* Default Long retry count */
+#define RETRY_SHORT_FB                 3       /* Short count for fb rate */
+#define RETRY_LONG_FB                  2       /* Long count for fb rate */
 
-#define        APHY_CWMIN              15
-#define PHY_CWMAX              1023
+#define APHY_CWMIN                     15
+#define PHY_CWMAX                      1023
 
-#define EDCF_AIFSN_MIN               1
+#define EDCF_AIFSN_MIN                 1
 
-#define FRAGNUM_MASK           0xF
+#define FRAGNUM_MASK                   0xF
 
-#define APHY_SLOT_TIME         9
-#define BPHY_SLOT_TIME         20
+#define APHY_SLOT_TIME                 9
+#define BPHY_SLOT_TIME                 20
 
-#define        WL_SPURAVOID_OFF        0
-#define        WL_SPURAVOID_ON1        1
-#define        WL_SPURAVOID_ON2        2
+#define WL_SPURAVOID_OFF               0
+#define WL_SPURAVOID_ON1               1
+#define WL_SPURAVOID_ON2               2
 
 /* invalid core flags, use the saved coreflags */
-#define BRCMS_USE_COREFLAGS    0xffffffff
+#define BRCMS_USE_COREFLAGS            0xffffffff
 
 /* values for PLCPHdr_override */
-#define BRCMS_PLCP_AUTO        -1
-#define BRCMS_PLCP_SHORT       0
-#define BRCMS_PLCP_LONG        1
+#define BRCMS_PLCP_AUTO                        -1
+#define BRCMS_PLCP_SHORT               0
+#define BRCMS_PLCP_LONG                        1
 
 /* values for g_protection_override and n_protection_override */
 #define BRCMS_PROTECTION_AUTO          -1
 #define BRCMS_PROTECTION_OFF           0
 #define BRCMS_PROTECTION_ON            1
 #define BRCMS_PROTECTION_MMHDR_ONLY    2
-#define BRCMS_PROTECTION_CTS_ONLY              3
+#define BRCMS_PROTECTION_CTS_ONLY      3
 
 /* values for g_protection_control and n_protection_control */
-#define BRCMS_PROTECTION_CTL_OFF               0
+#define BRCMS_PROTECTION_CTL_OFF       0
 #define BRCMS_PROTECTION_CTL_LOCAL     1
 #define BRCMS_PROTECTION_CTL_OVERLAP   2
 
 /* values for n_protection */
 #define BRCMS_N_PROTECTION_OFF         0
 #define BRCMS_N_PROTECTION_OPTIONAL    1
-#define BRCMS_N_PROTECTION_20IN40              2
+#define BRCMS_N_PROTECTION_20IN40      2
 #define BRCMS_N_PROTECTION_MIXEDMODE   3
 
 /* values for band specific 40MHz capabilities */
-#define BRCMS_N_BW_20ALL                       0
-#define BRCMS_N_BW_40ALL                       1
-#define BRCMS_N_BW_20IN2G_40IN5G               2
+#define BRCMS_N_BW_20ALL               0
+#define BRCMS_N_BW_40ALL               1
+#define BRCMS_N_BW_20IN2G_40IN5G       2
 
 /* bitflags for SGI support (sgi_rx iovar) */
 #define BRCMS_N_SGI_20                 0x01
@@ -282,48 +213,42 @@ static u16 frametype(u32 rspec, u8 mimoframe)
 
 /* defines used by the nrate iovar */
 /* MSC in use,indicates b0-6 holds an mcs */
-#define NRATE_MCS_INUSE        0x00000080
+#define NRATE_MCS_INUSE                        0x00000080
 /* rate/mcs value */
-#define NRATE_RATE_MASK 0x0000007f
+#define NRATE_RATE_MASK                        0x0000007f
 /* stf mode mask: siso, cdd, stbc, sdm */
-#define NRATE_STF_MASK 0x0000ff00
+#define NRATE_STF_MASK                 0x0000ff00
 /* stf mode shift */
-#define NRATE_STF_SHIFT        8
-/* bit indicates override both rate & mode */
-#define NRATE_OVERRIDE 0x80000000
+#define NRATE_STF_SHIFT                        8
 /* bit indicate to override mcs only */
-#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
-#define NRATE_SGI_MASK  0x00800000     /* sgi mode */
-#define NRATE_SGI_SHIFT 23     /* sgi mode */
-#define NRATE_LDPC_CODING 0x00400000   /* bit indicates adv coding in use */
-#define NRATE_LDPC_SHIFT 22    /* ldpc shift */
+#define NRATE_OVERRIDE_MCS_ONLY                0x40000000
+#define NRATE_SGI_MASK                 0x00800000      /* sgi mode */
+#define NRATE_SGI_SHIFT                        23              /* sgi mode */
+#define NRATE_LDPC_CODING              0x00400000      /* adv coding in use */
+#define NRATE_LDPC_SHIFT               22              /* ldpc shift */
 
-#define NRATE_STF_SISO 0       /* stf mode SISO */
-#define NRATE_STF_CDD  1       /* stf mode CDD */
-#define NRATE_STF_STBC 2       /* stf mode STBC */
-#define NRATE_STF_SDM  3       /* stf mode SDM */
+#define NRATE_STF_SISO                 0               /* stf mode SISO */
+#define NRATE_STF_CDD                  1               /* stf mode CDD */
+#define NRATE_STF_STBC                 2               /* stf mode STBC */
+#define NRATE_STF_SDM                  3               /* stf mode SDM */
 
-#define MAX_DMA_SEGS 4
+#define MAX_DMA_SEGS                   4
 
 /* Max # of entries in Tx FIFO based on 4kb page size */
-#define NTXD           256
+#define NTXD                           256
 /* Max # of entries in Rx FIFO based on 4kb page size */
-#define NRXD           256
+#define NRXD                           256
 
 /* try to keep this # rbufs posted to the chip */
-#define        NRXBUFPOST      32
+#define NRXBUFPOST                     32
 
 /* data msg txq hiwat mark */
-#define BRCMS_DATAHIWAT                50
+#define BRCMS_DATAHIWAT                        50
 
-/* bounded rx loops */
-#define RXBND          8 /* max # frames to process in brcms_c_recv() */
-#define TXSBND         8 /* max # tx status to process in wlc_txstatus() */
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN       ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+/* max # frames to process in brcms_c_recv() */
+#define RXBND                          8
+/* max # tx status to process in wlc_txstatus() */
+#define TXSBND                         8
 
 /* brcmu_format_flags() bit description structure */
 struct brcms_c_bit_desc {
@@ -375,10 +300,22 @@ uint brcm_msg_level =
 #endif                         /* BCMDBG */
 
 /* TX FIFO number to WME/802.1E Access Category */
-static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
+static const u8 wme_fifo2ac[] = {
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BE
+};
 
-/* WME/802.1E Access Category to TX FIFO number */
-static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
+/* ieee80211 Access Category to TX FIFO number */
+static const u8 wme_ac2fifo[] = {
+       TX_AC_VO_FIFO,
+       TX_AC_VI_FIFO,
+       TX_AC_BE_FIFO,
+       TX_AC_BK_FIFO
+};
 
 /* 802.1D Priority to precedence queue mapping */
 const u8 wlc_prio2prec_map[] = {
@@ -405,13 +342,6 @@ static const u16 xmtfifo_sz[][NFIFO] = {
        {9, 58, 22, 14, 14, 5},
 };
 
-static const u8 acbitmap2maxprio[] = {
-       PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
-       PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
-       PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
-       PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
-};
-
 #ifdef BCMDBG
 static const char * const fifo_names[] = {
        "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
@@ -424,6 +354,22 @@ static const char fifo_names[6][0];
 static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
 #endif
 
+/* Find basic rate for a given rate */
+static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
+{
+       if (is_mcs_rate(rspec))
+               return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
+                      .leg_ofdm];
+       return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
+}
+
+static u16 frametype(u32 rspec, u8 mimoframe)
+{
+       if (is_mcs_rate(rspec))
+               return mimoframe;
+       return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
+}
+
 /* currently the best mechanism for determining SIFS is the band in use */
 static u16 get_sifs(struct brcms_band *band)
 {
@@ -470,20 +416,6 @@ static int brcms_chspec_bw(u16 chanspec)
        return BRCMS_10_MHZ;
 }
 
-/*
- * return true if Minimum Power Consumption should
- * be entered, false otherwise
- */
-static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
-{
-       return false;
-}
-
-static bool brcms_c_ismpc(struct brcms_c_info *wlc)
-{
-       return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
-}
-
 static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
 {
        if (cfg == NULL)
@@ -669,9 +601,8 @@ static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
  * calculate frame duration of a given rate and length, return
  * time in usec unit
  */
-uint
-brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
-                       u8 preamble_type, uint mac_len)
+static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
+                                   u8 preamble_type, uint mac_len)
 {
        uint nsyms, dur = 0, Ndps, kNdps;
        uint rate = rspec2rate(ratespec);
@@ -969,7 +900,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
                    lfbl,       /* Long Frame Rate Fallback Limit */
                    fbl;
 
-               if (queue < AC_COUNT) {
+               if (queue < IEEE80211_NUM_ACS) {
                        sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
                                      EDCF_SFB);
                        lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
@@ -1018,7 +949,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
                        tx_info->flags |= IEEE80211_TX_STAT_ACK;
        }
 
-       totlen = brcmu_pkttotlen(p);
+       totlen = p->len;
        free_pdu = true;
 
        brcms_c_txfifo_complete(wlc, queue, 1);
@@ -2352,13 +2283,6 @@ void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
        wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
 }
 
-static void brcms_c_fatal_error(struct brcms_c_info *wlc)
-{
-       wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
-                 wlc->pub->unit);
-       brcms_init(wlc->wl);
-}
-
 static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
 {
        bool fatal = false;
@@ -2414,7 +2338,7 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
                }
 
                if (fatal) {
-                       brcms_c_fatal_error(wlc_hw->wlc);       /* big hammer */
+                       brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */
                        break;
                } else
                        W_REG(&regs->intctrlregs[idx].intstatus,
@@ -2479,6 +2403,7 @@ void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
        W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
 }
 
+/* assumes that the d11 MAC is enabled */
 static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
                                    uint tx_fifo)
 {
@@ -2535,11 +2460,12 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
        }
 }
 
-static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
+/* precondition: requires the mac core to be enabled */
+static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
 {
        static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
-       if (on) {
+       if (mute_tx) {
                /* suspend tx fifos */
                brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
                brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
@@ -2561,14 +2487,20 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
                                       wlc_hw->etheraddr);
        }
 
-       wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
+       wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
 
-       if (on)
+       if (mute_tx)
                brcms_c_ucode_mute_override_set(wlc_hw);
        else
                brcms_c_ucode_mute_override_clear(wlc_hw);
 }
 
+void
+brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx)
+{
+       brcms_b_mute(wlc->hw, mute_tx);
+}
+
 /*
  * Read and clear macintmask and macintstatus and intstatus registers.
  * This routine should be called with interrupts off
@@ -3437,8 +3369,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
 }
 
 void
-static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
-                         bool mute) {
+static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
        u32 macintmask;
        bool fastclk;
        struct brcms_c_info *wlc = wlc_hw->wlc;
@@ -3463,10 +3394,6 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
        /* core-specific initialization */
        brcms_b_coreinit(wlc);
 
-       /* suspend the tx fifos and mute the phy for preism cac time */
-       if (mute)
-               brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
-
        /* band-specific inits */
        brcms_b_bsinit(wlc, chanspec);
 
@@ -3656,42 +3583,30 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
        brcms_c_set_phy_chanspec(wlc, chanspec);
 }
 
-static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
-{
-       if (wlc->bcnmisc_monitor)
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
-       else
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
-}
-
-void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
-{
-       wlc->bcnmisc_monitor = promisc;
-       brcms_c_mac_bcn_promisc(wlc);
-}
-
-/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
+/*
+ * Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and
+ * MCTL_KEEPCONTROL
+ */
 static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
 {
        u32 promisc_bits = 0;
 
-       /*
-        * promiscuous mode just sets MCTL_PROMISC
-        * Note: APs get all BSS traffic without the need to set
-        * the MCTL_PROMISC bit since all BSS data traffic is
-        * directed at the AP
-        */
-       if (wlc->pub->promisc)
-               promisc_bits |= MCTL_PROMISC;
+       if (wlc->bcnmisc_monitor)
+               promisc_bits |= MCTL_BCNS_PROMISC;
 
-       /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
-        * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
-        * handled in brcms_c_mac_bcn_promisc()
-        */
        if (wlc->monitor)
-               promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
+               promisc_bits |=
+                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL;
 
-       brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+       brcms_b_mctrl(wlc->hw,
+                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL,
+                       promisc_bits);
+}
+
+void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+{
+       wlc->bcnmisc_monitor = promisc;
+       brcms_c_mac_promisc(wlc);
 }
 
 /*
@@ -3723,7 +3638,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
        }
 
        /* update the various promisc bits */
-       brcms_c_mac_bcn_promisc(wlc);
        brcms_c_mac_promisc(wlc);
 }
 
@@ -3979,7 +3893,7 @@ static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
 
 void
 brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
-                     bool mute, struct txpwr_limits *txpwr)
+                     bool mute_tx, struct txpwr_limits *txpwr)
 {
        uint bandunit;
 
@@ -4005,7 +3919,7 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
                }
        }
 
-       wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
+       wlc_phy_initcal_enable(wlc_hw->band->pi, !mute_tx);
 
        if (!wlc_hw->up) {
                if (wlc_hw->clk)
@@ -4017,7 +3931,7 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
                wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
 
                /* Update muting of the channel */
-               brcms_b_mute(wlc_hw, mute, 0);
+               brcms_b_mute(wlc_hw, mute_tx);
        }
 }
 
@@ -4205,7 +4119,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
            EDCF_TXOP2USEC(acp_shm.txop);
        acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
 
-       if (aci == AC_VI && acp_shm.txop == 0
+       if (aci == IEEE80211_AC_VI && acp_shm.txop == 0
            && acp_shm.aifs < EDCF_AIFSN_MAX)
                acp_shm.aifs++;
 
@@ -4242,7 +4156,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
        }
 }
 
-void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
 {
        u16 aci;
        int i_ac;
@@ -4255,7 +4169,7 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
        }; /* ucode needs these parameters during its initialization */
        const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
 
-       for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
+       for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) {
                /* find out which ac this set of params applies to */
                aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
 
@@ -4277,17 +4191,6 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
        }
 }
 
-/* maintain LED behavior in down state */
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
-{
-       /*
-        * maintain LEDs while in down state, turn on sbclk if
-        * not available yet. Turn on sbclk if necessary
-        */
-       brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP);
-       brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP);
-}
-
 static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
 {
        /* Don't start the timer if HWRADIO feature is disabled */
@@ -4299,28 +4202,6 @@ static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
        brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
 }
 
-static void brcms_c_radio_disable(struct brcms_c_info *wlc)
-{
-       if (!wlc->pub->up) {
-               brcms_c_down_led_upd(wlc);
-               return;
-       }
-
-       brcms_c_radio_monitor_start(wlc);
-       brcms_down(wlc->wl);
-}
-
-static void brcms_c_radio_enable(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->up)
-               return;
-
-       if (brcms_deviceremoved(wlc))
-               return;
-
-       brcms_up(wlc->wl);
-}
-
 static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
 {
        if (!wlc->radio_monitor)
@@ -4343,18 +4224,6 @@ static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
                mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
 }
 
-/*
- * centralized radio disable/enable function,
- * invoke radio enable/disable after updating hwradio status
- */
-static void brcms_c_radio_upd(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->radio_disabled)
-               brcms_c_radio_disable(wlc);
-       else
-               brcms_c_radio_enable(wlc);
-}
-
 /* update hwradio status and return it */
 bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
 {
@@ -4376,12 +4245,7 @@ static void brcms_c_radio_timer(void *arg)
                return;
        }
 
-       /* cap mpc off count */
-       if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
-               wlc->mpc_offcnt++;
-
        brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
 }
 
 /* common low-level watchdog code */
@@ -4407,60 +4271,6 @@ static void brcms_b_watchdog(void *arg)
        wlc_phy_watchdog(wlc_hw->band->pi);
 }
 
-static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
-{
-       bool mpc_radio, radio_state;
-
-       /*
-        * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
-        * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
-        * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
-        * the radio is going down.
-        */
-       if (!wlc->mpc) {
-               if (!wlc->pub->radio_disabled)
-                       return;
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (!wlc->pub->radio_disabled)
-                       brcms_c_radio_monitor_stop(wlc);
-               return;
-       }
-
-       /*
-        * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
-        * wlc->pub->radio_disabled to go ON, always call radio_upd
-        * synchronously to go OFF, postpone radio_upd to later when
-        * context is safe(e.g. watchdog)
-        */
-       radio_state =
-           (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
-            ON);
-       mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
-
-       if (radio_state == ON && mpc_radio == OFF)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-       else if (radio_state == OFF && mpc_radio == ON) {
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
-                       wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
-               else
-                       wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-       }
-       /*
-        * Below logic is meant to capture the transition from mpc off
-        * to mpc on for reasons other than wlc->mpc_delay_off keeping
-        * the mpc off. In that case reset wlc->mpc_delay_off to
-        * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
-        */
-       if ((wlc->prev_non_delay_mpc == false) &&
-           (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-
-       wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
-}
-
 /* common watchdog code */
 static void brcms_c_watchdog(void *arg)
 {
@@ -4481,21 +4291,7 @@ static void brcms_c_watchdog(void *arg)
        /* increment second count */
        wlc->pub->now++;
 
-       /* delay radio disable */
-       if (wlc->mpc_delay_off) {
-               if (--wlc->mpc_delay_off == 0) {
-                       mboolset(wlc->pub->radio_disabled,
-                                WL_RADIO_MPC_DISABLE);
-                       if (wlc->mpc && brcms_c_ismpc(wlc))
-                               wlc->mpc_offcnt = 0;
-               }
-       }
-
-       /* mpc sync */
-       brcms_c_radio_mpc_upd(wlc);
-       /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
        brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
        /* if radio is disable, driver may be down, quit here */
        if (wlc->pub->radio_disabled)
                return;
@@ -4599,9 +4395,6 @@ static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
        /* WME QoS mode is Auto by default */
        wlc->pub->_ampdu = AMPDU_AGG_HOST;
        wlc->pub->bcmerror = 0;
-
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
 }
 
 static uint brcms_c_attach_module(struct brcms_c_info *wlc)
@@ -5259,9 +5052,6 @@ static void brcms_c_ap_upd(struct brcms_c_info *wlc)
 {
        /* STA-BSS; short capable */
        wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
-
-       /* fixup mpc */
-       wlc->mpc = true;
 }
 
 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
@@ -5376,7 +5166,7 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
        if (!wlc->clk)
                return;
 
-       for (ac = 0; ac < AC_COUNT; ac++)
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
                                  wlc->wme_retries[ac]);
 }
@@ -5575,7 +5365,6 @@ uint brcms_c_down(struct brcms_c_info *wlc)
        if (!wlc->pub->up)
                return callbacks;
 
-       /* in between, mpc could try to bring down again.. */
        wlc->going_down = true;
 
        callbacks += brcms_b_bmac_down_prep(wlc->hw);
@@ -5852,7 +5641,7 @@ int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
 
        brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
 
-       for (ac = 0; ac < AC_COUNT; ac++) {
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                wlc->wme_retries[ac] =  SFIELD(wlc->wme_retries[ac],
                                               EDCF_SHORT,  wlc->SRL);
                wlc->wme_retries[ac] =  SFIELD(wlc->wme_retries[ac],
@@ -6103,7 +5892,6 @@ void brcms_c_print_txdesc(struct d11txh *txh)
 
        u8 *rtsph = txh->RTSPhyHeader;
        struct ieee80211_rts rts = txh->rts_frame;
-       char hexbuf[256];
 
        /* add plcp header along with txh descriptor */
        printk(KERN_DEBUG "Raw TxDesc + plcp header:\n");
@@ -6124,17 +5912,16 @@ void brcms_c_print_txdesc(struct d11txh *txh)
        printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft);
        printk(KERN_DEBUG "\n");
 
-       brcmu_format_hex(hexbuf, iv, sizeof(txh->IV));
-       printk(KERN_DEBUG "SecIV:       %s\n", hexbuf);
-       brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA));
-       printk(KERN_DEBUG "RA:          %s\n", hexbuf);
+       print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV));
+       print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET,
+                            ra, sizeof(txh->TxFrameRA));
 
        printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb);
-       brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback));
-       printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
+       print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET,
+                            rtspfb, sizeof(txh->RTSPLCPFallback));
        printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb);
-       brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback));
-       printk(KERN_DEBUG "PLCP: %s ", hexbuf);
+       print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET,
+                            fragpfb, sizeof(txh->FragPLCPFallback));
        printk(KERN_DEBUG "DUR: %04x", fragdfb);
        printk(KERN_DEBUG "\n");
 
@@ -6149,18 +5936,18 @@ void brcms_c_print_txdesc(struct d11txh *txh)
        printk(KERN_DEBUG "MaxAggbyte_fb:  %04x\n", mabyte_f);
        printk(KERN_DEBUG "MinByte:     %04x\n", mmbyte);
 
-       brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader));
-       printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
-       brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame));
-       printk(KERN_DEBUG "RTS Frame: %s", hexbuf);
+       print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET,
+                            rtsph, sizeof(txh->RTSPhyHeader));
+       print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET,
+                            (u8 *)&rts, sizeof(txh->rts_frame));
        printk(KERN_DEBUG "\n");
 }
 #endif                         /* defined(BCMDBG) */
 
 #if defined(BCMDBG)
-int
+static int
 brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
-                  int len)
+                    int len)
 {
        int i;
        char *p = buf;
@@ -6916,7 +6703,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
        qos = ieee80211_is_data_qos(h->frame_control);
 
        /* compute length of frame in bytes for use in PLCP computations */
-       len = brcmu_pkttotlen(p);
+       len = p->len;
        phylen = len + FCS_LEN;
 
        /* Get tx_info */
@@ -8253,12 +8040,6 @@ int brcms_c_get_tx_power(struct brcms_c_info *wlc)
        return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
 }
 
-void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
-{
-       wlc->mpc = mpc;
-       brcms_c_radio_mpc_upd(wlc);
-}
-
 /* Process received frames */
 /*
  * Return true if more frames need to be processed. false otherwise.
@@ -8328,21 +8109,17 @@ static bool
 brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
 {
        struct sk_buff *p;
-       struct sk_buff *head = NULL;
-       struct sk_buff *tail = NULL;
+       struct sk_buff *next = NULL;
+       struct sk_buff_head recv_frames;
+
        uint n = 0;
        uint bound_limit = bound ? RXBND : -1;
 
        BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-       /* gather received frames */
-       while ((p = dma_rx(wlc_hw->di[fifo]))) {
+       skb_queue_head_init(&recv_frames);
 
-               if (!tail)
-                       head = tail = p;
-               else {
-                       tail->prev = p;
-                       tail = p;
-               }
+       /* gather received frames */
+       while (dma_rx(wlc_hw->di[fifo], &recv_frames)) {
 
                /* !give others some time to run! */
                if (++n >= bound_limit)
@@ -8353,12 +8130,11 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
        dma_rxfill(wlc_hw->di[fifo]);
 
        /* process each frame */
-       while ((p = head) != NULL) {
+       skb_queue_walk_safe(&recv_frames, p, next) {
                struct d11rxhdr_le *rxh_le;
                struct d11rxhdr *rxh;
-               head = head->prev;
-               p->prev = NULL;
 
+               skb_unlink(p, &recv_frames);
                rxh_le = (struct d11rxhdr_le *)p->data;
                rxh = (struct d11rxhdr *)p->data;
 
@@ -8448,8 +8224,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
                printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
                                        __func__, wlc_hw->sih->chip,
                                        wlc_hw->sih->chiprev);
-               /* big hammer */
-               brcms_init(wlc->wl);
+               brcms_fatal_error(wlc_hw->wlc->wl);
        }
 
        /* gptimer timeout */
@@ -8470,15 +8245,14 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
        return wlc->macintstatus != 0;
 
  fatal:
-       brcms_init(wlc->wl);
+       brcms_fatal_error(wlc_hw->wlc->wl);
        return wlc->macintstatus != 0;
 }
 
-void brcms_c_init(struct brcms_c_info *wlc)
+void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 {
        struct d11regs __iomem *regs;
        u16 chanspec;
-       bool mute = false;
 
        BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
@@ -8494,7 +8268,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
        else
                chanspec = brcms_c_init_chanspec(wlc);
 
-       brcms_b_init(wlc->hw, chanspec, mute);
+       brcms_b_init(wlc->hw, chanspec);
 
        /* update beacon listen interval */
        brcms_c_bcn_li_upd(wlc);
@@ -8560,15 +8334,16 @@ void brcms_c_init(struct brcms_c_info *wlc)
        /* ..now really unleash hell (allow the MAC out of suspend) */
        brcms_c_enable_mac(wlc);
 
+       /* suspend the tx fifos and mute the phy for preism cac time */
+       if (mute_tx)
+               brcms_b_mute(wlc->hw, true);
+
        /* clear tx flow control */
        brcms_c_txflowcontrol_reset(wlc);
 
        /* enable the RF Disable Delay timer */
        W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
 
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-
        /*
         * Initialize WME parameters; if they haven't been set by some other
         * mechanism (IOVar, etc) then read them from the hardware.
@@ -8577,7 +8352,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
                /* Uninitialized; read from HW */
                int ac;
 
-               for (ac = 0; ac < AC_COUNT; ac++)
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                        wlc->wme_retries[ac] =
                            brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
        }
@@ -8754,8 +8529,6 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
                brcms_c_ht_update_sgi_rx(wlc, 0);
        }
 
-       /* initialize radio_mpc_disable according to wlc->mpc */
-       brcms_c_radio_mpc_upd(wlc);
        brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
 
        if (perr)
index c0e0fcfdfaf8e7988e5ec6d22919df019218f08e..251c350b3164567fdc979aee8a22dd53217c274e 100644 (file)
@@ -44,8 +44,6 @@
 /* transmit buffer max headroom for protocol headers */
 #define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN)
 
-#define AC_COUNT               4
-
 /* Macros for doing definition and get/set of bitfields
  * Usage example, e.g. a three-bit field (bits 4-6):
  *    #define <NAME>_M BITFIELD_MASK(3)
@@ -427,11 +425,6 @@ struct brcms_txq_info {
  * bandinit_pending: track band init in auto band.
  * radio_monitor: radio timer is running.
  * going_down: down path intermediate variable.
- * mpc: enable minimum power consumption.
- * mpc_dlycnt: # of watchdog cnt before turn disable radio.
- * mpc_offcnt: # of watchdog cnt that radio is disabled.
- * mpc_delay_off: delay radio disable by # of watchdog cnt.
- * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc.
  * wdtimer: timer for watchdog routine.
  * radio_timer: timer for hw radio button monitor routine.
  * monitor: monitor (MPDU sniffing) mode.
@@ -441,7 +434,7 @@ struct brcms_txq_info {
  * bcn_li_dtim: beacon listen interval in # dtims.
  * WDarmed: watchdog timer is armed.
  * WDlast: last time wlc_watchdog() was called.
- * edcf_txop[AC_COUNT]: current txop for each ac.
+ * edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac.
  * wme_retries: per-AC retry limits.
  * tx_prec_map: Precedence map based on HW FIFO space.
  * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
@@ -522,12 +515,6 @@ struct brcms_c_info {
        bool radio_monitor;
        bool going_down;
 
-       bool mpc;
-       u8 mpc_dlycnt;
-       u8 mpc_offcnt;
-       u8 mpc_delay_off;
-       u8 prev_non_delay_mpc;
-
        struct brcms_timer *wdtimer;
        struct brcms_timer *radio_timer;
 
@@ -546,9 +533,9 @@ struct brcms_c_info {
        u32 WDlast;
 
        /* WME */
-       u16 edcf_txop[AC_COUNT];
+       u16 edcf_txop[IEEE80211_NUM_ACS];
 
-       u16 wme_retries[AC_COUNT];
+       u16 wme_retries[IEEE80211_NUM_ACS];
        u16 tx_prec_map;
        u16 fifo2prec_map[NFIFO];
 
index a3149254cbcdadc9bdae753ec4300cf7904199c4..e17edf7e68335396d3de606681e61681d4ae0192 100644 (file)
@@ -112,7 +112,7 @@ static const struct chan_info_basic chan_info_all[] = {
        {216, 50800}
 };
 
-const u8 ofdm_rate_lookup[] = {
+static const u8 ofdm_rate_lookup[] = {
 
        BRCM_RATE_48M,
        BRCM_RATE_24M,
@@ -190,15 +190,7 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
                data = R_REG(&pi->regs->radioregdata);
        } else {
                W_REG_FLUSH(&pi->regs->phy4waddr, addr);
-
-#ifdef __ARM_ARCH_4T__
-               __asm__(" .align 4 ");
-               __asm__(" nop ");
-               data = R_REG(&pi->regs->phy4wdatalo);
-#else
                data = R_REG(&pi->regs->phy4wdatalo);
-#endif
-
        }
        pi->phy_wreg = 0;
 
index bea85241a244630cc8be4baf9693ea5cb0a91676..5f9478b1c9937be8e0ea94061a390d409b4814a8 100644 (file)
@@ -774,11 +774,6 @@ struct brcms_phy {
        s16 nphy_noise_win[PHY_CORE_MAX][PHY_NOISE_WINDOW_SZ];
        u8 nphy_noise_index;
 
-       u8 nphy_txpid2g[PHY_CORE_NUM_2];
-       u8 nphy_txpid5g[PHY_CORE_NUM_2];
-       u8 nphy_txpid5gl[PHY_CORE_NUM_2];
-       u8 nphy_txpid5gh[PHY_CORE_NUM_2];
-
        bool nphy_gain_boost;
        bool nphy_elna_gain_config;
        u16 old_bphy_test;
index cd19c2f7a34776bc96ee29cf9070bb0cfe524933..ec9b56639d544fed3c60d46fc0ed4a021407a96d 100644 (file)
@@ -29,6 +29,7 @@
 #include "phy_radio.h"
 #include "phyreg_n.h"
 #include "phytbl_n.h"
+#include "soc.h"
 
 #define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name)        \
        read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
@@ -14417,12 +14418,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                switch (band_num) {
                case 0:
 
-                       pi->nphy_txpid2g[PHY_CORE_0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID2GA0);
-                       pi->nphy_txpid2g[PHY_CORE_1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID2GA1);
                        pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP2GA0);
@@ -14486,12 +14481,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 1:
 
-                       pi->nphy_txpid5g[PHY_CORE_0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GA0);
-                       pi->nphy_txpid5g[PHY_CORE_1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GA1);
                        pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
                                (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
                        pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
@@ -14551,12 +14540,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 2:
 
-                       pi->nphy_txpid5gl[0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GLA0);
-                       pi->nphy_txpid5gl[1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GLA1);
                        pi->nphy_pwrctrl_info[0].max_pwr_5gl =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP5GLA0);
@@ -14615,12 +14598,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 3:
 
-                       pi->nphy_txpid5gh[0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GHA0);
-                       pi->nphy_txpid5gh[1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GHA1);
                        pi->nphy_pwrctrl_info[0].max_pwr_5gh =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP5GHA0);
@@ -27994,20 +27971,11 @@ void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
                chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
                switch (chan_freq_range) {
                case WL_CHAN_FREQ_RANGE_2G:
-                       txpi[0] = pi->nphy_txpid2g[0];
-                       txpi[1] = pi->nphy_txpid2g[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GL:
-                       txpi[0] = pi->nphy_txpid5gl[0];
-                       txpi[1] = pi->nphy_txpid5gl[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GM:
-                       txpi[0] = pi->nphy_txpid5g[0];
-                       txpi[1] = pi->nphy_txpid5g[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GH:
-                       txpi[0] = pi->nphy_txpid5gh[0];
-                       txpi[1] = pi->nphy_txpid5gh[1];
+                       txpi[0] = 0;
+                       txpi[1] = 0;
                        break;
                default:
                        txpi[0] = txpi[1] = 91;
index 3b36e3acfd74cb77672af14596dcb8c4c2edc7fa..12ba575f578559031226a91a7555c44ee33d6698 100644 (file)
@@ -23,6 +23,7 @@
 #include "pub.h"
 #include "aiutils.h"
 #include "pmu.h"
+#include "soc.h"
 
 /*
  * external LPO crystal frequency
index 37bb2dcc113f179d990d7d9007d779d26e95540e..21ccf3a039873cf777595e0e5a71ff8eb93a94a1 100644 (file)
@@ -170,22 +170,6 @@ enum brcms_srom_id {
        BRCMS_SROM_TSSIPOS2G,
        BRCMS_SROM_TSSIPOS5G,
        BRCMS_SROM_TXCHAIN,
-       BRCMS_SROM_TXPID2GA0,
-       BRCMS_SROM_TXPID2GA1,
-       BRCMS_SROM_TXPID2GA2,
-       BRCMS_SROM_TXPID2GA3,
-       BRCMS_SROM_TXPID5GA0,
-       BRCMS_SROM_TXPID5GA1,
-       BRCMS_SROM_TXPID5GA2,
-       BRCMS_SROM_TXPID5GA3,
-       BRCMS_SROM_TXPID5GHA0,
-       BRCMS_SROM_TXPID5GHA1,
-       BRCMS_SROM_TXPID5GHA2,
-       BRCMS_SROM_TXPID5GHA3,
-       BRCMS_SROM_TXPID5GLA0,
-       BRCMS_SROM_TXPID5GLA1,
-       BRCMS_SROM_TXPID5GLA2,
-       BRCMS_SROM_TXPID5GLA3,
        /*
         * per-path identifiers (see srom.c)
         */
@@ -225,10 +209,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA2GW2A1,
        BRCMS_SROM_PA2GW2A2,
        BRCMS_SROM_PA2GW2A3,
-       BRCMS_SROM_PA2GW3A0,
-       BRCMS_SROM_PA2GW3A1,
-       BRCMS_SROM_PA2GW3A2,
-       BRCMS_SROM_PA2GW3A3,
        BRCMS_SROM_PA5GHW0A0,
        BRCMS_SROM_PA5GHW0A1,
        BRCMS_SROM_PA5GHW0A2,
@@ -241,10 +221,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GHW2A1,
        BRCMS_SROM_PA5GHW2A2,
        BRCMS_SROM_PA5GHW2A3,
-       BRCMS_SROM_PA5GHW3A0,
-       BRCMS_SROM_PA5GHW3A1,
-       BRCMS_SROM_PA5GHW3A2,
-       BRCMS_SROM_PA5GHW3A3,
        BRCMS_SROM_PA5GLW0A0,
        BRCMS_SROM_PA5GLW0A1,
        BRCMS_SROM_PA5GLW0A2,
@@ -257,10 +233,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GLW2A1,
        BRCMS_SROM_PA5GLW2A2,
        BRCMS_SROM_PA5GLW2A3,
-       BRCMS_SROM_PA5GLW3A0,
-       BRCMS_SROM_PA5GLW3A1,
-       BRCMS_SROM_PA5GLW3A2,
-       BRCMS_SROM_PA5GLW3A3,
        BRCMS_SROM_PA5GW0A0,
        BRCMS_SROM_PA5GW0A1,
        BRCMS_SROM_PA5GW0A2,
@@ -273,14 +245,9 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GW2A1,
        BRCMS_SROM_PA5GW2A2,
        BRCMS_SROM_PA5GW2A3,
-       BRCMS_SROM_PA5GW3A0,
-       BRCMS_SROM_PA5GW3A1,
-       BRCMS_SROM_PA5GW3A2,
-       BRCMS_SROM_PA5GW3A3,
 };
 
 #define        BRCMS_NUMRATES  16      /* max # of rates in a rateset */
-#define        D11_PHY_HDR_LEN 6       /* Phy header length - 6 bytes */
 
 /* phy types */
 #define        PHY_TYPE_A      0       /* Phy type A */
@@ -414,7 +381,6 @@ struct brcms_pub {
        uint _nbands;           /* # bands supported */
        uint now;               /* # elapsed seconds */
 
-       bool promisc;           /* promiscuous destination address */
        bool delayed_down;      /* down delayed */
        bool associated;        /* true:part of [I]BSS, false: not */
        /* (union of stas_associated, aps_associated) */
@@ -572,7 +538,7 @@ extern int brcms_c_up(struct brcms_c_info *wlc);
 extern uint brcms_c_down(struct brcms_c_info *wlc);
 
 extern bool brcms_c_chipmatch(u16 vendor, u16 device);
-extern void brcms_c_init(struct brcms_c_info *wlc);
+extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx);
 extern void brcms_c_reset(struct brcms_c_info *wlc);
 
 extern void brcms_c_intrson(struct brcms_c_info *wlc);
@@ -628,7 +594,7 @@ extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
                                        u8 interval);
 extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
 extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
-extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
 extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
+extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
 
 #endif                         /* _BRCM_PUB_H_ */
index e7b9dc2f27315a17e7776efe43080ed3098afe93..980d578825cc0b3b131995bfcf6926bbab0bbbf1 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "types.h"
 #include "d11.h"
+#include "phy_hal.h"
 
 extern const u8 rate_info[];
 extern const struct brcms_c_rateset cck_ofdm_mimo_rates;
@@ -198,11 +199,9 @@ static inline u8 cck_rspec(u8 cck)
 
 /* Convert encoded rate value in plcp header to numerical rates in 500 KHz
  * increments */
-extern const u8 ofdm_rate_lookup[];
-
 static inline u8 ofdm_phy2mac_rate(u8 rlpt)
 {
-       return ofdm_rate_lookup[rlpt & 0x7];
+       return wlc_phy_get_ofdm_rate_lookup()[rlpt & 0x7];
 }
 
 static inline u8 cck_phy2mac_rate(u8 signal)
index 99f791048e841b7295a9fb8abf8c4f172c267029..b6987ea9fc689b6b4351ab83cf3af9f67aa32e3a 100644 (file)
@@ -28,6 +28,7 @@
 #include "aiutils.h"
 #include "otp.h"
 #include "srom.h"
+#include "soc.h"
 
 /*
  * SROM CRC8 polynomial value:
@@ -62,9 +63,6 @@
 #define        SROM_MACHI_ET1          42
 #define        SROM_MACMID_ET1         43
 #define        SROM_MACLO_ET1          44
-#define        SROM3_MACHI             37
-#define        SROM3_MACMID            38
-#define        SROM3_MACLO             39
 
 #define        SROM_BXARSSI2G          40
 #define        SROM_BXARSSI5G          41
 
 #define        SROM_BFL                57
 #define        SROM_BFL2               28
-#define        SROM3_BFL2              61
 
 #define        SROM_AG10               58
 
 
 #define        SROM_OPO                60
 
-#define        SROM3_LEDDC             62
-
 #define        SROM_CRCREV             63
 
-/* SROM Rev 4: Reallocate the software part of the srom to accommodate
- * MIMO features. It assumes up to two PCIE functions and 440 bytes
- * of usable srom i.e. the usable storage in chips with OTP that
- * implements hardware redundancy.
- */
-
 #define        SROM4_WORDS             220
 
-#define        SROM4_SIGN              32
-#define        SROM4_SIGNATURE         0x5372
-
-#define        SROM4_BREV              33
-
-#define        SROM4_BFL0              34
-#define        SROM4_BFL1              35
-#define        SROM4_BFL2              36
-#define        SROM4_BFL3              37
-#define        SROM5_BFL0              37
-#define        SROM5_BFL1              38
-#define        SROM5_BFL2              39
-#define        SROM5_BFL3              40
-
-#define        SROM4_MACHI             38
-#define        SROM4_MACMID            39
-#define        SROM4_MACLO             40
-#define        SROM5_MACHI             41
-#define        SROM5_MACMID            42
-#define        SROM5_MACLO             43
-
-#define        SROM4_CCODE             41
-#define        SROM4_REGREV            42
-#define        SROM5_CCODE             34
-#define        SROM5_REGREV            35
-
-#define        SROM4_LEDBH10           43
-#define        SROM4_LEDBH32           44
-#define        SROM5_LEDBH10           59
-#define        SROM5_LEDBH32           60
-
-#define        SROM4_LEDDC             45
-#define        SROM5_LEDDC             45
-
-#define        SROM4_AA                46
-
-#define        SROM4_AG10              47
-#define        SROM4_AG32              48
-
-#define        SROM4_TXPID2G           49
-#define        SROM4_TXPID5G           51
-#define        SROM4_TXPID5GL          53
-#define        SROM4_TXPID5GH          55
-
-#define SROM4_TXRXC            61
 #define SROM4_TXCHAIN_MASK     0x000f
-#define SROM4_TXCHAIN_SHIFT    0
 #define SROM4_RXCHAIN_MASK     0x00f0
-#define SROM4_RXCHAIN_SHIFT    4
 #define SROM4_SWITCH_MASK      0xff00
-#define SROM4_SWITCH_SHIFT     8
 
 /* Per-path fields */
 #define        MAX_PATH_SROM           4
-#define        SROM4_PATH0             64
-#define        SROM4_PATH1             87
-#define        SROM4_PATH2             110
-#define        SROM4_PATH3             133
-
-#define        SROM4_2G_ITT_MAXP       0
-#define        SROM4_2G_PA             1
-#define        SROM4_5G_ITT_MAXP       5
-#define        SROM4_5GLH_MAXP         6
-#define        SROM4_5G_PA             7
-#define        SROM4_5GL_PA            11
-#define        SROM4_5GH_PA            15
-
-/* All the miriad power offsets */
-#define        SROM4_2G_CCKPO          156
-#define        SROM4_2G_OFDMPO         157
-#define        SROM4_5G_OFDMPO         159
-#define        SROM4_5GL_OFDMPO        161
-#define        SROM4_5GH_OFDMPO        163
-#define        SROM4_2G_MCSPO          165
-#define        SROM4_5G_MCSPO          173
-#define        SROM4_5GL_MCSPO         181
-#define        SROM4_5GH_MCSPO         189
-#define        SROM4_CDDPO             197
-#define        SROM4_STBCPO            198
-#define        SROM4_BW40PO            199
-#define        SROM4_BWDUPPO           200
 
 #define        SROM4_CRCREV            219
 
@@ -424,103 +338,32 @@ struct brcms_varbuf {
 static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
         0xffff},
-       {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV,
-        SROM_BR_MASK},
-       {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
        {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff},
        {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
         0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff},
        {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
         0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
        {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff},
        {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
-       {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
-       {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00},
-       {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff},
-       {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff},
        {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
-       {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
-       {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
-       {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
        {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
        {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
        {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
        {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
-       {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
-       {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
-       {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
-       {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff},
-       {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
        {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
        {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
        {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
        {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
        {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
-       {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff},
        {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
-       {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
-       {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff},
        {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
-       {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
-       {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00},
        {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
-       {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff},
-       {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00},
-       {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff},
-       {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00},
-       {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff},
-       {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00},
        {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
        {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
        {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
        {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
-       {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
-       {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
-       {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
-       {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
-       {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
-       {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
-       {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
-       {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
-       {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
-       {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00},
-       {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
-       {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
-       {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
        {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
        {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
        {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
@@ -534,40 +377,20 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
        {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
        {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
-       {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
-       {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
-       {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
-       {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
        {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
        {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
        {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
        {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
-       {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
-       {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
-       {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
-       {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
        {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
        {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
        {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
        {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
-       {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff},
-       {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00},
-       {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
-       {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00},
        {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
        {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
        {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
        {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
-       {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
-       {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
        {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
        {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
-       {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_TXCHAIN_MASK},
-       {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_RXCHAIN_MASK},
-       {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_SWITCH_MASK},
        {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
         SROM4_TXCHAIN_MASK},
        {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
@@ -594,43 +417,11 @@ static const struct brcms_sromvar pci_sromvars[] = {
         SROM8_FEM_ANTSWLUT_MASK},
        {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
        {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
-       {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
-       {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
-       {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
-       {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
-       {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
-       {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
-       {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
-       {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
-       {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
-       {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
-
-       {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
-       {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
-       {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+
        {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
        {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
-       {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0,
-        0xffff},
-       {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1,
-        0xffff},
        {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
         0xffff},
-       {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC,
-        0xffff},
-       {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC,
-        0xffff},
-       {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC,
-        0xffff},
        {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
         0x01ff},
        {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
@@ -650,16 +441,7 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
         0x00ff},
 
-       {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
        {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
-       {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
@@ -668,38 +450,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
        {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
        {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
        {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
@@ -732,10 +482,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
        {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
        {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff},
-       {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff},
-       {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff},
-       {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
        {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
        {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
        {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
@@ -811,34 +557,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
 };
 
 static const struct brcms_sromvar perpath_pci_sromvars[] = {
-       {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
-       {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
-       {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
-       {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
-       {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
-       {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
-       {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
-       {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
-       {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
-       {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
-       {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
-       {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
-       {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
-       {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
-       {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
-       {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1,
-        0xffff},
-       {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2,
-        0xffff},
-       {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3,
-        0xffff},
-       {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
-       {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1,
-        0xffff},
-       {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2,
-        0xffff},
-       {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3,
-        0xffff},
        {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
        {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
        {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
@@ -868,24 +586,17 @@ static const struct brcms_sromvar perpath_pci_sromvars[] = {
  * shared between devices. */
 static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
 
-static u16 __iomem *
+static u8 __iomem *
 srom_window_address(struct si_pub *sih, u8 __iomem *curmap)
 {
        if (sih->ccrev < 32)
-               return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET);
+               return curmap + PCI_BAR0_SPROM_OFFSET;
        if (sih->cccaps & CC_CAP_SROM)
-               return (u16 __iomem *)
-                      (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP);
+               return curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP;
 
        return NULL;
 }
 
-/* Parse SROM and create name=value pairs. 'srom' points to
- * the SROM word array. 'off' specifies the offset of the
- * first word 'srom' points to, which should be either 0 or
- * SROM3_SWRG_OFF (full SROM or software region).
- */
-
 static uint mask_shift(u16 mask)
 {
        uint i;
@@ -906,18 +617,16 @@ static uint mask_width(u16 mask)
        return 0;
 }
 
-static inline void ltoh16_buf(u16 *buf, unsigned int size)
+static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
 {
-       size /= 2;
-       while (size--)
-               *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size));
+       while (nwords--)
+               *(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
 }
 
-static inline void htol16_buf(u16 *buf, unsigned int size)
+static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
 {
-       size /= 2;
-       while (size--)
-               *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size));
+       while (nwords--)
+               *(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
 }
 
 /*
@@ -929,11 +638,14 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
        struct brcms_srom_list_head *entry;
        enum brcms_srom_id id;
        u16 w;
-       u32 val;
+       u32 val = 0;
        const struct brcms_sromvar *srv;
        uint width;
        uint flags;
        u32 sr = (1 << sromrev);
+       uint p;
+       uint pb =  SROM8_PATH0;
+       const uint psz = SROM8_PATH1 - SROM8_PATH0;
 
        /* first store the srom revision */
        entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
@@ -1031,47 +743,34 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
                list_add(&entry->var_list, var_list);
        }
 
-       if (sromrev >= 4) {
-               /* Do per-path variables */
-               uint p, pb, psz;
-
-               if (sromrev >= 8) {
-                       pb = SROM8_PATH0;
-                       psz = SROM8_PATH1 - SROM8_PATH0;
-               } else {
-                       pb = SROM4_PATH0;
-                       psz = SROM4_PATH1 - SROM4_PATH0;
-               }
-
-               for (p = 0; p < MAX_PATH_SROM; p++) {
-                       for (srv = perpath_pci_sromvars;
-                            srv->varid != BRCMS_SROM_NULL; srv++) {
-                               if ((srv->revmask & sr) == 0)
-                                       continue;
+       for (p = 0; p < MAX_PATH_SROM; p++) {
+               for (srv = perpath_pci_sromvars;
+                    srv->varid != BRCMS_SROM_NULL; srv++) {
+                       if ((srv->revmask & sr) == 0)
+                               continue;
 
-                               if (srv->flags & SRFL_NOVAR)
-                                       continue;
+                       if (srv->flags & SRFL_NOVAR)
+                               continue;
 
-                               w = srom[pb + srv->off];
-                               val = (w & srv->mask) >> mask_shift(srv->mask);
-                               width = mask_width(srv->mask);
+                       w = srom[pb + srv->off];
+                       val = (w & srv->mask) >> mask_shift(srv->mask);
+                       width = mask_width(srv->mask);
 
-                               /* Cheating: no per-path var is more than
-                                * 1 word */
-                               if ((srv->flags & SRFL_NOFFS)
-                                   && ((int)val == (1 << width) - 1))
-                                       continue;
+                       /* Cheating: no per-path var is more than
+                        * 1 word */
+                       if ((srv->flags & SRFL_NOFFS)
+                           && ((int)val == (1 << width) - 1))
+                               continue;
 
-                               entry =
-                                   kzalloc(sizeof(struct brcms_srom_list_head),
-                                           GFP_KERNEL);
-                               entry->varid = srv->varid+p;
-                               entry->var_type = BRCMS_SROM_UNUMBER;
-                               entry->uval = val;
-                               list_add(&entry->var_list, var_list);
-                       }
-                       pb += psz;
+                       entry =
+                           kzalloc(sizeof(struct brcms_srom_list_head),
+                                   GFP_KERNEL);
+                       entry->varid = srv->varid+p;
+                       entry->var_type = BRCMS_SROM_UNUMBER;
+                       entry->uval = val;
+                       list_add(&entry->var_list, var_list);
                }
+               pb += psz;
        }
 }
 
@@ -1080,41 +779,38 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
  * Return 0 on success, nonzero on error.
  */
 static int
-sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff,
+sprom_read_pci(struct si_pub *sih, u8 __iomem *sprom, uint wordoff,
               u16 *buf, uint nwords, bool check_crc)
 {
        int err = 0;
        uint i;
+       u8 *bbuf = (u8 *)buf; /* byte buffer */
+       uint nbytes = nwords << 1;
 
-       /* read the sprom */
-       for (i = 0; i < nwords; i++)
-               buf[i] = R_REG(&sprom[wordoff + i]);
-
-       if (check_crc) {
+       /* read the sprom in bytes */
+       for (i = 0; i < nbytes; i++)
+               bbuf[i] = readb(sprom+i);
 
-               if (buf[0] == 0xffff)
-                       /*
-                        * The hardware thinks that an srom that starts with
-                        * 0xffff is blank, regardless of the rest of the
-                        * content, so declare it bad.
-                        */
-                       return -ENODATA;
-
-               /* fixup the endianness so crc8 will pass */
-               htol16_buf(buf, nwords * 2);
-               if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2,
-                        CRC8_INIT_VALUE) !=
-                        CRC8_GOOD_VALUE(brcms_srom_crc8_table))
-                       /* DBG only pci always read srom4 first, then srom8/9 */
-                       err = -EIO;
+       if (buf[0] == 0xffff)
+               /*
+                * The hardware thinks that an srom that starts with
+                * 0xffff is blank, regardless of the rest of the
+                * content, so declare it bad.
+                */
+               return -ENODATA;
 
+       if (check_crc &&
+           crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) !=
+                CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+               err = -EIO;
+       else
                /* now correct the endianness of the byte array */
-               ltoh16_buf(buf, nwords * 2);
-       }
+               le16_to_cpu_buf(buf, nwords);
+
        return err;
 }
 
-static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
+static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
 {
        u8 *otp;
        uint sz = OTP_SZ_MAX / 2;       /* size in words */
@@ -1126,7 +822,8 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
 
        err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
 
-       memcpy(buf, otp, bufsz);
+       sz = min_t(uint, sz, nwords);
+       memcpy(buf, otp, sz * 2);
 
        kfree(otp);
 
@@ -1139,13 +836,13 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
                return -ENODATA;
 
        /* fixup the endianness so crc8 will pass */
-       htol16_buf(buf, bufsz);
-       if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2,
+       cpu_to_le16_buf(buf, sz);
+       if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
                 CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
                err = -EIO;
-
-       /* now correct the endianness of the byte array */
-       ltoh16_buf(buf, bufsz);
+       else
+               /* now correct the endianness of the byte array */
+               le16_to_cpu_buf(buf, sz);
 
        return err;
 }
@@ -1157,7 +854,7 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
 static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
 {
        u16 *srom;
-       u16 __iomem *sromwindow;
+       u8 __iomem *sromwindow;
        u8 sromrev = 0;
        u32 sr;
        int err = 0;
@@ -1173,29 +870,16 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
 
        crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
        if (ai_is_sprom_available(sih)) {
-               err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
-                                    true);
-
-               if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
-                   (((sih->buscoretype == PCIE_CORE_ID)
-                     && (sih->buscorerev >= 6))
-                    || ((sih->buscoretype == PCI_CORE_ID)
-                        && (sih->buscorerev >= 0xe)))) {
-                       /* sromrev >= 4, read more */
-                       err = sprom_read_pci(sih, sromwindow, 0, srom,
-                                            SROM4_WORDS, true);
-                       sromrev = srom[SROM4_CRCREV] & 0xff;
-               } else if (err == 0) {
-                       /* srom is good and is rev < 4 */
+               err = sprom_read_pci(sih, sromwindow, 0, srom,
+                                    SROM4_WORDS, true);
+
+               if (err == 0)
+                       /* srom read and passed crc */
                        /* top word of sprom contains version and crc8 */
-                       sromrev = srom[SROM_CRCREV] & 0xff;
-                       /* bcm4401 sroms misprogrammed */
-                       if (sromrev == 0x10)
-                               sromrev = 1;
-               }
+                       sromrev = srom[SROM4_CRCREV] & 0xff;
        } else {
                /* Use OTP if SPROM not available */
-               err = otp_read_pci(sih, srom, SROM_MAX);
+               err = otp_read_pci(sih, srom, SROM4_WORDS);
                if (err == 0)
                        /* OTP only contain SROM rev8/rev9 for now */
                        sromrev = srom[SROM4_CRCREV] & 0xff;
@@ -1208,10 +892,9 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
                sr = 1 << sromrev;
 
                /*
-                * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8,
-                * 9
+                * srom version check: Current valid versions: 8, 9
                 */
-               if ((sr & 0x33e) == 0) {
+               if ((sr & 0x300) == 0) {
                        err = -EINVAL;
                        goto errout;
                }
index 708c43ff51ccf44286c25ce0e18500f1f6799fc7..c81df9798e50ac606dc4c9e15122f8ba58d28354 100644 (file)
@@ -26,9 +26,4 @@ extern void srom_free_vars(struct si_pub *sih);
 extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
                     uint byteoff, uint nbytes, u16 *buf, bool check_crc);
 
-/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP
- *   and extract from it into name=value pairs
- */
-extern int srom_parsecis(u8 **pcis, uint ciscnt,
-                        char **vars, uint *count);
 #endif                         /* _BRCM_SROM_H_ */
index f27c489108273281f96f5d2c3be8bd1c9ee70bf4..b7537f70a79538fab66fd48183179c4b78a2f78a 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/module.h>
+
 #include <brcmu_utils.h>
 
 MODULE_AUTHOR("Broadcom Corporation");
@@ -40,74 +41,20 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
 /* Free the driver packet. Free the tag if present */
 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
 {
-       struct sk_buff *nskb;
-       int nest = 0;
-
-       /* perversion: we use skb->next to chain multi-skb packets */
-       while (skb) {
-               nskb = skb->next;
-               skb->next = NULL;
-
-               if (skb->destructor)
-                       /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
-                        * destructor exists
-                        */
-                       dev_kfree_skb_any(skb);
-               else
-                       /* can free immediately (even in_irq()) if destructor
-                        * does not exist
-                        */
-                       dev_kfree_skb(skb);
-
-               nest++;
-               skb = nskb;
-       }
+       WARN_ON(skb->next);
+       if (skb->destructor)
+               /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
+                * destructor exists
+                */
+               dev_kfree_skb_any(skb);
+       else
+               /* can free immediately (even in_irq()) if destructor
+                * does not exist
+                */
+               dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
 
-
-/* copy a buffer into a pkt buffer chain */
-uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
-               unsigned char *buf)
-{
-       uint n, ret = 0;
-
-       /* skip 'offset' bytes */
-       for (; p && offset; p = p->next) {
-               if (offset < (uint) (p->len))
-                       break;
-               offset -= p->len;
-       }
-
-       if (!p)
-               return 0;
-
-       /* copy the data */
-       for (; p && len; p = p->next) {
-               n = min((uint) (p->len) - offset, (uint) len);
-               memcpy(p->data + offset, buf, n);
-               buf += n;
-               len -= n;
-               ret += n;
-               offset = 0;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(brcmu_pktfrombuf);
-
-/* return total length of buffer chain */
-uint brcmu_pkttotlen(struct sk_buff *p)
-{
-       uint total;
-
-       total = 0;
-       for (; p; p = p->next)
-               total += p->len;
-       return total;
-}
-EXPORT_SYMBOL(brcmu_pkttotlen);
-
 /*
  * osl multiple-precedence packet queue
  * hi_prec is always >= the number of the highest non-empty precedence
@@ -115,21 +62,13 @@ EXPORT_SYMBOL(brcmu_pkttotlen);
 struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
                                      struct sk_buff *p)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
 
        if (pktq_full(pq) || pktq_pfull(pq, prec))
                return NULL;
 
-       q = &pq->q[prec];
-
-       if (q->head)
-               q->tail->prev = p;
-       else
-               q->head = p;
-
-       q->tail = p;
-       q->len++;
-
+       q = &pq->q[prec].skblist;
+       skb_queue_tail(q, p);
        pq->len++;
 
        if (pq->hi_prec < prec)
@@ -142,20 +81,13 @@ EXPORT_SYMBOL(brcmu_pktq_penq);
 struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
                                           struct sk_buff *p)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
 
        if (pktq_full(pq) || pktq_pfull(pq, prec))
                return NULL;
 
-       q = &pq->q[prec];
-
-       if (q->head == NULL)
-               q->tail = p;
-
-       p->prev = q->head;
-       q->head = p;
-       q->len++;
-
+       q = &pq->q[prec].skblist;
+       skb_queue_head(q, p);
        pq->len++;
 
        if (pq->hi_prec < prec)
@@ -167,53 +99,30 @@ EXPORT_SYMBOL(brcmu_pktq_penq_head);
 
 struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
        struct sk_buff *p;
 
-       q = &pq->q[prec];
-
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue(q);
        if (p == NULL)
                return NULL;
 
-       q->head = p->prev;
-       if (q->head == NULL)
-               q->tail = NULL;
-
-       q->len--;
-
        pq->len--;
-
-       p->prev = NULL;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq);
 
 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
 {
-       struct pktq_prec *q;
-       struct sk_buff *p, *prev;
-
-       q = &pq->q[prec];
+       struct sk_buff_head *q;
+       struct sk_buff *p;
 
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue_tail(q);
        if (p == NULL)
                return NULL;
 
-       for (prev = NULL; p != q->tail; p = p->prev)
-               prev = p;
-
-       if (prev)
-               prev->prev = NULL;
-       else
-               q->head = NULL;
-
-       q->tail = prev;
-       q->len--;
-
        pq->len--;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
@@ -222,31 +131,17 @@ void
 brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
                  bool (*fn)(struct sk_buff *, void *), void *arg)
 {
-       struct pktq_prec *q;
-       struct sk_buff *p, *prev = NULL;
+       struct sk_buff_head *q;
+       struct sk_buff *p, *next;
 
-       q = &pq->q[prec];
-       p = q->head;
-       while (p) {
+       q = &pq->q[prec].skblist;
+       skb_queue_walk_safe(q, p, next) {
                if (fn == NULL || (*fn) (p, arg)) {
-                       bool head = (p == q->head);
-                       if (head)
-                               q->head = p->prev;
-                       else
-                               prev->prev = p->prev;
-                       p->prev = NULL;
+                       skb_unlink(p, q);
                        brcmu_pkt_buf_free_skb(p);
-                       q->len--;
                        pq->len--;
-                       p = (head ? q->head : prev->prev);
-               } else {
-                       prev = p;
-                       p = p->prev;
                }
        }
-
-       if (q->head == NULL)
-               q->tail = NULL;
 }
 EXPORT_SYMBOL(brcmu_pktq_pflush);
 
@@ -271,8 +166,10 @@ void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
 
        pq->max = (u16) max_len;
 
-       for (prec = 0; prec < num_prec; prec++)
+       for (prec = 0; prec < num_prec; prec++) {
                pq->q[prec].max = pq->max;
+               skb_queue_head_init(&pq->q[prec].skblist);
+       }
 }
 EXPORT_SYMBOL(brcmu_pktq_init);
 
@@ -284,13 +181,13 @@ struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
                return NULL;
 
        for (prec = 0; prec < pq->hi_prec; prec++)
-               if (pq->q[prec].head)
+               if (!skb_queue_empty(&pq->q[prec].skblist))
                        break;
 
        if (prec_out)
                *prec_out = prec;
 
-       return pq->q[prec].tail;
+       return skb_peek_tail(&pq->q[prec].skblist);
 }
 EXPORT_SYMBOL(brcmu_pktq_peek_tail);
 
@@ -303,7 +200,7 @@ int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
 
        for (prec = 0; prec <= pq->hi_prec; prec++)
                if (prec_bmp & (1 << prec))
-                       len += pq->q[prec].len;
+                       len += pq->q[prec].skblist.qlen;
 
        return len;
 }
@@ -313,39 +210,32 @@ EXPORT_SYMBOL(brcmu_pktq_mlen);
 struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
                                      int *prec_out)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
        struct sk_buff *p;
        int prec;
 
        if (pq->len == 0)
                return NULL;
 
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
+       while ((prec = pq->hi_prec) > 0 &&
+              skb_queue_empty(&pq->q[prec].skblist))
                pq->hi_prec--;
 
-       while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
+       while ((prec_bmp & (1 << prec)) == 0 ||
+              skb_queue_empty(&pq->q[prec].skblist))
                if (prec-- == 0)
                        return NULL;
 
-       q = &pq->q[prec];
-
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue(q);
        if (p == NULL)
                return NULL;
 
-       q->head = p->prev;
-       if (q->head == NULL)
-               q->tail = NULL;
-
-       q->len--;
+       pq->len--;
 
        if (prec_out)
                *prec_out = prec;
 
-       pq->len--;
-
-       p->prev = NULL;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_mdeq);
@@ -364,23 +254,3 @@ void brcmu_prpkt(const char *msg, struct sk_buff *p0)
 }
 EXPORT_SYMBOL(brcmu_prpkt);
 #endif                         /* defined(BCMDBG) */
-
-#if defined(BCMDBG)
-/*
- * print bytes formatted as hex to a string. return the resulting
- * string length
- */
-int brcmu_format_hex(char *str, const void *bytes, int len)
-{
-       int i;
-       char *p = str;
-       const u8 *src = (const u8 *)bytes;
-
-       for (i = 0; i < len; i++) {
-               p += snprintf(p, 3, "%02X", *src);
-               src++;
-       }
-       return (int)(p - str);
-}
-EXPORT_SYMBOL(brcmu_format_hex);
-#endif                         /* defined(BCMDBG) */
index 7d0f46e0eb95a071d4f40ab16fefcb6cfb7c2570..ad249a0b4730ebea6eec5cd2f2bdfbb355fe232a 100644 (file)
@@ -65,9 +65,7 @@
 #define ETHER_ADDR_STR_LEN     18
 
 struct pktq_prec {
-       struct sk_buff *head;   /* first packet to dequeue */
-       struct sk_buff *tail;   /* last packet to dequeue */
-       u16 len;                /* number of queued packets */
+       struct sk_buff_head skblist;
        u16 max;                /* maximum number of queued packets */
 };
 
@@ -88,32 +86,32 @@ struct pktq {
 
 static inline int pktq_plen(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len;
+       return pq->q[prec].skblist.qlen;
 }
 
 static inline int pktq_pavail(struct pktq *pq, int prec)
 {
-       return pq->q[prec].max - pq->q[prec].len;
+       return pq->q[prec].max - pq->q[prec].skblist.qlen;
 }
 
 static inline bool pktq_pfull(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len >= pq->q[prec].max;
+       return pq->q[prec].skblist.qlen >= pq->q[prec].max;
 }
 
 static inline bool pktq_pempty(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len == 0;
+       return skb_queue_empty(&pq->q[prec].skblist);
 }
 
 static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec)
 {
-       return pq->q[prec].head;
+       return skb_peek(&pq->q[prec].skblist);
 }
 
 static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec)
 {
-       return pq->q[prec].tail;
+       return skb_peek_tail(&pq->q[prec].skblist);
 }
 
 extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
@@ -172,24 +170,16 @@ extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
                bool (*fn)(struct sk_buff *, void *), void *arg);
 
 /* externs */
-/* packet */
-extern uint brcmu_pktfrombuf(struct sk_buff *p,
-       uint offset, int len, unsigned char *buf);
-extern uint brcmu_pkttotlen(struct sk_buff *p);
-
 /* ip address */
 struct ipv4_addr;
 
+
+/* externs */
+/* format/print */
 #ifdef BCMDBG
 extern void brcmu_prpkt(const char *msg, struct sk_buff *p0);
 #else
 #define brcmu_prpkt(a, b)
 #endif                         /* BCMDBG */
 
-/* externs */
-/* format/print */
-#if defined(BCMDBG)
-extern int brcmu_format_hex(char *str, const void *bytes, int len);
-#endif
-
 #endif                         /* _BRCMU_UTILS_H_ */
index 1e5f310af1e77e10e341e8fe26872f4bd6db592a..f0d8c04a9c8cd13b03962b8855acdc69f8913b35 100644 (file)
@@ -62,7 +62,6 @@
 
 #define WL_RADIO_SW_DISABLE            (1<<0)
 #define WL_RADIO_HW_DISABLE            (1<<1)
-#define WL_RADIO_MPC_DISABLE           (1<<2)
 /* some countries don't support any channel */
 #define WL_RADIO_COUNTRY_DISABLE       (1<<3)
 
index 4fcb956ad9e03633ed01589e4adade6f05919eb0..4e9b7e4827ea88c845a7869835763849cd2db57e 100644 (file)
@@ -77,8 +77,9 @@
 #define        DMEMS_CORE_ID           0x835   /* SDR/DDR1 memory controller core */
 #define        DEF_SHIM_COMP           0x837   /* SHIM component in ubus/6362 */
 #define OOB_ROUTER_CORE_ID     0x367   /* OOB router core ID */
-/* Default component, in ai chips it maps all unused address ranges */
-#define        DEF_AI_COMP             0xfff
+#define        DEF_AI_COMP             0xfff   /* Default component, in ai chips it
+                                        * maps all unused address ranges
+                                        */
 
 /* Common core control flags */
 #define        SICF_BIST_EN            0x8000
 #define        SICF_FGC                0x0002
 #define        SICF_CLOCK_EN           0x0001
 
+/* Common core status flags */
+#define        SISF_BIST_DONE          0x8000
+#define        SISF_BIST_ERROR         0x4000
+#define        SISF_GATED_CLK          0x2000
+#define        SISF_DMA64              0x1000
+#define        SISF_CORE_BITS          0x0fff
+
 #endif                         /* _BRCM_SOC_H */
index 99a710dfe77106d83a61d795aebe90a68297a4ea..99575884ff525af70d69186ad625b55fb7d6dbdf 100644 (file)
@@ -131,6 +131,14 @@ static struct ieee80211_rate ipw2200_rates[] = {
 #define ipw2200_bg_rates       (ipw2200_rates + 0)
 #define ipw2200_num_bg_rates   12
 
+/* Ugly macro to convert literal channel numbers into their mhz equivalents
+ * There are certianly some conditions that will break this (like feeding it '30')
+ * but they shouldn't arise since nothing talks on channel 30. */
+#define ieee80211chan2mhz(x) \
+       (((x) <= 14) ? \
+       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
+       ((x) + 1000) * 5)
+
 #ifdef CONFIG_IPW2200_QOS
 static int qos_enable = 0;
 static int qos_burst_enable = 0;
index 70f5586d96bdeb060195763d8409fb4f64c27458..3d5821eeb05491327bda8a8a74c583722ca375cb 100644 (file)
@@ -66,16 +66,8 @@ extern u32 libipw_debug_level;
 do { if (libipw_debug_level & (level)) \
   printk(KERN_DEBUG "libipw: %c %s " fmt, \
          in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
-static inline bool libipw_ratelimit_debug(u32 level)
-{
-       return (libipw_debug_level & level) && net_ratelimit();
-}
 #else
 #define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
-static inline bool libipw_ratelimit_debug(u32 level)
-{
-       return false;
-}
 #endif                         /* CONFIG_LIBIPW_DEBUG */
 
 /*
index c73e5ed8db5e6994651358ac13f8da9b4d84f6d9..a7ab280994c8105e74aa61f0cec84a99449aa4eb 100644 (file)
@@ -1,6 +1,6 @@
 # WIFI
 obj-$(CONFIG_IWLWIFI)  += iwlwifi.o
-iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o
+iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
 iwlwifi-objs           += iwl-agn-ucode.o iwl-agn-tx.o
 iwlwifi-objs           += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
 iwlwifi-objs           += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
index 79431977a968583d8fb155fcc3c8fd5ea76bd6c7..b3193571ed07b3797f9e05783956a57384a63d06 100644 (file)
@@ -270,11 +270,6 @@ struct iwl_cfg iwl2000_2bgn_cfg = {
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2000_2bg_cfg = {
-       .name = "2000 Series 2x2 BG",
-       IWL_DEVICE_2000,
-};
-
 struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .name = "2000D Series 2x2 BGN",
        IWL_DEVICE_2000,
@@ -304,11 +299,6 @@ struct iwl_cfg iwl2030_2bgn_cfg = {
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2030_2bg_cfg = {
-       .name = "2000 Series 2x2 BG/BT",
-       IWL_DEVICE_2030,
-};
-
 #define IWL_DEVICE_105                                         \
        .fw_name_pre = IWL105_FW_PRE,                           \
        .ucode_api_max = IWL105_UCODE_API_MAX,                  \
@@ -326,11 +316,6 @@ struct iwl_cfg iwl2030_2bg_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl105_bg_cfg = {
-       .name = "105 Series 1x1 BG",
-       IWL_DEVICE_105,
-};
-
 struct iwl_cfg iwl105_bgn_cfg = {
        .name = "105 Series 1x1 BGN",
        IWL_DEVICE_105,
@@ -361,11 +346,6 @@ struct iwl_cfg iwl105_bgn_d_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl135_bg_cfg = {
-       .name = "135 Series 1x1 BG/BT",
-       IWL_DEVICE_135,
-};
-
 struct iwl_cfg iwl135_bgn_cfg = {
        .name = "135 Series 1x1 BGN/BT",
        IWL_DEVICE_135,
index c840c78278db89e977854c16756a129db4a97f94..ee3363fdf309d8881d47849154a2a567720ec271 100644 (file)
@@ -439,16 +439,6 @@ struct iwl_cfg iwl6035_2agn_cfg = {
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6035_2abg_cfg = {
-       .name = "6035 Series 2x2 ABG/BT",
-       IWL_DEVICE_6030,
-};
-
-struct iwl_cfg iwl6035_2bg_cfg = {
-       .name = "6035 Series 2x2 BG/BT",
-       IWL_DEVICE_6030,
-};
-
 struct iwl_cfg iwl1030_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
        IWL_DEVICE_6030,
index 1a52ed29f2d64e4425552e603534dc0f1f16a54f..0bc9622173510580b27892737b4ca03fad74ab52 100644 (file)
@@ -827,6 +827,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
        case IEEE80211_SMPS_STATIC:
        case IEEE80211_SMPS_DYNAMIC:
                return IWL_NUM_IDLE_CHAINS_SINGLE;
+       case IEEE80211_SMPS_AUTOMATIC:
        case IEEE80211_SMPS_OFF:
                return active_cnt;
        default:
@@ -983,3 +984,360 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
        list_del(&wait_entry->list);
        spin_unlock_bh(&priv->notif_wait_lock);
 }
+
+#ifdef CONFIG_PM_SLEEP
+static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
+{
+       int i;
+
+       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
+               out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+       struct iwl_rxon_context *ctx;
+       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+       struct iwlagn_wowlan_tkip_params_cmd *tkip;
+       const u8 *bssid;
+       bool error, use_rsc_tsc, use_tkip;
+};
+
+
+static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              struct ieee80211_key_conf *key,
+                              void *_data)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct wowlan_key_data *data = _data;
+       struct iwl_rxon_context *ctx = data->ctx;
+       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+       struct iwlagn_p1k_cache *rx_p1ks;
+       u8 *rx_mic_key;
+       struct ieee80211_key_seq seq;
+       u32 cur_rx_iv32 = 0;
+       u16 p1k[IWLAGN_P1K_SIZE];
+       int ret, i;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+            !sta && !ctx->key_mapping_keys)
+               ret = iwl_set_default_wep_key(priv, ctx, key);
+       else
+               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+
+       if (ret) {
+               IWL_ERR(priv, "Error setting key during suspend!\n");
+               data->error = true;
+       }
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (sta) {
+                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+                       rx_p1ks = data->tkip->rx_uni;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
+
+                       memcpy(data->tkip->mic_keys.tx,
+                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+                              IWLAGN_MIC_KEY_SIZE);
+
+                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
+               } else {
+                       tkip_sc =
+                               data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+                       rx_p1ks = data->tkip->rx_multi;
+                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
+               }
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 (as they need to to avoid replay attacks)
+                * for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+                       /* wrapping isn't allowed, AP must rekey */
+                       if (seq.tkip.iv32 > cur_rx_iv32)
+                               cur_rx_iv32 = seq.tkip.iv32;
+               }
+
+               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
+               ieee80211_get_tkip_rx_p1k(key, data->bssid,
+                                         cur_rx_iv32 + 1, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+               memcpy(rx_mic_key,
+                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+                      IWLAGN_MIC_KEY_SIZE);
+
+               data->use_tkip = true;
+               data->use_rsc_tsc = true;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               if (sta) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       aes_tx_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               } else
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       aes_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               }
+               data->use_rsc_tsc = true;
+               break;
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+}
+
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                       struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_WOWLAN_PATTERNS,
+               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+               .flags = CMD_SYNC,
+       };
+       int i, err;
+
+       if (!wowlan->n_patterns)
+               return 0;
+
+       cmd.len[0] = sizeof(*pattern_cmd) +
+               wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+
+       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+       if (!pattern_cmd)
+               return -ENOMEM;
+
+       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+       for (i = 0; i < wowlan->n_patterns; i++) {
+               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+               memcpy(&pattern_cmd->patterns[i].mask,
+                       wowlan->patterns[i].mask, mask_len);
+               memcpy(&pattern_cmd->patterns[i].pattern,
+                       wowlan->patterns[i].pattern,
+                       wowlan->patterns[i].pattern_len);
+               pattern_cmd->patterns[i].mask_size = mask_len;
+               pattern_cmd->patterns[i].pattern_size =
+                       wowlan->patterns[i].pattern_len;
+       }
+
+       cmd.data[0] = pattern_cmd;
+       err = iwl_trans_send_cmd(trans(priv), &cmd);
+       kfree(pattern_cmd);
+       return err;
+}
+
+int iwlagn_suspend(struct iwl_priv *priv,
+               struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
+       struct iwl_rxon_cmd rxon;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
+       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
+       struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
+       struct wowlan_key_data key_data = {
+               .ctx = ctx,
+               .bssid = ctx->active.bssid_addr,
+               .use_rsc_tsc = false,
+               .tkip = &tkip_cmd,
+               .use_tkip = false,
+       };
+       int ret, i;
+       u16 seq;
+
+       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+       if (!key_data.rsc_tsc)
+               return -ENOMEM;
+
+       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
+
+       /*
+        * We know the last used seqno, and the uCode expects to know that
+        * one, it will increment before TX.
+        */
+       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
+       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
+
+       /*
+        * For QoS counters, we store the one to use next, so subtract 0x10
+        * since the uCode will add 0x10 before using the value.
+        */
+       for (i = 0; i < 8; i++) {
+               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
+               seq -= 0x10;
+               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
+       }
+
+       if (wowlan->disconnect)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
+       if (wowlan->magic_pkt)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
+       if (wowlan->gtk_rekey_failure)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+       if (wowlan->eap_identity_req)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+       if (wowlan->four_way_handshake)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+       if (wowlan->n_patterns)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+       if (wowlan->rfkill_release)
+               d3_cfg_cmd.wakeup_flags |=
+                       cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
+
+       iwl_scan_cancel_timeout(priv, 200);
+
+       memcpy(&rxon, &ctx->active, sizeof(rxon));
+
+       iwl_trans_stop_device(trans(priv));
+
+       priv->shrd->wowlan = true;
+
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+       if (ret)
+               goto out;
+
+       /* now configure WoWLAN ucode */
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto out;
+
+       memcpy(&ctx->staging, &rxon, sizeof(rxon));
+       ret = iwlagn_commit_rxon(priv, ctx);
+       if (ret)
+               goto out;
+
+       ret = iwl_power_update_mode(priv, true);
+       if (ret)
+               goto out;
+
+       if (!iwlagn_mod_params.sw_crypto) {
+               /* mark all keys clear */
+               priv->ucode_key_table = 0;
+               ctx->key_mapping_keys = 0;
+
+               /*
+                * This needs to be unlocked due to lock ordering
+                * constraints. Since we're in the suspend path
+                * that isn't really a problem though.
+                */
+               mutex_unlock(&priv->shrd->mutex);
+               ieee80211_iter_keys(priv->hw, ctx->vif,
+                                   iwlagn_wowlan_program_keys,
+                                   &key_data);
+               mutex_lock(&priv->shrd->mutex);
+               if (key_data.error) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               if (key_data.use_rsc_tsc) {
+                       struct iwl_host_cmd rsc_tsc_cmd = {
+                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
+                               .flags = CMD_SYNC,
+                               .data[0] = key_data.rsc_tsc,
+                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+                               .len[0] = sizeof(key_data.rsc_tsc),
+                       };
+
+                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (key_data.use_tkip) {
+                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                                                REPLY_WOWLAN_TKIP_PARAMS,
+                                                CMD_SYNC, sizeof(tkip_cmd),
+                                                &tkip_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (priv->have_rekey_data) {
+                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
+                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
+                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
+
+                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
+                                                CMD_SYNC, sizeof(kek_kck_cmd),
+                                                &kek_kck_cmd);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC,
+                                    sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
+                                CMD_SYNC, sizeof(wakeup_filter_cmd),
+                                &wakeup_filter_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwlagn_send_patterns(priv, wowlan);
+ out:
+       kfree(key_data.rsc_tsc);
+       return ret;
+}
+#endif
index 66118cea2af343d3f97a0b4fe52cfc7c7e093769..359c47a4fcea457841c57e702910d4400797a22d 100644 (file)
@@ -1458,10 +1458,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               valid_tx_ant =
-                       first_antenna(hw_params(priv).valid_tx_ant);
                if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
-                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
@@ -1636,10 +1634,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               valid_tx_ant =
-                       first_antenna(hw_params(priv).valid_tx_ant);
                if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
-                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
index 5af9e6258a16a07ab21e42480b17199991ffd88e..fdb4c3786114d799dd890ca24c3b883a241a8c7e 100644 (file)
@@ -800,7 +800,8 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
                                               ctx->active.bssid_addr))
                                continue;
                        ctx->last_tx_rejected = false;
-                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid);
+                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid,
+                               "channel got active");
                }
        }
 
@@ -1032,6 +1033,50 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
        return 0;
 }
 
+static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb,
+                                     struct iwl_device_cmd *cmd)
+{
+       struct iwl_wipan_noa_data *new_data, *old_data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->u.raw;
+
+       /* no condition -- we're in softirq */
+       old_data = rcu_dereference_protected(priv->noa_data, true);
+
+       if (noa_notif->noa_active) {
+               u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
+               u32 copylen = len;
+
+               /* EID, len, OUI, subtype */
+               len += 1 + 1 + 3 + 1;
+               /* P2P id, P2P length */
+               len += 1 + 2;
+               copylen += 1 + 2;
+
+               new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
+               if (new_data) {
+                       new_data->length = len;
+                       new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
+                       new_data->data[1] = len - 2; /* not counting EID, len */
+                       new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+                       new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+                       new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+                       new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
+                       memcpy(&new_data->data[6], &noa_notif->noa_attribute,
+                              copylen);
+               }
+       } else
+               new_data = NULL;
+
+       rcu_assign_pointer(priv->noa_data, new_data);
+
+       if (old_data)
+               kfree_rcu(old_data, rcu_head);
+
+       return 0;
+}
+
 /**
  * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
@@ -1055,6 +1100,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
        handlers[BEACON_NOTIFICATION]           = iwlagn_rx_beacon_notif;
        handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
 
+       handlers[REPLY_WIPAN_NOA_NOTIFICATION]  = iwlagn_rx_noa_notification;
+
        /*
         * The same handler is used for both the REPLY to a discrete
         * statistics request from the host as well as for the periodic
index 58a381c01c89c9a367c7b592d65a49eb02457be0..8de97f5a1825f2f5818041f1f9bf6c7e3dc0a54a 100644 (file)
@@ -45,7 +45,8 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
        send->filter_flags = old_filter;
 
        if (ret)
-               IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
+               IWL_DEBUG_QUIET_RFKILL(priv,
+                       "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
 
        return ret;
 }
@@ -116,7 +117,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
        if (ctx->ht.enabled)
                ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
-       IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+       IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
                      ctx->qos_data.qos_active,
                      ctx->qos_data.def_qos_parm.qos_flags);
 
@@ -124,7 +125,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
                               sizeof(struct iwl_qosparam_cmd),
                               &ctx->qos_data.def_qos_parm);
        if (ret)
-               IWL_ERR(priv, "Failed to update QoS\n");
+               IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
 }
 
 static int iwlagn_update_beacon(struct iwl_priv *priv,
@@ -541,6 +542,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&priv->shrd->mutex);
 
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+               goto out;
+
        if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) {
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
                goto out;
@@ -840,7 +844,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        if (ctx->last_tx_rejected) {
                                ctx->last_tx_rejected = false;
                                iwl_trans_wake_any_queue(trans(priv),
-                                                        ctx->ctxid);
+                                                        ctx->ctxid,
+                                                        "Disassoc: flush queue");
                        }
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
index ed6283623932e2436ddc364d8429ee085df28249..901fd9485d757b216fd959b1aaa20849494a27a5 100644 (file)
@@ -647,7 +647,7 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        int ret;
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
-       bool active;
+       bool active, have_lq = false;
 
        spin_lock_irqsave(&priv->shrd->sta_lock, flags);
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
@@ -657,7 +657,10 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
        sta_cmd.mode = 0;
-       memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+       if (priv->stations[sta_id].lq) {
+               memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+               have_lq = true;
+       }
 
        active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
@@ -679,7 +682,8 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (ret)
                IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
                        priv->stations[sta_id].sta.sta.addr, ret);
-       iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
+       if (have_lq)
+               iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
 }
 
 int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
@@ -825,28 +829,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        return ret;
 }
 
-int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
-                          "station %pM\n", sta->addr);
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
-                       sta->addr);
-       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
-       if (ret)
-               IWL_ERR(priv, "Error removing station %pM\n",
-                       sta->addr);
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
 
 void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                     u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
@@ -1464,20 +1446,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-       unsigned long flags;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
-       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
-       priv->stations[sta_id].sta.sta.modify_mask = 0;
-       priv->stations[sta_id].sta.sleep_tx_count = 0;
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-
-}
 
 void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 {
@@ -1494,36 +1463,3 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
        spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
 
 }
-
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       switch (cmd) {
-       case STA_NOTIFY_SLEEP:
-               WARN_ON(!sta_priv->client);
-               sta_priv->asleep = true;
-               if (atomic_read(&sta_priv->pending_frames) > 0)
-                       ieee80211_sta_block_awake(hw, sta, true);
-               break;
-       case STA_NOTIFY_AWAKE:
-               WARN_ON(!sta_priv->client);
-               if (!sta_priv->asleep)
-                       break;
-               sta_priv->asleep = false;
-               sta_id = iwl_sta_id(sta);
-               if (sta_id != IWL_INVALID_STATION)
-                       iwl_sta_modify_ps_wake(priv, sta_id);
-               break;
-       default:
-               break;
-       }
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
index 35a6b71f358ce7a563f6507b58f0743eb6ded16a..e6a02e09ee18e1115ef83986e3bfaa998ec6d383 100644 (file)
@@ -283,6 +283,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
 #endif
 
+       if (unlikely(ieee80211_is_probe_resp(fc))) {
+               struct iwl_wipan_noa_data *noa_data =
+                       rcu_dereference(priv->noa_data);
+
+               if (noa_data &&
+                   pskb_expand_head(skb, 0, noa_data->length,
+                                    GFP_ATOMIC) == 0) {
+                       memcpy(skb_put(skb, noa_data->length),
+                              noa_data->data, noa_data->length);
+                       hdr = (struct ieee80211_hdr *)skb->data;
+               }
+       }
+
        hdr_len = ieee80211_hdrlen(fc);
 
        /* For management frames use broadcast id to do not break aggregation */
@@ -800,7 +813,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                            iwl_is_associated_ctx(ctx) && ctx->vif &&
                            ctx->vif->type == NL80211_IFTYPE_STATION) {
                                ctx->last_tx_rejected = true;
-                               iwl_trans_stop_queue(trans(priv), txq_id);
+                               iwl_trans_stop_queue(trans(priv), txq_id,
+                                       "Tx on passive channel");
 
                                IWL_DEBUG_TX_REPLY(priv,
                                           "TXQ %d status %s (0x%08x) "
index 8ba0dd54e37d4faee68bb900a1e99fb5de6543d6..9ec315b31d453cb0b9d71531ba060b9a23ff27d8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/dma-mapping.h>
 
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -72,51 +73,98 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
 };
 
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_free_fw_desc(struct iwl_bus *bus, struct fw_desc *desc)
+{
+       if (desc->v_addr)
+               dma_free_coherent(bus->dev, desc->len,
+                                 desc->v_addr, desc->p_addr);
+       desc->v_addr = NULL;
+       desc->len = 0;
+}
+
+static void iwl_free_fw_img(struct iwl_bus *bus, struct fw_img *img)
+{
+       iwl_free_fw_desc(bus, &img->code);
+       iwl_free_fw_desc(bus, &img->data);
+}
+
+void iwl_dealloc_ucode(struct iwl_trans *trans)
+{
+       iwl_free_fw_img(bus(trans), &trans->ucode_rt);
+       iwl_free_fw_img(bus(trans), &trans->ucode_init);
+       iwl_free_fw_img(bus(trans), &trans->ucode_wowlan);
+}
+
+int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
+                     const void *data, size_t len)
+{
+       if (!len) {
+               desc->v_addr = NULL;
+               return -EINVAL;
+       }
+
+       desc->v_addr = dma_alloc_coherent(bus->dev, len,
+                                         &desc->p_addr, GFP_KERNEL);
+       if (!desc->v_addr)
+               return -ENOMEM;
+
+       desc->len = len;
+       memcpy(desc->v_addr, data, len);
+       return 0;
+}
+
 /*
  * ucode
  */
-static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
+static int iwlagn_load_section(struct iwl_trans *trans, const char *name,
                                struct fw_desc *image, u32 dst_addr)
 {
+       struct iwl_bus *bus = bus(trans);
        dma_addr_t phy_addr = image->p_addr;
        u32 byte_cnt = image->len;
        int ret;
 
-       priv->ucode_write_complete = 0;
+       trans->ucode_write_complete = 0;
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
                phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
                (iwl_get_dma_hi_addr(phy_addr)
                        << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
                1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
                1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
                FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
-       IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name);
-       ret = wait_event_timeout(priv->shrd->wait_command_queue,
-                                priv->ucode_write_complete, 5 * HZ);
+       IWL_DEBUG_FW(bus, "%s uCode section being loaded...\n", name);
+       ret = wait_event_timeout(trans->shrd->wait_command_queue,
+                                trans->ucode_write_complete, 5 * HZ);
        if (!ret) {
-               IWL_ERR(priv, "Could not load the %s uCode section\n",
+               IWL_ERR(trans, "Could not load the %s uCode section\n",
                        name);
                return -ETIMEDOUT;
        }
@@ -124,17 +172,41 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
        return 0;
 }
 
-static int iwlagn_load_given_ucode(struct iwl_priv *priv,
-                                  struct fw_img *image)
+static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
+                                       enum iwl_ucode_type ucode_type)
+{
+       switch (ucode_type) {
+       case IWL_UCODE_INIT:
+               return &trans->ucode_init;
+       case IWL_UCODE_WOWLAN:
+               return &trans->ucode_wowlan;
+       case IWL_UCODE_REGULAR:
+               return &trans->ucode_rt;
+       case IWL_UCODE_NONE:
+               break;
+       }
+       return NULL;
+}
+
+static int iwlagn_load_given_ucode(struct iwl_trans *trans,
+                                  enum iwl_ucode_type ucode_type)
 {
        int ret = 0;
+       struct fw_img *image = iwl_get_ucode_image(trans, ucode_type);
+
+
+       if (!image) {
+               IWL_ERR(trans, "Invalid ucode requested (%d)\n",
+                       ucode_type);
+               return -EINVAL;
+       }
 
-       ret = iwlagn_load_section(priv, "INST", &image->code,
+       ret = iwlagn_load_section(trans, "INST", &image->code,
                                   IWLAGN_RTC_INST_LOWER_BOUND);
        if (ret)
                return ret;
 
-       return iwlagn_load_section(priv, "DATA", &image->data,
+       return iwlagn_load_section(trans, "DATA", &image->data,
                                    IWLAGN_RTC_DATA_LOWER_BOUND);
 }
 
@@ -418,7 +490,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwl_verify_inst_sparse(struct iwl_priv *priv,
+static int iwl_verify_inst_sparse(struct iwl_bus *bus,
                                      struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
@@ -426,15 +498,15 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
        u32 val;
        u32 i;
 
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len);
 
        for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
                /* read data comes through single port, auto-incr addr */
                /* NOTE: Use the debugless read so we don't flood kernel log
                 * if IWL_DL_IO is set */
-               iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
+               iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR,
                        i + IWLAGN_RTC_INST_LOWER_BOUND);
-               val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image))
                        return -EIO;
        }
@@ -442,7 +514,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
        return 0;
 }
 
-static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+static void iwl_print_mismatch_inst(struct iwl_bus *bus,
                                    struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
@@ -451,18 +523,18 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
        u32 offs;
        int errors = 0;
 
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len);
 
-       iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
+       iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR,
                           IWLAGN_RTC_INST_LOWER_BOUND);
 
        for (offs = 0;
             offs < len && errors < 20;
             offs += sizeof(u32), image++) {
                /* read data comes through single port, auto-incr addr */
-               val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image)) {
-                       IWL_ERR(priv, "uCode INST section at "
+                       IWL_ERR(bus, "uCode INST section at "
                                "offset 0x%x, is 0x%x, s/b 0x%x\n",
                                offs, val, le32_to_cpu(*image));
                        errors++;
@@ -474,16 +546,24 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
+static int iwl_verify_ucode(struct iwl_trans *trans,
+                           enum iwl_ucode_type ucode_type)
 {
-       if (!iwl_verify_inst_sparse(priv, &img->code)) {
-               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
+       struct fw_img *img = iwl_get_ucode_image(trans, ucode_type);
+
+       if (!img) {
+               IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type);
+               return -EINVAL;
+       }
+
+       if (!iwl_verify_inst_sparse(bus(trans), &img->code)) {
+               IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n");
                return 0;
        }
 
-       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+       IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-       iwl_print_mismatch_inst(priv, &img->code);
+       iwl_print_mismatch_inst(bus(trans), &img->code);
        return -EIO;
 }
 
@@ -519,13 +599,12 @@ static void iwlagn_alive_fn(struct iwl_priv *priv,
 #define UCODE_CALIB_TIMEOUT    (2*HZ)
 
 int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
-                                struct fw_img *image,
-                                enum iwlagn_ucode_type ucode_type)
+                                enum iwl_ucode_type ucode_type)
 {
        struct iwl_notification_wait alive_wait;
        struct iwlagn_alive_data alive_data;
        int ret;
-       enum iwlagn_ucode_type old_type;
+       enum iwl_ucode_type old_type;
 
        ret = iwl_trans_start_device(trans(priv));
        if (ret)
@@ -537,7 +616,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
        old_type = priv->ucode_type;
        priv->ucode_type = ucode_type;
 
-       ret = iwlagn_load_given_ucode(priv, image);
+       ret = iwlagn_load_given_ucode(trans(priv), ucode_type);
        if (ret) {
                priv->ucode_type = old_type;
                iwlagn_remove_notification(priv, &alive_wait);
@@ -568,7 +647,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
         * skip it for WoWLAN.
         */
        if (ucode_type != IWL_UCODE_WOWLAN) {
-               ret = iwl_verify_ucode(priv, image);
+               ret = iwl_verify_ucode(trans(priv), ucode_type);
                if (ret) {
                        priv->ucode_type = old_type;
                        return ret;
@@ -597,7 +676,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
        lockdep_assert_held(&priv->shrd->mutex);
 
        /* No init ucode required? Curious, but maybe ok */
-       if (!priv->ucode_init.code.len)
+       if (!trans(priv)->ucode_init.code.len)
                return 0;
 
        if (priv->ucode_type != IWL_UCODE_NONE)
@@ -608,8 +687,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
                                      NULL, NULL);
 
        /* Will also start the device */
-       ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
-                                          IWL_UCODE_INIT);
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
        if (ret)
                goto error;
 
index ccba69b7f8a78f9b54635328bee5c3e3d4d4553a..e235e84de8b4a5c678a2f5ad479899e9ac662901 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/skbuff.h>
@@ -452,52 +451,6 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
-/******************************************************************************
- *
- * uCode download functions
- *
- ******************************************************************************/
-
-static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc)
-{
-       if (desc->v_addr)
-               dma_free_coherent(bus(priv)->dev, desc->len,
-                                 desc->v_addr, desc->p_addr);
-       desc->v_addr = NULL;
-       desc->len = 0;
-}
-
-static void iwl_free_fw_img(struct iwl_priv *priv, struct fw_img *img)
-{
-       iwl_free_fw_desc(priv, &img->code);
-       iwl_free_fw_desc(priv, &img->data);
-}
-
-static void iwl_dealloc_ucode(struct iwl_priv *priv)
-{
-       iwl_free_fw_img(priv, &priv->ucode_rt);
-       iwl_free_fw_img(priv, &priv->ucode_init);
-       iwl_free_fw_img(priv, &priv->ucode_wowlan);
-}
-
-static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
-                            const void *data, size_t len)
-{
-       if (!len) {
-               desc->v_addr = NULL;
-               return -EINVAL;
-       }
-
-       desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len,
-                                         &desc->p_addr, GFP_KERNEL);
-       if (!desc->v_addr)
-               return -ENOMEM;
-
-       desc->len = len;
-       memcpy(desc->v_addr, data, len);
-       return 0;
-}
-
 static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
        int i;
@@ -555,16 +508,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 }
 
-
-struct iwlagn_ucode_capabilities {
-       u32 max_probe_length;
-       u32 standard_phy_calibration_size;
-       u32 flags;
-};
-
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa);
 
 #define UCODE_EXPERIMENTAL_INDEX       100
 #define UCODE_EXPERIMENTAL_TAG         "exp"
@@ -1040,30 +984,32 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
-       if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.code,
+       if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code,
                              pieces.inst, pieces.inst_size))
                goto err_pci_alloc;
-       if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.data,
+       if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.data,
                              pieces.data, pieces.data_size))
                goto err_pci_alloc;
 
        /* Initialization instructions and data */
        if (pieces.init_size && pieces.init_data_size) {
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_init.code,
+               if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code,
                                      pieces.init, pieces.init_size))
                        goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_init.data,
+               if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data,
                                      pieces.init_data, pieces.init_data_size))
                        goto err_pci_alloc;
        }
 
        /* WoWLAN instructions and data */
        if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.code,
+               if (iwl_alloc_fw_desc(bus(priv),
+                                     &trans(priv)->ucode_wowlan.code,
                                      pieces.wowlan_inst,
                                      pieces.wowlan_inst_size))
                        goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.data,
+               if (iwl_alloc_fw_desc(bus(priv),
+                                     &trans(priv)->ucode_wowlan.data,
                                      pieces.wowlan_data,
                                      pieces.wowlan_data_size))
                        goto err_pci_alloc;
@@ -1156,7 +1102,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 
  err_pci_alloc:
        IWL_ERR(priv, "failed to allocate pci memory\n");
-       iwl_dealloc_ucode(priv);
+       iwl_dealloc_ucode(trans(priv));
  out_unbind:
        complete(&priv->firmware_loading_complete);
        device_release_driver(bus(priv)->dev);
@@ -1352,7 +1298,7 @@ int iwl_alive_start(struct iwl_priv *priv)
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv);
 
-static void __iwl_down(struct iwl_priv *priv)
+void __iwl_down(struct iwl_priv *priv)
 {
        int exit_pending;
 
@@ -1415,7 +1361,7 @@ static void __iwl_down(struct iwl_priv *priv)
        priv->beacon_skb = NULL;
 }
 
-static void iwl_down(struct iwl_priv *priv)
+void iwl_down(struct iwl_priv *priv)
 {
        mutex_lock(&priv->shrd->mutex);
        __iwl_down(priv);
@@ -1424,57 +1370,6 @@ static void iwl_down(struct iwl_priv *priv)
        iwl_cancel_deferred_work(priv);
 }
 
-#define MAX_HW_RESTARTS 5
-
-static int __iwl_up(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-       int ret;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
-               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
-               return -EIO;
-       }
-
-       for_each_context(priv, ctx) {
-               ret = iwlagn_alloc_bcast_station(priv, ctx);
-               if (ret) {
-                       iwl_dealloc_bcast_stations(priv);
-                       return ret;
-               }
-       }
-
-       ret = iwlagn_run_init_ucode(priv);
-       if (ret) {
-               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwlagn_load_ucode_wait_alive(priv,
-                                          &priv->ucode_rt,
-                                          IWL_UCODE_REGULAR);
-       if (ret) {
-               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-       return 0;
-
- error:
-       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-       __iwl_down(priv);
-       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-
-       IWL_ERR(priv, "Unable to initialize device.\n");
-       return ret;
-}
-
-
 /*****************************************************************************
  *
  * Workqueue callbacks
@@ -1502,7 +1397,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        mutex_unlock(&priv->shrd->mutex);
 }
 
-static void iwlagn_prepare_restart(struct iwl_priv *priv)
+void iwlagn_prepare_restart(struct iwl_priv *priv)
 {
        struct iwl_rxon_context *ctx;
        bool bt_full_concurrent;
@@ -1559,1499 +1454,180 @@ static void iwl_bg_restart(struct work_struct *data)
        }
 }
 
-/*****************************************************************************
- *
- * mac80211 entry point functions
- *
- *****************************************************************************/
-
-static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_GO) |
-                        BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
-       },
-};
 
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_dualmode[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_sta_ap_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
-       },
-};
 
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_p2p[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_p2p_sta_go_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_p2p_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
-       },
-};
 
-/*
- * Not a mac80211 entry point function, but it fits in with all the
- * other mac80211 functions grouped here.
- */
-static int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa)
+void iwlagn_disable_roc(struct iwl_priv *priv)
 {
-       int ret;
-       struct ieee80211_hw *hw = priv->hw;
-       struct iwl_rxon_context *ctx;
-
-       hw->rate_control_algorithm = "iwl-agn-rs";
-
-       /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_NEED_DTIM_PERIOD |
-                   IEEE80211_HW_SPECTRUM_MGMT |
-                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
-
-       /*
-        * Including the following line will crash some AP's.  This
-        * workaround removes the stimulus which causes the crash until
-        * the AP software can be fixed.
-       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-        */
-
-       hw->flags |= IEEE80211_HW_SUPPORTS_PS |
-                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
-
-       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
-               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
-
-       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
-               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
-       hw->sta_data_size = sizeof(struct iwl_station_priv);
-       hw->vif_data_size = sizeof(struct iwl_vif_priv);
-
-       for_each_context(priv, ctx) {
-               hw->wiphy->interface_modes |= ctx->interface_modes;
-               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
-       }
-
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
-       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
-       }
-
-       hw->wiphy->max_remain_on_channel_duration = 1000;
-
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
-
-       if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) {
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT |
-                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                         WIPHY_WOWLAN_RFKILL_RELEASE;
-               if (!iwlagn_mod_params.sw_crypto)
-                       hw->wiphy->wowlan.flags |=
-                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
-
-               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
-               hw->wiphy->wowlan.pattern_min_len =
-                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
-               hw->wiphy->wowlan.pattern_max_len =
-                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
-       }
-
-       if (iwlagn_mod_params.power_save)
-               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
-       else
-               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 
-       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
-       /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+       lockdep_assert_held(&priv->shrd->mutex);
 
-       /* Default value; 4 EDCA QOS priorities */
-       hw->queues = 4;
+       if (!priv->hw_roc_setup)
+               return;
 
-       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &priv->bands[IEEE80211_BAND_2GHZ];
-       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &priv->bands[IEEE80211_BAND_5GHZ];
+       priv->hw_roc_channel = NULL;
 
-       iwl_leds_init(priv);
+       memset(ctx->staging.node_addr, 0, ETH_ALEN);
 
-       ret = ieee80211_register_hw(priv->hw);
-       if (ret) {
-               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
-               return ret;
-       }
-       priv->mac80211_registered = 1;
+       iwlagn_commit_rxon(priv, ctx);
 
-       return 0;
+       ctx->is_active = false;
+       priv->hw_roc_setup = false;
 }
 
-
-static int iwlagn_mac_start(struct ieee80211_hw *hw)
+static void iwlagn_disable_roc_work(struct work_struct *work)
 {
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
+       struct iwl_priv *priv = container_of(work, struct iwl_priv,
+                                            hw_roc_disable_work.work);
 
-       /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->shrd->mutex);
-       ret = __iwl_up(priv);
+       iwlagn_disable_roc(priv);
        mutex_unlock(&priv->shrd->mutex);
-       if (ret)
-               return ret;
-
-       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
-
-       /* Now we should be done, and the READY bit should be set. */
-       if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
-               ret = -EIO;
-
-       iwlagn_led_enable(priv);
-
-       priv->is_open = 1;
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
 }
 
-static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = hw->priv;
+       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
 
-       IWL_DEBUG_MAC80211(priv, "enter\n");
+       init_waitqueue_head(&priv->shrd->wait_command_queue);
 
-       if (!priv->is_open)
-               return;
+       INIT_WORK(&priv->restart, iwl_bg_restart);
+       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
+       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+                         iwlagn_disable_roc_work);
 
-       priv->is_open = 0;
+       iwl_setup_scan_deferred_work(priv);
 
-       iwl_down(priv);
+       if (priv->cfg->lib->bt_setup_deferred_work)
+               priv->cfg->lib->bt_setup_deferred_work(priv);
 
-       flush_workqueue(priv->shrd->workqueue);
+       init_timer(&priv->statistics_periodic);
+       priv->statistics_periodic.data = (unsigned long)priv;
+       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
-       /* User space software may expect getting rfkill changes
-        * even if interface is down */
-       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
-       iwl_enable_rfkill_int(priv);
+       init_timer(&priv->ucode_trace);
+       priv->ucode_trace.data = (unsigned long)priv;
+       priv->ucode_trace.function = iwl_bg_ucode_trace;
 
-       IWL_DEBUG_MAC80211(priv, "leave\n");
+       init_timer(&priv->watchdog);
+       priv->watchdog.data = (unsigned long)priv;
+       priv->watchdog.function = iwl_bg_watchdog;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int iwlagn_send_patterns(struct iwl_priv *priv,
-                               struct cfg80211_wowlan *wowlan)
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 {
-       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_WOWLAN_PATTERNS,
-               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-               .flags = CMD_SYNC,
-       };
-       int i, err;
+       if (priv->cfg->lib->cancel_deferred_work)
+               priv->cfg->lib->cancel_deferred_work(priv);
 
-       if (!wowlan->n_patterns)
-               return 0;
+       cancel_work_sync(&priv->run_time_calib_work);
+       cancel_work_sync(&priv->beacon_update);
 
-       cmd.len[0] = sizeof(*pattern_cmd) +
-                       wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+       iwl_cancel_scan_deferred_work(priv);
 
-       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
-       if (!pattern_cmd)
-               return -ENOMEM;
+       cancel_work_sync(&priv->bt_full_concurrency);
+       cancel_work_sync(&priv->bt_runtime_config);
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 
-       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+       del_timer_sync(&priv->statistics_periodic);
+       del_timer_sync(&priv->ucode_trace);
+}
 
-       for (i = 0; i < wowlan->n_patterns; i++) {
-               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+                             struct ieee80211_rate *rates)
+{
+       int i;
 
-               memcpy(&pattern_cmd->patterns[i].mask,
-                       wowlan->patterns[i].mask, mask_len);
-               memcpy(&pattern_cmd->patterns[i].pattern,
-                       wowlan->patterns[i].pattern,
-                       wowlan->patterns[i].pattern_len);
-               pattern_cmd->patterns[i].mask_size = mask_len;
-               pattern_cmd->patterns[i].pattern_size =
-                       wowlan->patterns[i].pattern_len;
+       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
+               rates[i].bitrate = iwl_rates[i].ieee * 5;
+               rates[i].hw_value = i; /* Rate scaling will work on indexes */
+               rates[i].hw_value_short = i;
+               rates[i].flags = 0;
+               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
+                       /*
+                        * If CCK != 1M then set short preamble rate flag.
+                        */
+                       rates[i].flags |=
+                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
+                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
+               }
        }
-
-       cmd.data[0] = pattern_cmd;
-       err = iwl_trans_send_cmd(trans(priv), &cmd);
-       kfree(pattern_cmd);
-       return err;
 }
-#endif
 
-static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif,
-                                     struct cfg80211_gtk_rekey_data *data)
+static int iwl_init_drv(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = hw->priv;
-
-       if (iwlagn_mod_params.sw_crypto)
-               return;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       int ret;
 
-       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
-               goto out;
+       spin_lock_init(&priv->shrd->sta_lock);
 
-       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
-       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
-       priv->replay_ctr = cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
-       priv->have_rekey_data = true;
+       mutex_init(&priv->shrd->mutex);
 
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
+       priv->ieee_channels = NULL;
+       priv->ieee_rates = NULL;
+       priv->band = IEEE80211_BAND_2GHZ;
 
-struct wowlan_key_data {
-       struct iwl_rxon_context *ctx;
-       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
-       struct iwlagn_wowlan_tkip_params_cmd *tkip;
-       const u8 *bssid;
-       bool error, use_rsc_tsc, use_tkip;
-};
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+       priv->agg_tids_count = 0;
 
-#ifdef CONFIG_PM_SLEEP
-static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
-{
-       int i;
+       /* initialize force reset */
+       priv->force_reset[IWL_RF_RESET].reset_duration =
+               IWL_DELAY_NEXT_FORCE_RF_RESET;
+       priv->force_reset[IWL_FW_RESET].reset_duration =
+               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
 
-       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
-               out[i] = cpu_to_le16(p1k[i]);
-}
+       priv->rx_statistics_jiffies = jiffies;
 
-static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif,
-                                      struct ieee80211_sta *sta,
-                                      struct ieee80211_key_conf *key,
-                                      void *_data)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct wowlan_key_data *data = _data;
-       struct iwl_rxon_context *ctx = data->ctx;
-       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
-       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
-       struct iwlagn_p1k_cache *rx_p1ks;
-       u8 *rx_mic_key;
-       struct ieee80211_key_seq seq;
-       u32 cur_rx_iv32 = 0;
-       u16 p1k[IWLAGN_P1K_SIZE];
-       int ret, i;
+       /* Choose which receivers/antennas to use */
+       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
 
-       mutex_lock(&priv->shrd->mutex);
+       iwl_init_scan_params(priv);
 
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
-            !sta && !ctx->key_mapping_keys)
-               ret = iwl_set_default_wep_key(priv, ctx, key);
-       else
-               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+       /* init bt coex */
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+               priv->bt_duration = BT_DURATION_LIMIT_DEF;
+               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+       }
 
+       ret = iwl_init_channel_map(priv);
        if (ret) {
-               IWL_ERR(priv, "Error setting key during suspend!\n");
-               data->error = true;
+               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
+               goto err;
        }
 
-       switch (key->cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               if (sta) {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
-                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
-
-                       rx_p1ks = data->tkip->rx_uni;
+       ret = iwl_init_geos(priv);
+       if (ret) {
+               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
+               goto err_free_channel_map;
+       }
+       iwl_init_hw_rates(priv, priv->ieee_rates);
 
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+       return 0;
 
-                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
-                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
-
-                       memcpy(data->tkip->mic_keys.tx,
-                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
-                              IWLAGN_MIC_KEY_SIZE);
-
-                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
-               } else {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
-                       rx_p1ks = data->tkip->rx_multi;
-                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
-               }
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 (as they need to to avoid replay attacks)
-                * for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
-                       /* wrapping isn't allowed, AP must rekey */
-                       if (seq.tkip.iv32 > cur_rx_iv32)
-                               cur_rx_iv32 = seq.tkip.iv32;
-               }
-
-               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
-               ieee80211_get_tkip_rx_p1k(key, data->bssid,
-                                         cur_rx_iv32 + 1, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
-
-               memcpy(rx_mic_key,
-                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
-                      IWLAGN_MIC_KEY_SIZE);
-
-               data->use_tkip = true;
-               data->use_rsc_tsc = true;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-               if (sta) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
-                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
-
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       aes_tx_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               } else
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       aes_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               }
-               data->use_rsc_tsc = true;
-               break;
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
-                             struct cfg80211_wowlan *wowlan)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
-       struct iwl_rxon_cmd rxon;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
-       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct wowlan_key_data key_data = {
-               .ctx = ctx,
-               .bssid = ctx->active.bssid_addr,
-               .use_rsc_tsc = false,
-               .tkip = &tkip_cmd,
-               .use_tkip = false,
-       };
-       int ret, i;
-       u16 seq;
-
-       if (WARN_ON(!wowlan))
-               return -EINVAL;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       /* Don't attempt WoWLAN when not associated, tear down instead. */
-       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
-           !iwl_is_associated_ctx(ctx)) {
-               ret = 1;
-               goto out;
-       }
-
-       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-       if (!key_data.rsc_tsc) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
-
-       /*
-        * We know the last used seqno, and the uCode expects to know that
-        * one, it will increment before TX.
-        */
-       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
-       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
-
-       /*
-        * For QoS counters, we store the one to use next, so subtract 0x10
-        * since the uCode will add 0x10 before using the value.
-        */
-       for (i = 0; i < 8; i++) {
-               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
-               seq -= 0x10;
-               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
-       }
-
-       if (wowlan->disconnect)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
-                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
-       if (wowlan->magic_pkt)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
-       if (wowlan->gtk_rekey_failure)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
-       if (wowlan->eap_identity_req)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
-       if (wowlan->four_way_handshake)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
-       if (wowlan->rfkill_release)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_RFKILL);
-       if (wowlan->n_patterns)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
-
-       iwl_scan_cancel_timeout(priv, 200);
-
-       memcpy(&rxon, &ctx->active, sizeof(rxon));
-
-       iwl_trans_stop_device(trans(priv));
-
-       priv->shrd->wowlan = true;
-
-       ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan,
-                                          IWL_UCODE_WOWLAN);
-       if (ret)
-               goto error;
-
-       /* now configure WoWLAN ucode */
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-
-       memcpy(&ctx->staging, &rxon, sizeof(rxon));
-       ret = iwlagn_commit_rxon(priv, ctx);
-       if (ret)
-               goto error;
-
-       ret = iwl_power_update_mode(priv, true);
-       if (ret)
-               goto error;
-
-       if (!iwlagn_mod_params.sw_crypto) {
-               /* mark all keys clear */
-               priv->ucode_key_table = 0;
-               ctx->key_mapping_keys = 0;
-
-               /*
-                * This needs to be unlocked due to lock ordering
-                * constraints. Since we're in the suspend path
-                * that isn't really a problem though.
-                */
-               mutex_unlock(&priv->shrd->mutex);
-               ieee80211_iter_keys(priv->hw, ctx->vif,
-                                   iwlagn_wowlan_program_keys,
-                                   &key_data);
-               mutex_lock(&priv->shrd->mutex);
-               if (key_data.error) {
-                       ret = -EIO;
-                       goto error;
-               }
-
-               if (key_data.use_rsc_tsc) {
-                       struct iwl_host_cmd rsc_tsc_cmd = {
-                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
-                               .flags = CMD_SYNC,
-                               .data[0] = key_data.rsc_tsc,
-                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-                               .len[0] = sizeof(*key_data.rsc_tsc),
-                       };
-
-                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
-                       if (ret)
-                               goto error;
-               }
-
-               if (key_data.use_tkip) {
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
-                                                REPLY_WOWLAN_TKIP_PARAMS,
-                                                CMD_SYNC, sizeof(tkip_cmd),
-                                                &tkip_cmd);
-                       if (ret)
-                               goto error;
-               }
-
-               if (priv->have_rekey_data) {
-                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
-                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
-                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
-                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
-                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
-                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
-
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
-                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
-                                                CMD_SYNC, sizeof(kek_kck_cmd),
-                                                &kek_kck_cmd);
-                       if (ret)
-                               goto error;
-               }
-       }
-
-       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
-                                CMD_SYNC, sizeof(wakeup_filter_cmd),
-                                &wakeup_filter_cmd);
-       if (ret)
-               goto error;
-
-       ret = iwlagn_send_patterns(priv, wowlan);
-       if (ret)
-               goto error;
-
-       device_set_wakeup_enable(bus(priv)->dev, true);
-
-       /* Now let the ucode operate on its own */
-       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       goto out;
-
- error:
-       priv->shrd->wowlan = false;
-       iwlagn_prepare_restart(priv);
-       ieee80211_restart_hw(priv->hw);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       kfree(key_data.rsc_tsc);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_resume(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct ieee80211_vif *vif;
-       unsigned long flags;
-       u32 base, status = 0xffffffff;
-       int ret = -EIO;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       base = priv->device_pointers.error_event_table;
-       if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
-               ret = iwl_grab_nic_access_silent(bus(priv));
-               if (ret == 0) {
-                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
-                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
-                       iwl_release_nic_access(bus(priv));
-               }
-               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               if (ret == 0) {
-                       if (!priv->wowlan_sram)
-                               priv->wowlan_sram =
-                                       kzalloc(priv->ucode_wowlan.data.len,
-                                               GFP_KERNEL);
-
-                       if (priv->wowlan_sram)
-                               _iwl_read_targ_mem_words(
-                                       bus(priv), 0x800000, priv->wowlan_sram,
-                                       priv->ucode_wowlan.data.len / 4);
-               }
-#endif
-       }
-
-       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
-       vif = ctx->vif;
-
-       priv->shrd->wowlan = false;
-
-       device_set_wakeup_enable(bus(priv)->dev, false);
-
-       iwlagn_prepare_restart(priv);
-
-       memset((void *)&ctx->active, 0, sizeof(ctx->active));
-       iwl_connection_init_rx_config(priv, ctx);
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       ieee80211_resume_disconnect(vif);
-
-       return 1;
-}
-#endif
-
-static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       IWL_DEBUG_MACDUMP(priv, "enter\n");
-
-       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
-       if (iwlagn_tx_skb(priv, skb))
-               dev_kfree_skb_any(skb);
-
-       IWL_DEBUG_MACDUMP(priv, "leave\n");
-}
-
-static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif,
-                                      struct ieee80211_key_conf *keyconf,
-                                      struct ieee80211_sta *sta,
-                                      u32 iv32, u16 *phase1key)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
-}
-
-static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta,
-                             struct ieee80211_key_conf *key)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       bool is_default_wep_key = false;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (iwlagn_mod_params.sw_crypto) {
-               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
-               return -EOPNOTSUPP;
-       }
-
-       /*
-        * We could program these keys into the hardware as well, but we
-        * don't expect much multicast traffic in IBSS and having keys
-        * for more stations is probably more useful.
-        *
-        * Mark key TX-only and return 0.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC &&
-           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-               key->hw_key_idx = WEP_INVALID_OFFSET;
-               return 0;
-       }
-
-       /* If they key was TX-only, accept deletion */
-       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
-               return 0;
-
-       mutex_lock(&priv->shrd->mutex);
-       iwl_scan_cancel_timeout(priv, 100);
-
-       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
-
-       /*
-        * If we are getting WEP group key and we didn't receive any key mapping
-        * so far, we are in legacy wep mode (group key only), otherwise we are
-        * in 1X mode.
-        * In legacy wep mode, we use another host command to the uCode.
-        */
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
-               if (cmd == SET_KEY)
-                       is_default_wep_key = !ctx->key_mapping_keys;
-               else
-                       is_default_wep_key =
-                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
-       }
-
-
-       switch (cmd) {
-       case SET_KEY:
-               if (is_default_wep_key) {
-                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
-                       break;
-               }
-               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
-               if (ret) {
-                       /*
-                        * can't add key for RX, but we don't need it
-                        * in the device for TX so still return 0
-                        */
-                       ret = 0;
-                       key->hw_key_idx = WEP_INVALID_OFFSET;
-               }
-
-               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
-               break;
-       case DISABLE_KEY:
-               if (is_default_wep_key)
-                       ret = iwl_remove_default_wep_key(priv, ctx, key);
-               else
-                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
-
-               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  enum ieee80211_ampdu_mlme_action action,
-                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                  u8 buf_size)
-{
-       struct iwl_priv *priv = hw->priv;
-       int ret = -EINVAL;
-       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
-                    sta->addr, tid);
-
-       if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
-               return -EACCES;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       switch (action) {
-       case IEEE80211_AMPDU_RX_START:
-               IWL_DEBUG_HT(priv, "start Rx\n");
-               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
-               break;
-       case IEEE80211_AMPDU_RX_STOP:
-               IWL_DEBUG_HT(priv, "stop Rx\n");
-               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
-               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       ret = 0;
-               break;
-       case IEEE80211_AMPDU_TX_START:
-               IWL_DEBUG_HT(priv, "start Tx\n");
-               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
-               break;
-       case IEEE80211_AMPDU_TX_STOP:
-               IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
-               if ((ret == 0) && (priv->agg_tids_count > 0)) {
-                       priv->agg_tids_count--;
-                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                                    priv->agg_tids_count);
-               }
-               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       ret = 0;
-               if (!priv->agg_tids_count && priv->cfg->ht_params &&
-                   priv->cfg->ht_params->use_rts_for_aggregation) {
-                       /*
-                        * switch off RTS/CTS if it was previously enabled
-                        */
-                       sta_priv->lq_sta.lq.general_params.flags &=
-                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-               }
-               break;
-       case IEEE80211_AMPDU_TX_OPERATIONAL:
-               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
-
-               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
-                               tid, buf_size);
-
-               /*
-                * If the limit is 0, then it wasn't initialised yet,
-                * use the default. We can do that since we take the
-                * minimum below, and we don't want to go above our
-                * default due to hardware restrictions.
-                */
-               if (sta_priv->max_agg_bufsize == 0)
-                       sta_priv->max_agg_bufsize =
-                               LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-
-               /*
-                * Even though in theory the peer could have different
-                * aggregation reorder buffer sizes for different sessions,
-                * our ucode doesn't allow for that and has a global limit
-                * for each station. Therefore, use the minimum of all the
-                * aggregation sessions and our default value.
-                */
-               sta_priv->max_agg_bufsize =
-                       min(sta_priv->max_agg_bufsize, buf_size);
-
-               if (priv->cfg->ht_params &&
-                   priv->cfg->ht_params->use_rts_for_aggregation) {
-                       /*
-                        * switch to RTS/CTS if it is the prefer protection
-                        * method for HT traffic
-                        */
-
-                       sta_priv->lq_sta.lq.general_params.flags |=
-                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-               }
-               priv->agg_tids_count++;
-               IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                            priv->agg_tids_count);
-
-               sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
-                       sta_priv->max_agg_bufsize;
-
-               iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                               &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-
-               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
-                        sta->addr, tid);
-               ret = 0;
-               break;
-       }
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return ret;
-}
-
-static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
-       int ret = 0;
-       u8 sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
-                       sta->addr);
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
-                       sta->addr);
-       sta_priv->sta_id = IWL_INVALID_STATION;
-
-       atomic_set(&sta_priv->pending_frames, 0);
-       if (vif->type == NL80211_IFTYPE_AP)
-               sta_priv->client = true;
-
-       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
-                                    is_ap, sta, &sta_id);
-       if (ret) {
-               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
-                       sta->addr, ret);
-               /* Should we return success if return code is EEXIST ? */
-               goto out;
-       }
-
-       sta_priv->sta_id = sta_id;
-
-       /* Initialize rate scaling */
-       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
-                      sta->addr);
-       iwl_rs_rate_init(priv, sta, sta_id);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-                               struct ieee80211_channel_switch *ch_switch)
-{
-       struct iwl_priv *priv = hw->priv;
-       const struct iwl_channel_info *ch_info;
-       struct ieee80211_conf *conf = &hw->conf;
-       struct ieee80211_channel *channel = ch_switch->channel;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-       /*
-        * MULTI-FIXME
-        * When we add support for multiple interfaces, we need to
-        * revisit this. The channel switch command in the device
-        * only affects the BSS context, but what does that really
-        * mean? And what if we get a CSA on the second interface?
-        * This needs a lot of work.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       u16 ch;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_rfkill(priv->shrd))
-               goto out;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
-           test_bit(STATUS_SCANNING, &priv->shrd->status) ||
-           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
-               goto out;
-
-       if (!iwl_is_associated_ctx(ctx))
-               goto out;
-
-       if (!priv->cfg->lib->set_channel_switch)
-               goto out;
-
-       ch = channel->hw_value;
-       if (le16_to_cpu(ctx->active.channel) == ch)
-               goto out;
-
-       ch_info = iwl_get_channel_info(priv, channel->band, ch);
-       if (!is_channel_valid(ch_info)) {
-               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
-               goto out;
-       }
-
-       spin_lock_irq(&priv->shrd->lock);
-
-       priv->current_ht_config.smps = conf->smps_mode;
-
-       /* Configure HT40 channels */
-       ctx->ht.enabled = conf_is_ht(conf);
-       if (ctx->ht.enabled) {
-               if (conf_is_ht40_minus(conf)) {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                       ctx->ht.is_40mhz = true;
-               } else if (conf_is_ht40_plus(conf)) {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                       ctx->ht.is_40mhz = true;
-               } else {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                       ctx->ht.is_40mhz = false;
-               }
-       } else
-               ctx->ht.is_40mhz = false;
-
-       if ((le16_to_cpu(ctx->staging.channel) != ch))
-               ctx->staging.flags = 0;
-
-       iwl_set_rxon_channel(priv, channel, ctx);
-       iwl_set_rxon_ht(priv, ht_conf);
-       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
-
-       spin_unlock_irq(&priv->shrd->lock);
-
-       iwl_set_rate(priv);
-       /*
-        * at this point, staging_rxon has the
-        * configuration for channel switch
-        */
-       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
-       priv->switch_channel = cpu_to_le16(ch);
-       if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
-               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
-               priv->switch_channel = 0;
-               ieee80211_chswitch_done(ctx->vif, false);
-       }
-
-out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static void iwlagn_configure_filter(struct ieee80211_hw *hw,
-                                   unsigned int changed_flags,
-                                   unsigned int *total_flags,
-                                   u64 multicast)
-{
-       struct iwl_priv *priv = hw->priv;
-       __le32 filter_or = 0, filter_nand = 0;
-       struct iwl_rxon_context *ctx;
-
-#define CHK(test, flag)        do { \
-       if (*total_flags & (test))              \
-               filter_or |= (flag);            \
-       else                                    \
-               filter_nand |= (flag);          \
-       } while (0)
-
-       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
-                       changed_flags, *total_flags);
-
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
-       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
-       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
-       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
-
-#undef CHK
-
-       mutex_lock(&priv->shrd->mutex);
-
-       for_each_context(priv, ctx) {
-               ctx->staging.filter_flags &= ~filter_nand;
-               ctx->staging.filter_flags |= filter_or;
-
-               /*
-                * Not committing directly because hardware can perform a scan,
-                * but we'll eventually commit the filter flags change anyway.
-                */
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       /*
-        * Receiving all multicast frames is always enabled by the
-        * default flags setup in iwl_connection_init_rx_config()
-        * since we currently do not support programming multicast
-        * filters into the device.
-        */
-       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
-                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
-}
-
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
-               goto done;
-       }
-       if (iwl_is_rfkill(priv->shrd)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
-               goto done;
-       }
-
-       /*
-        * mac80211 will not push any more frames for transmit
-        * until the flush is completed
-        */
-       if (drop) {
-               IWL_DEBUG_MAC80211(priv, "send flush command\n");
-               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
-                       IWL_ERR(priv, "flush request fail\n");
-                       goto done;
-               }
-       }
-       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(trans(priv));
-done:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwlagn_disable_roc(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (!priv->hw_roc_setup)
-               return;
-
-       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-       priv->hw_roc_channel = NULL;
-
-       memset(ctx->staging.node_addr, 0, ETH_ALEN);
-
-       iwlagn_commit_rxon(priv, ctx);
-
-       ctx->is_active = false;
-       priv->hw_roc_setup = false;
-}
-
-static void iwlagn_disable_roc_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                                            hw_roc_disable_work.work);
-
-       mutex_lock(&priv->shrd->mutex);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
-                                    struct ieee80211_channel *channel,
-                                    enum nl80211_channel_type channel_type,
-                                    int duration)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-       int err = 0;
-
-       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       priv->hw_roc_channel = channel;
-       priv->hw_roc_chantype = channel_type;
-       priv->hw_roc_duration = duration;
-       priv->hw_roc_start_notified = false;
-       cancel_delayed_work(&priv->hw_roc_disable_work);
-
-       if (!ctx->is_active) {
-               ctx->is_active = true;
-               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-               memcpy(ctx->staging.node_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               memcpy(ctx->staging.bssid_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err)
-                       goto out;
-               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
-                                            RXON_FILTER_PROMISC_MSK |
-                                            RXON_FILTER_CTL2HOST_MSK;
-
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err) {
-                       iwlagn_disable_roc(priv);
-                       goto out;
-               }
-               priv->hw_roc_setup = true;
-       }
-
-       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
-       if (err)
-               iwlagn_disable_roc(priv);
-
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
-
-static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return 0;
-}
-
-static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             const u8 *bssid,
-                             enum ieee80211_tx_sync_type type)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       u8 sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_associated_ctx(ctx)) {
-               ret = 0;
-               goto out;
-       }
-
-       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
-       if (ret)
-               goto out;
-
-       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
-               ret = -EIO;
-               goto out_remove_sta;
-       }
-
-       memcpy(ctx->bssid, bssid, ETH_ALEN);
-       ctx->preauth_bssid = true;
-
-       ret = iwlagn_commit_rxon(priv, ctx);
-
-       if (ret == 0)
-               goto out;
-
- out_remove_sta:
-       iwl_remove_station(priv, sta_id, bssid);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  const u8 *bssid,
-                                  enum ieee80211_tx_sync_type type)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_associated_ctx(ctx))
-               goto out;
-
-       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
-       ctx->preauth_bssid = false;
-       /* no need to commit */
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-/*****************************************************************************
- *
- * driver setup and teardown
- *
- *****************************************************************************/
-
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
-{
-       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
-
-       init_waitqueue_head(&priv->shrd->wait_command_queue);
-
-       INIT_WORK(&priv->restart, iwl_bg_restart);
-       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
-       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
-       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
-       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
-                         iwlagn_disable_roc_work);
-
-       iwl_setup_scan_deferred_work(priv);
-
-       if (priv->cfg->lib->bt_setup_deferred_work)
-               priv->cfg->lib->bt_setup_deferred_work(priv);
-
-       init_timer(&priv->statistics_periodic);
-       priv->statistics_periodic.data = (unsigned long)priv;
-       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
-
-       init_timer(&priv->ucode_trace);
-       priv->ucode_trace.data = (unsigned long)priv;
-       priv->ucode_trace.function = iwl_bg_ucode_trace;
-
-       init_timer(&priv->watchdog);
-       priv->watchdog.data = (unsigned long)priv;
-       priv->watchdog.function = iwl_bg_watchdog;
-}
-
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
-{
-       if (priv->cfg->lib->cancel_deferred_work)
-               priv->cfg->lib->cancel_deferred_work(priv);
-
-       cancel_work_sync(&priv->run_time_calib_work);
-       cancel_work_sync(&priv->beacon_update);
-
-       iwl_cancel_scan_deferred_work(priv);
-
-       cancel_work_sync(&priv->bt_full_concurrency);
-       cancel_work_sync(&priv->bt_runtime_config);
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       del_timer_sync(&priv->statistics_periodic);
-       del_timer_sync(&priv->ucode_trace);
-}
-
-static void iwl_init_hw_rates(struct iwl_priv *priv,
-                             struct ieee80211_rate *rates)
-{
-       int i;
-
-       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
-               rates[i].bitrate = iwl_rates[i].ieee * 5;
-               rates[i].hw_value = i; /* Rate scaling will work on indexes */
-               rates[i].hw_value_short = i;
-               rates[i].flags = 0;
-               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
-                       /*
-                        * If CCK != 1M then set short preamble rate flag.
-                        */
-                       rates[i].flags |=
-                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
-                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
-               }
-       }
-}
-
-static int iwl_init_drv(struct iwl_priv *priv)
-{
-       int ret;
-
-       spin_lock_init(&priv->shrd->sta_lock);
-
-       mutex_init(&priv->shrd->mutex);
-
-       priv->ieee_channels = NULL;
-       priv->ieee_rates = NULL;
-       priv->band = IEEE80211_BAND_2GHZ;
-
-       priv->iw_mode = NL80211_IFTYPE_STATION;
-       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
-       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
-       priv->agg_tids_count = 0;
-
-       /* initialize force reset */
-       priv->force_reset[IWL_RF_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_RF_RESET;
-       priv->force_reset[IWL_FW_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
-
-       priv->rx_statistics_jiffies = jiffies;
-
-       /* Choose which receivers/antennas to use */
-       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
-
-       iwl_init_scan_params(priv);
-
-       /* init bt coex */
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
-               priv->bt_duration = BT_DURATION_LIMIT_DEF;
-               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
-       }
-
-       ret = iwl_init_channel_map(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
-               goto err;
-       }
-
-       ret = iwl_init_geos(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
-               goto err_free_channel_map;
-       }
-       iwl_init_hw_rates(priv, priv->ieee_rates);
-
-       return 0;
-
-err_free_channel_map:
-       iwl_free_channel_map(priv);
-err:
-       return ret;
-}
+err_free_channel_map:
+       iwl_free_channel_map(priv);
+err:
+       return ret;
+}
 
 static void iwl_uninit_drv(struct iwl_priv *priv)
 {
@@ -3062,81 +1638,13 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
                kmem_cache_destroy(priv->tx_cmd_pool);
        kfree(priv->scan_cmd);
        kfree(priv->beacon_cmd);
+       kfree(rcu_dereference_raw(priv->noa_data));
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        kfree(priv->wowlan_sram);
 #endif
 }
 
-static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-                          enum ieee80211_rssi_event rssi_event)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (priv->cfg->bt_params &&
-                       priv->cfg->bt_params->advanced_bt_coexist) {
-               if (rssi_event == RSSI_EVENT_LOW)
-                       priv->bt_enable_pspoll = true;
-               else if (rssi_event == RSSI_EVENT_HIGH)
-                       priv->bt_enable_pspoll = false;
-
-               iwlagn_send_advance_bt_config(priv);
-       } else {
-               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
-                               "ignoring RSSI callback\n");
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-                          struct ieee80211_sta *sta, bool set)
-{
-       struct iwl_priv *priv = hw->priv;
 
-       queue_work(priv->shrd->workqueue, &priv->beacon_update);
-
-       return 0;
-}
-
-struct ieee80211_ops iwlagn_hw_ops = {
-       .tx = iwlagn_mac_tx,
-       .start = iwlagn_mac_start,
-       .stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM_SLEEP
-       .suspend = iwlagn_mac_suspend,
-       .resume = iwlagn_mac_resume,
-#endif
-       .add_interface = iwlagn_mac_add_interface,
-       .remove_interface = iwlagn_mac_remove_interface,
-       .change_interface = iwlagn_mac_change_interface,
-       .config = iwlagn_mac_config,
-       .configure_filter = iwlagn_configure_filter,
-       .set_key = iwlagn_mac_set_key,
-       .update_tkip_key = iwlagn_mac_update_tkip_key,
-       .set_rekey_data = iwlagn_mac_set_rekey_data,
-       .conf_tx = iwlagn_mac_conf_tx,
-       .bss_info_changed = iwlagn_bss_info_changed,
-       .ampdu_action = iwlagn_mac_ampdu_action,
-       .hw_scan = iwlagn_mac_hw_scan,
-       .sta_notify = iwlagn_mac_sta_notify,
-       .sta_add = iwlagn_mac_sta_add,
-       .sta_remove = iwlagn_mac_sta_remove,
-       .channel_switch = iwlagn_mac_channel_switch,
-       .flush = iwlagn_mac_flush,
-       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
-       .remain_on_channel = iwlagn_mac_remain_on_channel,
-       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
-       .rssi_callback = iwlagn_mac_rssi_callback,
-       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
-       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
-       .tx_sync = iwlagn_mac_tx_sync,
-       .finish_tx_sync = iwlagn_mac_finish_tx_sync,
-       .set_tim = iwlagn_mac_set_tim,
-};
 
 static u32 iwl_hw_detect(struct iwl_priv *priv)
 {
@@ -3170,27 +1678,7 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
        return priv->cfg->lib->set_hw_params(priv);
 }
 
-/* This function both allocates and initializes hw and priv. */
-static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
-{
-       struct iwl_priv *priv;
-       /* mac80211 allocates memory for this device instance, including
-        *   space for this driver's private structure */
-       struct ieee80211_hw *hw;
-
-       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
-       if (hw == NULL) {
-               pr_err("%s: Can not allocate network device\n",
-                      cfg->name);
-               goto out;
-       }
-
-       priv = hw->priv;
-       priv->hw = hw;
 
-out:
-       return hw;
-}
 
 int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
                struct iwl_cfg *cfg)
@@ -3204,8 +1692,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        /************************
         * 1. Allocating HW data
         ************************/
-       hw = iwl_alloc_all(cfg);
+       hw = iwl_alloc_all();
        if (!hw) {
+               pr_err("%s: Cannot allocate network device\n", cfg->name);
                err = -ENOMEM;
                goto out;
        }
@@ -3397,7 +1886,7 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        /*This will stop the queues, move the device to low power state */
        iwl_trans_stop_device(trans(priv));
 
-       iwl_dealloc_ucode(priv);
+       iwl_dealloc_ucode(trans(priv));
 
        iwl_eeprom_free(priv);
 
index 5b936ec1a541ecc1ecd213771f7d4e75f7960136..5d8d2f445923f7c68a3c9dcd5547505c9b0b6bb6 100644 (file)
 
 #include "iwl-dev.h"
 
+struct iwlagn_ucode_capabilities {
+       u32 max_probe_length;
+       u32 standard_phy_calibration_size;
+       u32 flags;
+};
+
 extern struct ieee80211_ops iwlagn_hw_ops;
 
 int iwl_reset_ict(struct iwl_trans *trans);
@@ -77,6 +83,15 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
        hdr->data_valid = 1;
 }
 
+void __iwl_down(struct iwl_priv *priv);
+void iwl_down(struct iwl_priv *priv);
+void iwlagn_prepare_restart(struct iwl_priv *priv);
+
+/* MAC80211 */
+struct ieee80211_hw *iwl_alloc_all(void);
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                             struct iwlagn_ucode_capabilities *capa);
+
 /* RXON */
 int iwlagn_set_pan_params(struct iwl_priv *priv);
 int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -95,8 +110,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
 void iwlagn_send_prio_tbl(struct iwl_priv *priv);
 int iwlagn_run_init_ucode(struct iwl_priv *priv);
 int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
-                                struct fw_img *image,
-                                enum iwlagn_ucode_type ucode_type);
+                                enum iwl_ucode_type ucode_type);
 
 /* lib */
 int iwlagn_send_tx_power(struct iwl_priv *priv);
@@ -105,6 +119,12 @@ u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
 int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
+#ifdef CONFIG_PM_SLEEP
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                        struct cfg80211_wowlan *wowlan);
+int iwlagn_suspend(struct iwl_priv *priv,
+                  struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
+#endif
 
 /* rx */
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
@@ -196,9 +216,6 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           struct ieee80211_sta *sta, u8 *sta_id_r);
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
-int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta);
-
 u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
 
@@ -316,10 +333,6 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
 int iwl_update_bcast_station(struct iwl_priv *priv,
                             struct iwl_rxon_context *ctx);
 int iwl_update_bcast_stations(struct iwl_priv *priv);
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta);
 
 /* rate */
 static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
index 2a2dc4597ba187e46da6814d05af0f98cee3bc31..e1d78257e4a9426c0908a0b64acd7b31a1ca972b 100644 (file)
@@ -101,17 +101,11 @@ extern struct iwl_cfg iwl100_bg_cfg;
 extern struct iwl_cfg iwl130_bgn_cfg;
 extern struct iwl_cfg iwl130_bg_cfg;
 extern struct iwl_cfg iwl2000_2bgn_cfg;
-extern struct iwl_cfg iwl2000_2bg_cfg;
 extern struct iwl_cfg iwl2000_2bgn_d_cfg;
 extern struct iwl_cfg iwl2030_2bgn_cfg;
-extern struct iwl_cfg iwl2030_2bg_cfg;
 extern struct iwl_cfg iwl6035_2agn_cfg;
-extern struct iwl_cfg iwl6035_2abg_cfg;
-extern struct iwl_cfg iwl6035_2bg_cfg;
-extern struct iwl_cfg iwl105_bg_cfg;
 extern struct iwl_cfg iwl105_bgn_cfg;
 extern struct iwl_cfg iwl105_bgn_d_cfg;
-extern struct iwl_cfg iwl135_bg_cfg;
 extern struct iwl_cfg iwl135_bgn_cfg;
 
 #endif /* __iwl_pci_h__ */
index 69d5f85d11e2a10e53d02ac986e18288e614d972..f4eccf583775f0b4b806d6b3ab2de7d220dedd61 100644 (file)
@@ -198,6 +198,7 @@ enum {
        REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
        REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
        REPLY_WOWLAN_GET_STATUS = 0xe5,
+       REPLY_D3_CONFIG = 0xd3,
 
        REPLY_MAX = 0xff
 };
@@ -3800,6 +3801,19 @@ struct iwl_bt_coex_prot_env_cmd {
        u8 reserved[2];
 } __attribute__((packed));
 
+/*
+ * REPLY_D3_CONFIG
+ */
+enum iwlagn_d3_wakeup_filters {
+       IWLAGN_D3_WAKEUP_RFKILL         = BIT(0),
+       IWLAGN_D3_WAKEUP_SYSASSERT      = BIT(1),
+};
+
+struct iwlagn_d3_config_cmd {
+       __le32 min_sleep_time;
+       __le32 wakeup_flags;
+} __packed;
+
 /*
  * REPLY_WOWLAN_PATTERNS
  */
@@ -3830,19 +3844,16 @@ enum iwlagn_wowlan_wakeup_filters {
        IWLAGN_WOWLAN_WAKEUP_BEACON_MISS        = BIT(2),
        IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE        = BIT(3),
        IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL     = BIT(4),
-       IWLAGN_WOWLAN_WAKEUP_RFKILL             = BIT(5),
-       IWLAGN_WOWLAN_WAKEUP_UCODE_ERROR        = BIT(6),
-       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(7),
-       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(8),
-       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(9),
-       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(10),
+       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(5),
+       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(6),
+       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(7),
+       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(8),
 };
 
 struct iwlagn_wowlan_wakeup_filter_cmd {
        __le32 enabled;
        __le16 non_qos_seq;
-       u8 min_sleep_seconds;
-       u8 reserved;
+       __le16 reserved;
        __le16 qos_seq[8];
 };
 
index 001fdf140abbb72de6d12fe95dac3d8211158ff0..f9e9170e977a8ac053e3af8cd35281987c59493f 100644 (file)
@@ -1120,229 +1120,8 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
                                        &statistics_cmd);
 }
 
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif, u16 queue,
-                   const struct ieee80211_tx_queue_params *params)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx;
-       unsigned long flags;
-       int q;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (!iwl_is_ready_rf(priv->shrd)) {
-               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
-               return -EIO;
-       }
-
-       if (queue >= AC_NUM) {
-               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
-               return 0;
-       }
-
-       q = AC_NUM - 1 - queue;
-
-       spin_lock_irqsave(&priv->shrd->lock, flags);
-
-       /*
-        * MULTI-FIXME
-        * This may need to be done per interface in nl80211/cfg80211/mac80211.
-        */
-       for_each_context(priv, ctx) {
-               ctx->qos_data.def_qos_parm.ac[q].cw_min =
-                       cpu_to_le16(params->cw_min);
-               ctx->qos_data.def_qos_parm.ac[q].cw_max =
-                       cpu_to_le16(params->cw_max);
-               ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-               ctx->qos_data.def_qos_parm.ac[q].edca_txop =
-                               cpu_to_le16((params->txop * 32));
-
-               ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-       }
-
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
-}
-
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       return priv->ibss_manager == IWL_IBSS_MANAGER;
-}
-
-static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       iwl_connection_init_rx_config(priv, ctx);
-
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       return iwlagn_commit_rxon(priv, ctx);
-}
-
-static int iwl_setup_interface(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx)
-{
-       struct ieee80211_vif *vif = ctx->vif;
-       int err;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       /*
-        * This variable will be correct only when there's just
-        * a single context, but all code using it is for hardware
-        * that supports only one context.
-        */
-       priv->iw_mode = vif->type;
-
-       ctx->is_active = true;
-
-       err = iwl_set_mode(priv, ctx);
-       if (err) {
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-               return err;
-       }
-
-       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
-           vif->type == NL80211_IFTYPE_ADHOC) {
-               /*
-                * pretend to have high BT traffic as long as we
-                * are operating in IBSS mode, as this will cause
-                * the rate scaling etc. to behave as intended.
-                */
-               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-       }
-
-       return 0;
-}
-
-int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *tmp, *ctx = NULL;
-       int err;
-       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
-                          viftype, vif->addr);
-
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       mutex_lock(&priv->shrd->mutex);
-
-       iwlagn_disable_roc(priv);
-
-       if (!iwl_is_ready_rf(priv->shrd)) {
-               IWL_WARN(priv, "Try to add interface when device not ready\n");
-               err = -EINVAL;
-               goto out;
-       }
-
-       for_each_context(priv, tmp) {
-               u32 possible_modes =
-                       tmp->interface_modes | tmp->exclusive_interface_modes;
-
-               if (tmp->vif) {
-                       /* check if this busy context is exclusive */
-                       if (tmp->exclusive_interface_modes &
-                                               BIT(tmp->vif->type)) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       continue;
-               }
-
-               if (!(possible_modes & BIT(viftype)))
-                       continue;
 
-               /* have maybe usable context w/o interface */
-               ctx = tmp;
-               break;
-       }
-
-       if (!ctx) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       vif_priv->ctx = ctx;
-       ctx->vif = vif;
-
-       err = iwl_setup_interface(priv, ctx);
-       if (!err)
-               goto out;
 
-       ctx->vif = NULL;
-       priv->iw_mode = NL80211_IFTYPE_STATION;
- out:
-       mutex_unlock(&priv->shrd->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return err;
-}
-
-static void iwl_teardown_interface(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif,
-                                  bool mode_change)
-{
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (priv->scan_vif == vif) {
-               iwl_scan_cancel_timeout(priv, 200);
-               iwl_force_scan_end(priv);
-       }
-
-       if (!mode_change) {
-               iwl_set_mode(priv, ctx);
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-       }
-
-       /*
-        * When removing the IBSS interface, overwrite the
-        * BT traffic load with the stored one from the last
-        * notification, if any. If this is a device that
-        * doesn't implement this, this has no effect since
-        * both values are the same and zero.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC)
-               priv->bt_traffic_load = priv->last_bt_traffic_load;
-}
-
-void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (WARN_ON(ctx->vif != vif)) {
-               struct iwl_rxon_context *tmp;
-               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
-               for_each_context(priv, tmp)
-                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
-                               tmp->ctxid, tmp, tmp->vif);
-       }
-       ctx->vif = NULL;
-
-       iwl_teardown_interface(priv, vif, false);
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 
@@ -1649,97 +1428,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
        return 0;
 }
 
-int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               enum nl80211_iftype newtype, bool newp2p)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl_rxon_context *tmp;
-       enum nl80211_iftype newviftype = newtype;
-       u32 interface_modes;
-       int err;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       newtype = ieee80211_iftype_p2p(newtype, newp2p);
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
-               /*
-                * Huh? But wait ... this can maybe happen when
-                * we're in the middle of a firmware restart!
-                */
-               err = -EBUSY;
-               goto out;
-       }
-
-       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
-
-       if (!(interface_modes & BIT(newtype))) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       /*
-        * Refuse a change that should be done by moving from the PAN
-        * context to the BSS context instead, if the BSS context is
-        * available and can support the new interface type.
-        */
-       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
-           (bss_ctx->interface_modes & BIT(newtype) ||
-            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
-               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-               err = -EBUSY;
-               goto out;
-       }
-
-       if (ctx->exclusive_interface_modes & BIT(newtype)) {
-               for_each_context(priv, tmp) {
-                       if (ctx == tmp)
-                               continue;
-
-                       if (!tmp->vif)
-                               continue;
-
-                       /*
-                        * The current mode switch would be exclusive, but
-                        * another context is active ... refuse the switch.
-                        */
-                       err = -EBUSY;
-                       goto out;
-               }
-       }
-
-       /* success */
-       iwl_teardown_interface(priv, vif, true);
-       vif->type = newviftype;
-       vif->p2p = newp2p;
-       err = iwl_setup_interface(priv, ctx);
-       WARN_ON(err);
-       /*
-        * We've switched internally, but submitting to the
-        * device may have failed for some reason. Mask this
-        * error, because otherwise mac80211 will not switch
-        * (and set the interface type back) and we'll be
-        * out of sync with it.
-        */
-       err = 0;
-
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
 
 int iwl_cmd_echo_test(struct iwl_priv *priv)
 {
        int ret;
        struct iwl_host_cmd cmd = {
                .id = REPLY_ECHO,
+               .len = { 0 },
                .flags = CMD_SYNC,
        };
 
index 137da33807044bedd162a501a65454037abce49f..fa47f75185dfe57745f5f3b38f3174a76e431155 100644 (file)
@@ -237,10 +237,6 @@ struct iwl_cfg {
  *   L i b                 *
  ***************************/
 
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif, u16 queue,
-                   const struct ieee80211_tx_queue_params *params);
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           int hw_decrypt);
 int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -260,13 +256,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
                                   struct iwl_rxon_context *ctx);
 void iwl_set_rate(struct iwl_priv *priv);
-int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif);
-void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif);
-int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            enum nl80211_iftype newtype, bool newp2p);
 int iwl_cmd_echo_test(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
@@ -323,9 +312,6 @@ void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 void iwl_force_scan_end(struct iwl_priv *priv);
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif,
-                   struct cfg80211_scan_request *req);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
index b9f3267e720cb3c9b9d14b75fa6331555576823e..fbc3095c7b445b71f9ddf09bc15d3cf2fd308869 100644 (file)
 #define CSR_HW_REV_TYPE_6x35          CSR_HW_REV_TYPE_6x05
 #define CSR_HW_REV_TYPE_2x30          (0x00000C0)
 #define CSR_HW_REV_TYPE_2x00          (0x0000100)
-#define CSR_HW_REV_TYPE_200           (0x0000110)
-#define CSR_HW_REV_TYPE_230           (0x0000120)
+#define CSR_HW_REV_TYPE_105           (0x0000110)
+#define CSR_HW_REV_TYPE_135           (0x0000120)
 #define CSR_HW_REV_TYPE_NONE           (0x00001F0)
 
 /* EEPROM REG */
index 69a77e24d2293536dec710f80707c491d24e9b4c..40ef97bac1aa232139d8d4274ee46fd9e7f64398 100644 (file)
@@ -70,10 +70,25 @@ do {                                                                \
                               DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);   \
 } while (0)
 
+#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)                        \
+do {                                                                   \
+       if (!iwl_is_rfkill(p->shrd))                            \
+               dev_printk(KERN_ERR, bus(p)->dev, "%c %s " fmt, \
+               (in_interrupt() ? 'I' : 'U'), __func__ , ##args);       \
+       else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO)   \
+               dev_printk(KERN_ERR, bus(p)->dev, "(RFKILL) %c %s " fmt, \
+               (in_interrupt() ? 'I' : 'U'), __func__ , ##args);       \
+} while (0)
+
 #else
 #define IWL_DEBUG(m, level, fmt, args...)
 #define IWL_DEBUG_LIMIT(m, level, fmt, args...)
 #define iwl_print_hex_dump(m, level, p, len)
+#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)        \
+do {                                                   \
+       if (!iwl_is_rfkill(p->shrd))                    \
+               IWL_ERR(p, fmt, ##args);                \
+} while (0)
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -151,7 +166,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #define IWL_DL_11H             (1 << 28)
 #define IWL_DL_STATS           (1 << 29)
 #define IWL_DL_TX_REPLY                (1 << 30)
-#define IWL_DL_QOS             (1 << 31)
+#define IWL_DL_TX_QUEUES       (1 << 31)
 
 #define IWL_DEBUG_INFO(p, f, a...)     IWL_DEBUG(p, IWL_DL_INFO, f, ## a)
 #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a)
@@ -188,7 +203,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a)
 #define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \
                IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a)
-#define IWL_DEBUG_QOS(p, f, a...)      IWL_DEBUG(p, IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_TX_QUEUES(p, f, a...)        IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a)
 #define IWL_DEBUG_RADIO(p, f, a...)    IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
 #define IWL_DEBUG_POWER(p, f, a...)    IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
 #define IWL_DEBUG_11H(p, f, a...)      IWL_DEBUG(p, IWL_DL_11H, f, ## a)
index a1670e3f8bfaa48bc0f2bb1328e9ba6b59acfe92..68b04f5b10ceb31ba0ac2480e87103b67f016a58 100644 (file)
@@ -236,9 +236,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
        if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
                priv->dbgfs_sram_offset = 0x800000;
                if (priv->ucode_type == IWL_UCODE_INIT)
-                       priv->dbgfs_sram_len = priv->ucode_init.data.len;
+                       priv->dbgfs_sram_len = trans(priv)->ucode_init.data.len;
                else
-                       priv->dbgfs_sram_len = priv->ucode_rt.data.len;
+                       priv->dbgfs_sram_len = trans(priv)->ucode_rt.data.len;
        }
        len = priv->dbgfs_sram_len;
 
@@ -341,7 +341,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
 
        return simple_read_from_buffer(user_buf, count, ppos,
                                       priv->wowlan_sram,
-                                      priv->ucode_wowlan.data.len);
+                                      trans(priv)->ucode_wowlan.data.len);
 }
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -430,7 +430,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
        eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
        pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
                        "version: 0x%x\n",
-                       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                       (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                         ? "OTP" : "EEPROM", eeprom_ver);
        for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
                pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
index 6c00a447963d7f5bec37ecd2921696a4517d8b22..556e4a2c19bceb0296cb90309f2d21bc534c82f8 100644 (file)
@@ -230,17 +230,6 @@ struct iwl_vif_priv {
        u8 ibss_bssid_sta_id;
 };
 
-/* one for each uCode image (inst/data, boot/init/runtime) */
-struct fw_desc {
-       void *v_addr;           /* access by driver */
-       dma_addr_t p_addr;      /* access by card's busmaster DMA */
-       u32 len;                /* bytes */
-};
-
-struct fw_img {
-       struct fw_desc code, data;
-};
-
 /* v1/v2 uCode file layout */
 struct iwl_ucode_header {
        __le32 ver;     /* major/minor/API/serial */
@@ -805,13 +794,6 @@ enum iwl_scan_type {
        IWL_SCAN_ROC,
 };
 
-enum iwlagn_ucode_type {
-       IWL_UCODE_NONE,
-       IWL_UCODE_REGULAR,
-       IWL_UCODE_INIT,
-       IWL_UCODE_WOWLAN,
-};
-
 #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
 struct iwl_testmode_trace {
        u32 buff_size;
@@ -824,6 +806,12 @@ struct iwl_testmode_trace {
 };
 #endif
 
+struct iwl_wipan_noa_data {
+       struct rcu_head rcu_head;
+       u32 length;
+       u8 data[];
+};
+
 struct iwl_priv {
 
        /*data shared among all the driver's layers */
@@ -883,6 +871,8 @@ struct iwl_priv {
        /* init calibration results */
        struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
+       struct iwl_wipan_noa_data __rcu *noa_data;
+
        /* Scan related variables */
        unsigned long scan_start;
        unsigned long scan_start_tsf;
@@ -907,12 +897,7 @@ struct iwl_priv {
        u32 ucode_ver;                  /* version of ucode, copy of
                                           iwl_ucode.ver */
 
-       struct fw_img ucode_rt;
-       struct fw_img ucode_init;
-       struct fw_img ucode_wowlan;
-
-       enum iwlagn_ucode_type ucode_type;
-       u8 ucode_write_complete;        /* the image write is complete */
+       enum iwl_ucode_type ucode_type;
        char firmware_name[25];
 
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
@@ -959,7 +944,6 @@ struct iwl_priv {
 
        /* eeprom -- this is in the card's little endian byte order */
        u8 *eeprom;
-       int    nvm_device_type;
        struct iwl_eeprom_calib_info *calib_info;
 
        enum nl80211_iftype iw_mode;
index a635a7e754473220fa93c85fab9475654f0013c8..2a2c8de64a04d135052d2e8ec421f2aebbd8553d 100644 (file)
@@ -28,7 +28,7 @@
 
 /* sparse doesn't like tracepoint macros */
 #ifndef __CHECKER__
-#include "iwl-dev.h"
+#include "iwl-trans.h"
 
 #define CREATE_TRACE_POINTS
 #include "iwl-devtrace.h"
index 8a51c5ccda1ee50b81b734125cc9eb008647e1d6..f9d3319ecad5b9f6cb1c9f32bae83f59cc2f4a90 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/tracepoint.h>
 
-struct iwl_priv;
 
 #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
 #undef TRACE_EVENT
@@ -37,14 +36,14 @@ struct iwl_priv;
 static inline void trace_ ## name(proto) {}
 #endif
 
-#define PRIV_ENTRY     __field(struct iwl_priv *, priv)
+#define PRIV_ENTRY     __field(void *, priv)
 #define PRIV_ASSIGN    __entry->priv = priv
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi_io
 
 TRACE_EVENT(iwlwifi_dev_ioread32,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+       TP_PROTO(void *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -60,7 +59,7 @@ TRACE_EVENT(iwlwifi_dev_ioread32,
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite8,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val),
+       TP_PROTO(void *priv, u32 offs, u8 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -76,7 +75,7 @@ TRACE_EVENT(iwlwifi_dev_iowrite8,
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite32,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+       TP_PROTO(void *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -95,7 +94,7 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
 #define TRACE_SYSTEM iwlwifi_ucode
 
 TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
-       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
        TP_ARGS(priv, time, data, ev),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -115,7 +114,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
-       TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
+       TP_PROTO(void *priv, u32 wraps, u32 n_entry, u32 p_entry),
        TP_ARGS(priv, wraps, n_entry, p_entry),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -139,7 +138,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
-       TP_PROTO(struct iwl_priv *priv, u32 flags,
+       TP_PROTO(void *priv, u32 flags,
                 const void *hcmd0, size_t len0,
                 const void *hcmd1, size_t len1,
                 const void *hcmd2, size_t len2),
@@ -164,7 +163,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
 );
 
 TRACE_EVENT(iwlwifi_dev_rx,
-       TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len),
+       TP_PROTO(void *priv, void *rxbuf, size_t len),
        TP_ARGS(priv, rxbuf, len),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -179,7 +178,7 @@ TRACE_EVENT(iwlwifi_dev_rx,
 );
 
 TRACE_EVENT(iwlwifi_dev_tx,
-       TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen,
+       TP_PROTO(void *priv, void *tfd, size_t tfdlen,
                 void *buf0, size_t buf0_len,
                 void *buf1, size_t buf1_len),
        TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
@@ -211,7 +210,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_error,
-       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 tsf_low,
+       TP_PROTO(void *priv, u32 desc, u32 tsf_low,
                 u32 data1, u32 data2, u32 line, u32 blink1,
                 u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
                 u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
@@ -271,7 +270,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_event,
-       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
        TP_ARGS(priv, time, data, ev),
        TP_STRUCT__entry(
                PRIV_ENTRY
index a4e43bd4a54763bfac47354088f027a4023ebc63..dcada0827ea43db482effeaa8966b62af51be67e 100644 (file)
@@ -149,23 +149,23 @@ static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
  * EEPROM chip, not a single event, so even reads could conflict if they
  * weren't arbitrated by the semaphore.
  */
-static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
+static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus)
 {
        u16 count;
        int ret;
 
        for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
                /* Request semaphore */
-               iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+               iwl_set_bit(bus, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
                /* See if we got it */
-               ret = iwl_poll_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+               ret = iwl_poll_bit(bus, CSR_HW_IF_CONFIG_REG,
                                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
                                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
                                EEPROM_SEM_TIMEOUT);
                if (ret >= 0) {
-                       IWL_DEBUG_EEPROM(priv,
+                       IWL_DEBUG_EEPROM(bus,
                                "Acquired semaphore after %d tries.\n",
                                count+1);
                        return ret;
@@ -175,39 +175,39 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
        return ret;
 }
 
-static void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+static void iwl_eeprom_release_semaphore(struct iwl_bus *bus)
 {
-       iwl_clear_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+       iwl_clear_bit(bus, CSR_HW_IF_CONFIG_REG,
                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 }
 
-static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
+static int iwl_eeprom_verify_signature(struct iwl_trans *trans)
 {
-       u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+       u32 gp = iwl_read32(bus(trans), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
        int ret = 0;
 
-       IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
+       IWL_DEBUG_EEPROM(trans, "EEPROM signature=0x%08x\n", gp);
        switch (gp) {
        case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
-               if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
-                       IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n",
+               if (trans->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
+                       IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n",
                                gp);
                        ret = -ENOENT;
                }
                break;
        case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
        case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
-               if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
-                       IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp);
+               if (trans->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
+                       IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp);
                        ret = -ENOENT;
                }
                break;
        case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
        default:
-               IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, "
+               IWL_ERR(trans, "bad EEPROM/OTP signature, type=%s, "
                        "EEPROM_GP=0x%08x\n",
-                       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                       (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                        ? "OTP" : "EEPROM", gp);
                ret = -ENOENT;
                break;
@@ -302,19 +302,19 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
  *
 ******************************************************************************/
 
-static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode)
 {
-       iwl_read32(bus(priv), CSR_OTP_GP_REG);
+       iwl_read32(bus, CSR_OTP_GP_REG);
 
        if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-               iwl_clear_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_clear_bit(bus, CSR_OTP_GP_REG,
                              CSR_OTP_GP_REG_OTP_ACCESS_MODE);
        else
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                            CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
-static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
+static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
 {
        u32 otpgp;
        int nvm_type;
@@ -322,7 +322,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
        /* OTP only valid for CP/PP and after */
        switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
        case CSR_HW_REV_TYPE_NONE:
-               IWL_ERR(priv, "Unknown hardware type\n");
+               IWL_ERR(bus, "Unknown hardware type\n");
                return -ENOENT;
        case CSR_HW_REV_TYPE_5300:
        case CSR_HW_REV_TYPE_5350:
@@ -331,7 +331,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
                nvm_type = NVM_DEVICE_TYPE_EEPROM;
                break;
        default:
-               otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
+               otpgp = iwl_read32(bus, CSR_OTP_GP_REG);
                if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
                        nvm_type = NVM_DEVICE_TYPE_OTP;
                else
@@ -341,73 +341,73 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
        return  nvm_type;
 }
 
-static int iwl_init_otp_access(struct iwl_priv *priv)
+static int iwl_init_otp_access(struct iwl_bus *bus)
 {
        int ret;
 
        /* Enable 40MHz radio clock */
-       iwl_write32(bus(priv), CSR_GP_CNTRL,
-                   iwl_read32(bus(priv), CSR_GP_CNTRL) |
+       iwl_write32(bus, CSR_GP_CNTRL,
+                   iwl_read32(bus, CSR_GP_CNTRL) |
                    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
        /* wait for clock to be ready */
-       ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL,
+       ret = iwl_poll_bit(bus, CSR_GP_CNTRL,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                                 25000);
        if (ret < 0)
-               IWL_ERR(priv, "Time out access OTP\n");
+               IWL_ERR(bus, "Time out access OTP\n");
        else {
-               iwl_set_bits_prph(bus(priv), APMG_PS_CTRL_REG,
+               iwl_set_bits_prph(bus, APMG_PS_CTRL_REG,
                                  APMG_PS_CTRL_VAL_RESET_REQ);
                udelay(5);
-               iwl_clear_bits_prph(bus(priv), APMG_PS_CTRL_REG,
+               iwl_clear_bits_prph(bus, APMG_PS_CTRL_REG,
                                    APMG_PS_CTRL_VAL_RESET_REQ);
 
                /*
                 * CSR auto clock gate disable bit -
                 * this is only applicable for HW with OTP shadow RAM
                 */
-               if (priv->cfg->base_params->shadow_ram_support)
-                       iwl_set_bit(bus(priv), CSR_DBG_LINK_PWR_MGMT_REG,
+               if (priv(bus)->cfg->base_params->shadow_ram_support)
+                       iwl_set_bit(bus, CSR_DBG_LINK_PWR_MGMT_REG,
                                CSR_RESET_LINK_PWR_MGMT_DISABLED);
        }
        return ret;
 }
 
-static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data)
+static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data)
 {
        int ret = 0;
        u32 r;
        u32 otpgp;
 
-       iwl_write32(bus(priv), CSR_EEPROM_REG,
+       iwl_write32(bus, CSR_EEPROM_REG,
                    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-       ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG,
+       ret = iwl_poll_bit(bus, CSR_EEPROM_REG,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 IWL_EEPROM_ACCESS_TIMEOUT);
        if (ret < 0) {
-               IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+               IWL_ERR(bus, "Time out reading OTP[%d]\n", addr);
                return ret;
        }
-       r = iwl_read32(bus(priv), CSR_EEPROM_REG);
+       r = iwl_read32(bus, CSR_EEPROM_REG);
        /* check for ECC errors: */
-       otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
+       otpgp = iwl_read32(bus, CSR_OTP_GP_REG);
        if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
                /* stop in this case */
                /* set the uncorrectable OTP ECC bit for acknowledgement */
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                        CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-               IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+               IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n");
                return -EINVAL;
        }
        if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
                /* continue in this case */
                /* set the correctable OTP ECC bit for acknowledgement */
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                                CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-               IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+               IWL_ERR(bus, "Correctable OTP ECC error, continue read\n");
        }
        *eeprom_data = cpu_to_le16(r >> 16);
        return 0;
@@ -416,20 +416,20 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
 /*
  * iwl_is_otp_empty: check for empty OTP
  */
-static bool iwl_is_otp_empty(struct iwl_priv *priv)
+static bool iwl_is_otp_empty(struct iwl_bus *bus)
 {
        u16 next_link_addr = 0;
        __le16 link_value;
        bool is_empty = false;
 
        /* locate the beginning of OTP link list */
-       if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+       if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) {
                if (!link_value) {
-                       IWL_ERR(priv, "OTP is empty\n");
+                       IWL_ERR(bus, "OTP is empty\n");
                        is_empty = true;
                }
        } else {
-               IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+               IWL_ERR(bus, "Unable to read first block of OTP list.\n");
                is_empty = true;
        }
 
@@ -446,7 +446,7 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv)
  *   we should read and used to configure the device.
  *   only perform this operation if shadow RAM is disabled
  */
-static int iwl_find_otp_image(struct iwl_priv *priv,
+static int iwl_find_otp_image(struct iwl_bus *bus,
                                        u16 *validblockaddr)
 {
        u16 next_link_addr = 0, valid_addr;
@@ -454,10 +454,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
        int usedblocks = 0;
 
        /* set addressing mode to absolute to traverse the link list */
-       iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+       iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE);
 
        /* checking for empty OTP or error */
-       if (iwl_is_otp_empty(priv))
+       if (iwl_is_otp_empty(bus))
                return -EINVAL;
 
        /*
@@ -471,9 +471,9 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                 */
                valid_addr = next_link_addr;
                next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-               IWL_DEBUG_EEPROM(priv, "OTP blocks %d addr 0x%x\n",
+               IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n",
                               usedblocks, next_link_addr);
-               if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+               if (iwl_read_otp_word(bus, next_link_addr, &link_value))
                        return -EINVAL;
                if (!link_value) {
                        /*
@@ -488,10 +488,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                }
                /* more in the link list, continue */
                usedblocks++;
-       } while (usedblocks <= priv->cfg->base_params->max_ll_items);
+       } while (usedblocks <= priv(bus)->cfg->base_params->max_ll_items);
 
        /* OTP has no valid blocks */
-       IWL_DEBUG_EEPROM(priv, "OTP has no valid blocks\n");
+       IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n");
        return -EINVAL;
 }
 
@@ -504,28 +504,28 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
  * iwl_get_max_txpower_avg - get the highest tx power from all chains.
  *     find the highest tx power from all chains for the channel
  */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
+static s8 iwl_get_max_txpower_avg(struct iwl_cfg *cfg,
                struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
                int element, s8 *max_txpower_in_half_dbm)
 {
        s8 max_txpower_avg = 0; /* (dBm) */
 
        /* Take the highest tx power from any valid chains */
-       if ((priv->cfg->valid_tx_ant & ANT_A) &&
+       if ((cfg->valid_tx_ant & ANT_A) &&
            (enhanced_txpower[element].chain_a_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_a_max;
-       if ((priv->cfg->valid_tx_ant & ANT_B) &&
+       if ((cfg->valid_tx_ant & ANT_B) &&
            (enhanced_txpower[element].chain_b_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_b_max;
-       if ((priv->cfg->valid_tx_ant & ANT_C) &&
+       if ((cfg->valid_tx_ant & ANT_C) &&
            (enhanced_txpower[element].chain_c_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_c_max;
-       if (((priv->cfg->valid_tx_ant == ANT_AB) |
-           (priv->cfg->valid_tx_ant == ANT_BC) |
-           (priv->cfg->valid_tx_ant == ANT_AC)) &&
+       if (((cfg->valid_tx_ant == ANT_AB) |
+           (cfg->valid_tx_ant == ANT_BC) |
+           (cfg->valid_tx_ant == ANT_AC)) &&
            (enhanced_txpower[element].mimo2_max > max_txpower_avg))
                max_txpower_avg =  enhanced_txpower[element].mimo2_max;
-       if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
+       if ((cfg->valid_tx_ant == ANT_ABC) &&
            (enhanced_txpower[element].mimo3_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].mimo3_max;
 
@@ -627,7 +627,7 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
                                 ((txp->delta_20_in_40 & 0xf0) >> 4),
                                 (txp->delta_20_in_40 & 0x0f));
 
-               max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+               max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx,
                                                      &max_txp_avg_halfdbm);
 
                /*
@@ -660,8 +660,8 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        u16 validblockaddr = 0;
        u16 cache_addr = 0;
 
-       priv->nvm_device_type = iwl_get_nvm_type(priv, hw_rev);
-       if (priv->nvm_device_type == -ENOENT)
+       trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev);
+       if (trans(priv)->nvm_device_type == -ENOENT)
                return -ENOENT;
        /* allocate eeprom */
        sz = priv->cfg->base_params->eeprom_size;
@@ -675,7 +675,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
 
        iwl_apm_init(priv);
 
-       ret = iwl_eeprom_verify_signature(priv);
+       ret = iwl_eeprom_verify_signature(trans(priv));
        if (ret < 0) {
                IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
                ret = -ENOENT;
@@ -683,16 +683,16 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
 
        /* Make sure driver (instead of uCode) is allowed to read EEPROM */
-       ret = iwl_eeprom_acquire_semaphore(priv);
+       ret = iwl_eeprom_acquire_semaphore(bus(priv));
        if (ret < 0) {
                IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
                ret = -ENOENT;
                goto err;
        }
 
-       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+       if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
-               ret = iwl_init_otp_access(priv);
+               ret = iwl_init_otp_access(bus(priv));
                if (ret) {
                        IWL_ERR(priv, "Failed to initialize OTP access.\n");
                        ret = -ENOENT;
@@ -707,7 +707,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                             CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
                /* traversing the linked list if no shadow ram supported */
                if (!priv->cfg->base_params->shadow_ram_support) {
-                       if (iwl_find_otp_image(priv, &validblockaddr)) {
+                       if (iwl_find_otp_image(bus(priv), &validblockaddr)) {
                                ret = -ENOENT;
                                goto done;
                        }
@@ -716,7 +716,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                     addr += sizeof(u16)) {
                        __le16 eeprom_data;
 
-                       ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+                       ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data);
                        if (ret)
                                goto done;
                        e[cache_addr / 2] = eeprom_data;
@@ -744,13 +744,13 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
 
        IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                      (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                       ? "OTP" : "EEPROM",
                       iwl_eeprom_query16(priv, EEPROM_VERSION));
 
        ret = 0;
 done:
-       iwl_eeprom_release_semaphore(priv);
+       iwl_eeprom_release_semaphore(bus(priv));
 
 err:
        if (ret)
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
new file mode 100644 (file)
index 0000000..05b1f0d
--- /dev/null
@@ -0,0 +1,1632 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn-calib.h"
+#include "iwl-agn.h"
+#include "iwl-shared.h"
+#include "iwl-bus.h"
+#include "iwl-trans.h"
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_GO) |
+                        BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_dualmode[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_sta_ap_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_p2p[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_p2p_sta_go_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_p2p_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
+       },
+};
+
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa)
+{
+       int ret;
+       struct ieee80211_hw *hw = priv->hw;
+       struct iwl_rxon_context *ctx;
+
+       hw->rate_control_algorithm = "iwl-agn-rs";
+
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_NEED_DTIM_PERIOD |
+                   IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+
+       /*
+        * Including the following line will crash some AP's.  This
+        * workaround removes the stimulus which causes the crash until
+        * the AP software can be fixed.
+       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+        */
+
+       hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+
+       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
+               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
+       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+       hw->sta_data_size = sizeof(struct iwl_station_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
+       for_each_context(priv, ctx) {
+               hw->wiphy->interface_modes |= ctx->interface_modes;
+               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+       }
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
+               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
+       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+               hw->wiphy->iface_combinations =
+                       iwlagn_iface_combinations_dualmode;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
+       }
+
+       hw->wiphy->max_remain_on_channel_duration = 1000;
+
+       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
+                           WIPHY_FLAG_IBSS_RSN;
+
+       if (trans(priv)->ucode_wowlan.code.len &&
+           device_can_wakeup(bus(priv)->dev)) {
+               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                                         WIPHY_WOWLAN_DISCONNECT |
+                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                         WIPHY_WOWLAN_RFKILL_RELEASE;
+               if (!iwlagn_mod_params.sw_crypto)
+                       hw->wiphy->wowlan.flags |=
+                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+
+               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
+               hw->wiphy->wowlan.pattern_min_len =
+                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
+               hw->wiphy->wowlan.pattern_max_len =
+                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
+       }
+
+       if (iwlagn_mod_params.power_save)
+               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       else
+               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+       /* we create the 802.11 header and a zero-length SSID element */
+       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+
+       /* Default value; 4 EDCA QOS priorities */
+       hw->queues = 4;
+
+       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->bands[IEEE80211_BAND_2GHZ];
+       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &priv->bands[IEEE80211_BAND_5GHZ];
+
+       iwl_leds_init(priv);
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+               return ret;
+       }
+       priv->mac80211_registered = 1;
+
+       return 0;
+}
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
+               return -EIO;
+       }
+
+       for_each_context(priv, ctx) {
+               ret = iwlagn_alloc_bcast_station(priv, ctx);
+               if (ret) {
+                       iwl_dealloc_bcast_stations(priv);
+                       return ret;
+               }
+       }
+
+       ret = iwlagn_run_init_ucode(priv);
+       if (ret) {
+               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+       if (ret) {
+               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto error;
+       return 0;
+
+ error:
+       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+       __iwl_down(priv);
+       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+
+       IWL_ERR(priv, "Unable to initialize device.\n");
+       return ret;
+}
+
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       /* we should be verifying the device is ready to be opened */
+       mutex_lock(&priv->shrd->mutex);
+       ret = __iwl_up(priv);
+       mutex_unlock(&priv->shrd->mutex);
+       if (ret)
+               return ret;
+
+       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
+
+       /* Now we should be done, and the READY bit should be set. */
+       if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
+               ret = -EIO;
+
+       iwlagn_led_enable(priv);
+
+       priv->is_open = 1;
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!priv->is_open)
+               return;
+
+       priv->is_open = 0;
+
+       iwl_down(priv);
+
+       flush_workqueue(priv->shrd->workqueue);
+
+       /* User space software may expect getting rfkill changes
+        * even if interface is down */
+       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
+       iwl_enable_rfkill_int(priv);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct cfg80211_gtk_rekey_data *data)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       if (iwlagn_mod_params.sw_crypto)
+               return;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
+               goto out;
+
+       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
+       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
+       priv->replay_ctr =
+               cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+       priv->have_rekey_data = true;
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
+                             struct cfg80211_wowlan *wowlan)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       int ret;
+
+       if (WARN_ON(!wowlan))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       /* Don't attempt WoWLAN when not associated, tear down instead. */
+       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
+           !iwl_is_associated_ctx(ctx)) {
+               ret = 1;
+               goto out;
+       }
+
+       ret = iwlagn_suspend(priv, hw, wowlan);
+       if (ret)
+               goto error;
+
+       device_set_wakeup_enable(bus(priv)->dev, true);
+
+       /* Now let the ucode operate on its own */
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       goto out;
+
+ error:
+       priv->shrd->wowlan = false;
+       iwlagn_prepare_restart(priv);
+       ieee80211_restart_hw(priv->hw);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_resume(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct ieee80211_vif *vif;
+       unsigned long flags;
+       u32 base, status = 0xffffffff;
+       int ret = -EIO;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       base = priv->device_pointers.error_event_table;
+       if (iwlagn_hw_valid_rtc_data_addr(base)) {
+               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
+               ret = iwl_grab_nic_access_silent(bus(priv));
+               if (ret == 0) {
+                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
+                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+                       iwl_release_nic_access(bus(priv));
+               }
+               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               if (ret == 0) {
+                       struct iwl_trans *trans = trans(priv);
+                       if (!priv->wowlan_sram)
+                               priv->wowlan_sram =
+                                       kzalloc(trans->ucode_wowlan.data.len,
+                                               GFP_KERNEL);
+
+                       if (priv->wowlan_sram)
+                               _iwl_read_targ_mem_words(
+                                       bus(priv), 0x800000, priv->wowlan_sram,
+                                       trans->ucode_wowlan.data.len / 4);
+               }
+#endif
+       }
+
+       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
+       vif = ctx->vif;
+
+       priv->shrd->wowlan = false;
+
+       device_set_wakeup_enable(bus(priv)->dev, false);
+
+       iwlagn_prepare_restart(priv);
+
+       memset((void *)&ctx->active, 0, sizeof(ctx->active));
+       iwl_connection_init_rx_config(priv, ctx);
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       ieee80211_resume_disconnect(vif);
+
+       return 1;
+}
+
+#endif
+
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MACDUMP(priv, "enter\n");
+
+       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
+
+       if (iwlagn_tx_skb(priv, skb))
+               dev_kfree_skb_any(skb);
+
+       IWL_DEBUG_MACDUMP(priv, "leave\n");
+}
+
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_key_conf *keyconf,
+                                      struct ieee80211_sta *sta,
+                                      u32 iv32, u16 *phase1key)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
+}
+
+static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta,
+                             struct ieee80211_key_conf *key)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       bool is_default_wep_key = false;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (iwlagn_mod_params.sw_crypto) {
+               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
+               return -EOPNOTSUPP;
+       }
+
+       /*
+        * We could program these keys into the hardware as well, but we
+        * don't expect much multicast traffic in IBSS and having keys
+        * for more stations is probably more useful.
+        *
+        * Mark key TX-only and return 0.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               key->hw_key_idx = WEP_INVALID_OFFSET;
+               return 0;
+       }
+
+       /* If they key was TX-only, accept deletion */
+       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
+               return 0;
+
+       mutex_lock(&priv->shrd->mutex);
+       iwl_scan_cancel_timeout(priv, 100);
+
+       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
+
+       /*
+        * If we are getting WEP group key and we didn't receive any key mapping
+        * so far, we are in legacy wep mode (group key only), otherwise we are
+        * in 1X mode.
+        * In legacy wep mode, we use another host command to the uCode.
+        */
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
+               if (cmd == SET_KEY)
+                       is_default_wep_key = !ctx->key_mapping_keys;
+               else
+                       is_default_wep_key =
+                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
+       }
+
+
+       switch (cmd) {
+       case SET_KEY:
+               if (is_default_wep_key) {
+                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
+                       break;
+               }
+               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
+               if (ret) {
+                       /*
+                        * can't add key for RX, but we don't need it
+                        * in the device for TX so still return 0
+                        */
+                       ret = 0;
+                       key->hw_key_idx = WEP_INVALID_OFFSET;
+               }
+
+               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
+               break;
+       case DISABLE_KEY:
+               if (is_default_wep_key)
+                       ret = iwl_remove_default_wep_key(priv, ctx, key);
+               else
+                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
+
+               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  enum ieee80211_ampdu_mlme_action action,
+                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+                                  u8 buf_size)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret = -EINVAL;
+       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
+                    sta->addr, tid);
+
+       if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
+               return -EACCES;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               IWL_DEBUG_HT(priv, "start Rx\n");
+               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               IWL_DEBUG_HT(priv, "stop Rx\n");
+               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
+               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+                       ret = 0;
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               IWL_DEBUG_HT(priv, "start Tx\n");
+               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               IWL_DEBUG_HT(priv, "stop Tx\n");
+               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
+               if ((ret == 0) && (priv->agg_tids_count > 0)) {
+                       priv->agg_tids_count--;
+                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                                    priv->agg_tids_count);
+               }
+               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+                       ret = 0;
+               if (!priv->agg_tids_count && priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
+                       /*
+                        * switch off RTS/CTS if it was previously enabled
+                        */
+                       sta_priv->lq_sta.lq.general_params.flags &=
+                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+               }
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
+                               tid, buf_size);
+
+               /*
+                * If the limit is 0, then it wasn't initialised yet,
+                * use the default. We can do that since we take the
+                * minimum below, and we don't want to go above our
+                * default due to hardware restrictions.
+                */
+               if (sta_priv->max_agg_bufsize == 0)
+                       sta_priv->max_agg_bufsize =
+                               LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+               /*
+                * Even though in theory the peer could have different
+                * aggregation reorder buffer sizes for different sessions,
+                * our ucode doesn't allow for that and has a global limit
+                * for each station. Therefore, use the minimum of all the
+                * aggregation sessions and our default value.
+                */
+               sta_priv->max_agg_bufsize =
+                       min(sta_priv->max_agg_bufsize, buf_size);
+
+               if (priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
+                       /*
+                        * switch to RTS/CTS if it is the prefer protection
+                        * method for HT traffic
+                        */
+
+                       sta_priv->lq_sta.lq.general_params.flags |=
+                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+               }
+               priv->agg_tids_count++;
+               IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                            priv->agg_tids_count);
+
+               sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
+                       sta_priv->max_agg_bufsize;
+
+               iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                               &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+
+               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
+                        sta->addr, tid);
+               ret = 0;
+               break;
+       }
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return ret;
+}
+
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+       int ret = 0;
+       u8 sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
+                       sta->addr);
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+                       sta->addr);
+       sta_priv->sta_id = IWL_INVALID_STATION;
+
+       atomic_set(&sta_priv->pending_frames, 0);
+       if (vif->type == NL80211_IFTYPE_AP)
+               sta_priv->client = true;
+
+       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+                                    is_ap, sta, &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               goto out;
+       }
+
+       sta_priv->sta_id = sta_id;
+
+       /* Initialize rate scaling */
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
+                      sta->addr);
+       iwl_rs_rate_init(priv, sta, sta_id);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+                               struct ieee80211_channel_switch *ch_switch)
+{
+       struct iwl_priv *priv = hw->priv;
+       const struct iwl_channel_info *ch_info;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = ch_switch->channel;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       /*
+        * MULTI-FIXME
+        * When we add support for multiple interfaces, we need to
+        * revisit this. The channel switch command in the device
+        * only affects the BSS context, but what does that really
+        * mean? And what if we get a CSA on the second interface?
+        * This needs a lot of work.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       u16 ch;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_rfkill(priv->shrd))
+               goto out;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
+           test_bit(STATUS_SCANNING, &priv->shrd->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
+               goto out;
+
+       if (!iwl_is_associated_ctx(ctx))
+               goto out;
+
+       if (!priv->cfg->lib->set_channel_switch)
+               goto out;
+
+       ch = channel->hw_value;
+       if (le16_to_cpu(ctx->active.channel) == ch)
+               goto out;
+
+       ch_info = iwl_get_channel_info(priv, channel->band, ch);
+       if (!is_channel_valid(ch_info)) {
+               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+               goto out;
+       }
+
+       spin_lock_irq(&priv->shrd->lock);
+
+       priv->current_ht_config.smps = conf->smps_mode;
+
+       /* Configure HT40 channels */
+       ctx->ht.enabled = conf_is_ht(conf);
+       if (ctx->ht.enabled) {
+               if (conf_is_ht40_minus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                       ctx->ht.is_40mhz = true;
+               } else if (conf_is_ht40_plus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                       ctx->ht.is_40mhz = true;
+               } else {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                       ctx->ht.is_40mhz = false;
+               }
+       } else
+               ctx->ht.is_40mhz = false;
+
+       if ((le16_to_cpu(ctx->staging.channel) != ch))
+               ctx->staging.flags = 0;
+
+       iwl_set_rxon_channel(priv, channel, ctx);
+       iwl_set_rxon_ht(priv, ht_conf);
+       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
+
+       spin_unlock_irq(&priv->shrd->lock);
+
+       iwl_set_rate(priv);
+       /*
+        * at this point, staging_rxon has the
+        * configuration for channel switch
+        */
+       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+       priv->switch_channel = cpu_to_le16(ch);
+       if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
+               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+               priv->switch_channel = 0;
+               ieee80211_chswitch_done(ctx->vif, false);
+       }
+
+out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed_flags,
+                                   unsigned int *total_flags,
+                                   u64 multicast)
+{
+       struct iwl_priv *priv = hw->priv;
+       __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx;
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
+
+       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
+                       changed_flags, *total_flags);
+
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
+
+#undef CHK
+
+       mutex_lock(&priv->shrd->mutex);
+
+       for_each_context(priv, ctx) {
+               ctx->staging.filter_flags &= ~filter_nand;
+               ctx->staging.filter_flags |= filter_or;
+
+               /*
+                * Not committing directly because hardware can perform a scan,
+                * but we'll eventually commit the filter flags change anyway.
+                */
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       /*
+        * Receiving all multicast frames is always enabled by the
+        * default flags setup in iwl_connection_init_rx_config()
+        * since we currently do not support programming multicast
+        * filters into the device.
+        */
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
+}
+
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
+               goto done;
+       }
+       if (iwl_is_rfkill(priv->shrd)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
+               goto done;
+       }
+
+       /*
+        * mac80211 will not push any more frames for transmit
+        * until the flush is completed
+        */
+       if (drop) {
+               IWL_DEBUG_MAC80211(priv, "send flush command\n");
+               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
+       }
+       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+       iwl_trans_wait_tx_queue_empty(trans(priv));
+done:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
+                                    struct ieee80211_channel *channel,
+                                    enum nl80211_channel_type channel_type,
+                                    int duration)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+       int err = 0;
+
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       priv->hw_roc_channel = channel;
+       priv->hw_roc_chantype = channel_type;
+       /* convert from ms to TU */
+       priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
+       priv->hw_roc_start_notified = false;
+       cancel_delayed_work(&priv->hw_roc_disable_work);
+
+       if (!ctx->is_active) {
+               static const struct iwl_qos_info default_qos_data = {
+                       .def_qos_parm = {
+                               .ac[0] = {
+                                       .cw_min = cpu_to_le16(3),
+                                       .cw_max = cpu_to_le16(7),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(1504),
+                               },
+                               .ac[1] = {
+                                       .cw_min = cpu_to_le16(7),
+                                       .cw_max = cpu_to_le16(15),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(3008),
+                               },
+                               .ac[2] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 3,
+                               },
+                               .ac[3] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 7,
+                               },
+                       },
+               };
+
+               ctx->is_active = true;
+               ctx->qos_data = default_qos_data;
+               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+               memcpy(ctx->staging.node_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               memcpy(ctx->staging.bssid_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err)
+                       goto out;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+                                            RXON_FILTER_PROMISC_MSK |
+                                            RXON_FILTER_CTL2HOST_MSK;
+
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err) {
+                       iwlagn_disable_roc(priv);
+                       goto out;
+               }
+               priv->hw_roc_setup = true;
+       }
+
+       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+       if (err)
+               iwlagn_disable_roc(priv);
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
+       iwlagn_disable_roc(priv);
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return 0;
+}
+
+static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             const u8 *bssid,
+                             enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       u8 sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx)) {
+               ret = 0;
+               goto out;
+       }
+
+       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW,
+           &priv->shrd->status)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
+       if (ret)
+               goto out;
+
+       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
+               ret = -EIO;
+               goto out_remove_sta;
+       }
+
+       memcpy(ctx->bssid, bssid, ETH_ALEN);
+       ctx->preauth_bssid = true;
+
+       ret = iwlagn_commit_rxon(priv, ctx);
+
+       if (ret == 0)
+               goto out;
+
+ out_remove_sta:
+       iwl_remove_station(priv, sta_id, bssid);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const u8 *bssid,
+                                  enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx))
+               goto out;
+
+       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
+       ctx->preauth_bssid = false;
+       /* no need to commit */
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+                          enum ieee80211_rssi_event rssi_event)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (priv->cfg->bt_params &&
+                       priv->cfg->bt_params->advanced_bt_coexist) {
+               if (rssi_event == RSSI_EVENT_LOW)
+                       priv->bt_enable_pspoll = true;
+               else if (rssi_event == RSSI_EVENT_HIGH)
+                       priv->bt_enable_pspoll = false;
+
+               iwlagn_send_advance_bt_config(priv);
+       } else {
+               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
+                               "ignoring RSSI callback\n");
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
+                          struct ieee80211_sta *sta, bool set)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       queue_work(priv->shrd->workqueue, &priv->beacon_update);
+
+       return 0;
+}
+
+static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif, u16 queue,
+                   const struct ieee80211_tx_queue_params *params)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       unsigned long flags;
+       int q;
+
+       if (WARN_ON(!ctx))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!iwl_is_ready_rf(priv->shrd)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
+       }
+
+       if (queue >= AC_NUM) {
+               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+               return 0;
+       }
+
+       q = AC_NUM - 1 - queue;
+
+       spin_lock_irqsave(&priv->shrd->lock, flags);
+
+       ctx->qos_data.def_qos_parm.ac[q].cw_min =
+               cpu_to_le16(params->cw_min);
+       ctx->qos_data.def_qos_parm.ac[q].cw_max =
+               cpu_to_le16(params->cw_max);
+       ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+       ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+                       cpu_to_le16((params->txop * 32));
+
+       ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+
+       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       iwl_connection_init_rx_config(priv, ctx);
+
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       return iwlagn_commit_rxon(priv, ctx);
+}
+
+static int iwl_setup_interface(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       struct ieee80211_vif *vif = ctx->vif;
+       int err;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       /*
+        * This variable will be correct only when there's just
+        * a single context, but all code using it is for hardware
+        * that supports only one context.
+        */
+       priv->iw_mode = vif->type;
+
+       ctx->is_active = true;
+
+       err = iwl_set_mode(priv, ctx);
+       if (err) {
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+               return err;
+       }
+
+       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               /*
+                * pretend to have high BT traffic as long as we
+                * are operating in IBSS mode, as this will cause
+                * the rate scaling etc. to behave as intended.
+                */
+               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+       }
+
+       return 0;
+}
+
+static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *tmp, *ctx = NULL;
+       int err;
+       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+                          viftype, vif->addr);
+
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+       mutex_lock(&priv->shrd->mutex);
+
+       iwlagn_disable_roc(priv);
+
+       if (!iwl_is_ready_rf(priv->shrd)) {
+               IWL_WARN(priv, "Try to add interface when device not ready\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       for_each_context(priv, tmp) {
+               u32 possible_modes =
+                       tmp->interface_modes | tmp->exclusive_interface_modes;
+
+               if (tmp->vif) {
+                       /* check if this busy context is exclusive */
+                       if (tmp->exclusive_interface_modes &
+                                               BIT(tmp->vif->type)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (!(possible_modes & BIT(viftype)))
+                       continue;
+
+               /* have maybe usable context w/o interface */
+               ctx = tmp;
+               break;
+       }
+
+       if (!ctx) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       vif_priv->ctx = ctx;
+       ctx->vif = vif;
+
+       err = iwl_setup_interface(priv, ctx);
+       if (!err)
+               goto out;
+
+       ctx->vif = NULL;
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return err;
+}
+
+static void iwl_teardown_interface(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif,
+                                  bool mode_change)
+{
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (priv->scan_vif == vif) {
+               iwl_scan_cancel_timeout(priv, 200);
+               iwl_force_scan_end(priv);
+       }
+
+       if (!mode_change) {
+               iwl_set_mode(priv, ctx);
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+       }
+
+       /*
+        * When removing the IBSS interface, overwrite the
+        * BT traffic load with the stored one from the last
+        * notification, if any. If this is a device that
+        * doesn't implement this, this has no effect since
+        * both values are the same and zero.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC)
+               priv->bt_traffic_load = priv->last_bt_traffic_load;
+}
+
+static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (WARN_ON(ctx->vif != vif)) {
+               struct iwl_rxon_context *tmp;
+               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+               for_each_context(priv, tmp)
+                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+                               tmp->ctxid, tmp, tmp->vif);
+       }
+       ctx->vif = NULL;
+
+       iwl_teardown_interface(priv, vif, false);
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+
+static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               enum nl80211_iftype newtype, bool newp2p)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_rxon_context *tmp;
+       enum nl80211_iftype newviftype = newtype;
+       u32 interface_modes;
+       int err;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       newtype = ieee80211_iftype_p2p(newtype, newp2p);
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
+               /*
+                * Huh? But wait ... this can maybe happen when
+                * we're in the middle of a firmware restart!
+                */
+               err = -EBUSY;
+               goto out;
+       }
+
+       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
+
+       if (!(interface_modes & BIT(newtype))) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       /*
+        * Refuse a change that should be done by moving from the PAN
+        * context to the BSS context instead, if the BSS context is
+        * available and can support the new interface type.
+        */
+       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
+           (bss_ctx->interface_modes & BIT(newtype) ||
+            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
+               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+               err = -EBUSY;
+               goto out;
+       }
+
+       if (ctx->exclusive_interface_modes & BIT(newtype)) {
+               for_each_context(priv, tmp) {
+                       if (ctx == tmp)
+                               continue;
+
+                       if (!tmp->vif)
+                               continue;
+
+                       /*
+                        * The current mode switch would be exclusive, but
+                        * another context is active ... refuse the switch.
+                        */
+                       err = -EBUSY;
+                       goto out;
+               }
+       }
+
+       /* success */
+       iwl_teardown_interface(priv, vif, true);
+       vif->type = newviftype;
+       vif->p2p = newp2p;
+       err = iwl_setup_interface(priv, ctx);
+       WARN_ON(err);
+       /*
+        * We've switched internally, but submitting to the
+        * device may have failed for some reason. Mask this
+        * error, because otherwise mac80211 will not switch
+        * (and set the interface type back) and we'll be
+        * out of sync with it.
+        */
+       err = 0;
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (req->n_channels == 0)
+               return -EINVAL;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       /*
+        * If an internal scan is in progress, just set
+        * up the scan_request as per above.
+        */
+       if (priv->scan_type != IWL_SCAN_NORMAL) {
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               ret = 0;
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
+               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
+                                       req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       return ret;
+}
+
+static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
+                          "station %pM\n", sta->addr);
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
+                       sta->addr);
+       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+       if (ret)
+               IWL_DEBUG_QUIET_RFKILL(priv, "Error removing station %pM\n",
+                       sta->addr);
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.sta.modify_mask = 0;
+       priv->stations[sta_id].sta.sleep_tx_count = 0;
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+
+}
+
+static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif,
+                          enum sta_notify_cmd cmd,
+                          struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       switch (cmd) {
+       case STA_NOTIFY_SLEEP:
+               WARN_ON(!sta_priv->client);
+               sta_priv->asleep = true;
+               if (atomic_read(&sta_priv->pending_frames) > 0)
+                       ieee80211_sta_block_awake(hw, sta, true);
+               break;
+       case STA_NOTIFY_AWAKE:
+               WARN_ON(!sta_priv->client);
+               if (!sta_priv->asleep)
+                       break;
+               sta_priv->asleep = false;
+               sta_id = iwl_sta_id(sta);
+               if (sta_id != IWL_INVALID_STATION)
+                       iwl_sta_modify_ps_wake(priv, sta_id);
+               break;
+       default:
+               break;
+       }
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+struct ieee80211_ops iwlagn_hw_ops = {
+       .tx = iwlagn_mac_tx,
+       .start = iwlagn_mac_start,
+       .stop = iwlagn_mac_stop,
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwlagn_mac_suspend,
+       .resume = iwlagn_mac_resume,
+#endif
+       .add_interface = iwlagn_mac_add_interface,
+       .remove_interface = iwlagn_mac_remove_interface,
+       .change_interface = iwlagn_mac_change_interface,
+       .config = iwlagn_mac_config,
+       .configure_filter = iwlagn_configure_filter,
+       .set_key = iwlagn_mac_set_key,
+       .update_tkip_key = iwlagn_mac_update_tkip_key,
+       .set_rekey_data = iwlagn_mac_set_rekey_data,
+       .conf_tx = iwlagn_mac_conf_tx,
+       .bss_info_changed = iwlagn_bss_info_changed,
+       .ampdu_action = iwlagn_mac_ampdu_action,
+       .hw_scan = iwlagn_mac_hw_scan,
+       .sta_notify = iwlagn_mac_sta_notify,
+       .sta_add = iwlagn_mac_sta_add,
+       .sta_remove = iwlagn_mac_sta_remove,
+       .channel_switch = iwlagn_mac_channel_switch,
+       .flush = iwlagn_mac_flush,
+       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
+       .remain_on_channel = iwlagn_mac_remain_on_channel,
+       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
+       .rssi_callback = iwlagn_mac_rssi_callback,
+       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
+       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
+       .tx_sync = iwlagn_mac_tx_sync,
+       .finish_tx_sync = iwlagn_mac_finish_tx_sync,
+       .set_tim = iwlagn_mac_set_tim,
+};
+
+/* This function both allocates and initializes hw and priv. */
+struct ieee80211_hw *iwl_alloc_all(void)
+{
+       struct iwl_priv *priv;
+       /* mac80211 allocates memory for this device instance, including
+        *   space for this driver's private structure */
+       struct ieee80211_hw *hw;
+
+       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
+       if (!hw)
+               goto out;
+
+       priv = hw->priv;
+       priv->hw = hw;
+
+out:
+       return hw;
+}
index 1800029911adfa1e21dfc8d3c6b0d59614daf88f..850ec8e51b176738544b755bdbea8687e1f0b3be 100644 (file)
@@ -256,6 +256,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */
+       {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */
 
 /* 6x30 Series */
        {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -325,46 +327,28 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)},
        {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
 
 /* 2x30 Series */
        {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)},
 
 /* 6x35 Series */
        {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)},
 
 /* 105 Series */
        {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)},
        {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
 
 /* 135 Series */
        {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)},
 
        {0}
 };
index e5d727f537d08eb09080fa8170609771cb230b5b..359d2182757bbbb6c567b2fb9cb4d7291021df4c 100644 (file)
@@ -416,6 +416,8 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
 
                if (!iwl_is_associated_ctx(ctx))
                        continue;
+               if (ctx->staging.dev_type == RXON_DEV_TYPE_P2P)
+                       continue;
                value = ctx->beacon_int;
                if (!value)
                        value = IWL_PASSIVE_DWELL_BASE;
@@ -678,7 +680,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        priv->contexts[IWL_RXON_CTX_BSS].active.flags &
                                                RXON_FLG_CHANNEL_MODE_MSK)
                                       >> RXON_FLG_CHANNEL_MODE_POS;
-               if (chan_mod == CHANNEL_MODE_PURE_40) {
+               if ((priv->scan_request && priv->scan_request->no_cck) ||
+                   chan_mod == CHANNEL_MODE_PURE_40) {
                        rate = IWL_RATE_6M_PLCP;
                } else {
                        rate = IWL_RATE_1M_PLCP;
@@ -938,51 +941,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
        return 0;
 }
 
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif,
-                   struct cfg80211_scan_request *req)
-{
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (req->n_channels == 0)
-               return -EINVAL;
-
-       mutex_lock(&priv->shrd->mutex);
-
-       /*
-        * If an internal scan is in progress, just set
-        * up the scan_request as per above.
-        */
-       if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv,
-                              "SCAN request during internal scan - defer\n");
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               ret = 0;
-       } else {
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               /*
-                * mac80211 will only ask for one band at a time
-                * so using channels[0] here is ok
-                */
-               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
-                                       req->channels[0]->band);
-               if (ret) {
-                       priv->scan_request = NULL;
-                       priv->scan_vif = NULL;
-               }
-       }
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       return ret;
-}
 
 /*
  * internal short scan, this function should only been called while associated.
index 5e50d88f302b761e565f8e4b24989a46639a14c0..e3882d0cfc85b9ce4c1bee214596a40c9ecfe2be 100644 (file)
@@ -396,8 +396,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-               status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
-                                                     IWL_UCODE_INIT);
+               status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
                if (status)
                        IWL_DEBUG_INFO(priv,
                                "Error loading init ucode: %d\n", status);
@@ -409,9 +408,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-               status = iwlagn_load_ucode_wait_alive(priv,
-                                          &priv->ucode_rt,
-                                          IWL_UCODE_REGULAR);
+               status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
                if (status) {
                        IWL_DEBUG_INFO(priv,
                                "Error loading runtime ucode: %d\n", status);
index 2b6756e8b8f97578394bdfd2a473f8acd0bd95d6..afaaa2a51b966e0bb93477f03fabfbb5590f0d40 100644 (file)
@@ -355,7 +355,7 @@ static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_tx_queue *txq, const char *msg)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -363,13 +363,22 @@ static inline void iwl_wake_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (test_and_clear_bit(hwq, trans_pcie->queue_stopped))
-               if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0)
+       if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) {
+               if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) {
                        iwl_wake_sw_queue(priv(trans), ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s",
+                                           hwq, ac, msg);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(trans, "Don't wake hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               }
+       }
 }
 
 static inline void iwl_stop_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_tx_queue *txq, const char *msg)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -377,9 +386,23 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (!test_and_set_bit(hwq, trans_pcie->queue_stopped))
-               if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0)
+       if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) {
+               if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) {
                        iwl_stop_sw_queue(priv(trans), ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(trans, "Don't stop hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               }
+       } else {
+               IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped/ %s",
+                                   hwq, msg);
+       }
 }
 
 #ifdef ieee80211_stop_queue
index 374c68cc1d705dca84ed42d75714524f3e0569b1..ee126f844a5c412f8eafaf32ea0b5e7daecfbd55 100644 (file)
@@ -1108,7 +1108,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                isr_stats->tx++;
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
-               priv(trans)->ucode_write_complete = 1;
+               trans->ucode_write_complete = 1;
                wake_up(&trans->shrd->wait_command_queue);
        }
 
index 4a0c95302a7e89f08021257f76468dbf43dae0a4..6dba1515023c89efcc95330da663c34c336ea3fd 100644 (file)
@@ -430,7 +430,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
 
        txq->sched_retry = scd_retry;
 
-       IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n",
+       IWL_DEBUG_TX_QUEUES(trans, "%s %s Queue %d on FIFO %d\n",
                       active ? "Activate" : "Deactivate",
                       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
 }
@@ -561,12 +561,13 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
 
        tid_data = &trans->shrd->tid_data[sta_id][tid];
        if (tid_data->tfds_in_queue == 0) {
-               IWL_DEBUG_HT(trans, "HW queue is empty\n");
+               IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
                iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
        } else {
-               IWL_DEBUG_HT(trans, "HW queue is NOT empty: %d packets in HW"
-                            "queue\n", tid_data->tfds_in_queue);
+               IWL_DEBUG_TX_QUEUES(trans,
+                                   "HW queue is NOT empty: %d packets in HW"
+                                   " queue\n", tid_data->tfds_in_queue);
                tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
        }
        spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
@@ -643,14 +644,15 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
 
        /* The queue is not empty */
        if (write_ptr != read_ptr) {
-               IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n");
+               IWL_DEBUG_TX_QUEUES(trans,
+                                   "Stopping a non empty AGG HW QUEUE\n");
                trans->shrd->tid_data[sta_id][tid].agg.state =
                        IWL_EMPTYING_HW_QUEUE_DELBA;
                spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
                return 0;
        }
 
-       IWL_DEBUG_HT(trans, "HW queue is empty\n");
+       IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n");
 turn_off:
        trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
 
@@ -982,7 +984,8 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        ret = iwl_enqueue_hcmd(trans, cmd);
        if (ret < 0) {
-               IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
+               IWL_DEBUG_QUIET_RFKILL(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
        }
@@ -1000,6 +1003,20 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                        get_cmd_string(cmd->id));
 
+       if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
+               return -EBUSY;
+
+
+       if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
+               IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
+                              get_cmd_string(cmd->id));
+               return -ECANCELED;
+       }
+       if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
+               IWL_ERR(trans, "Command %s failed: FW Error\n",
+                              get_cmd_string(cmd->id));
+               return -EIO;
+       }
        set_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
        IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
                        get_cmd_string(cmd->id));
@@ -1008,7 +1025,8 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (cmd_idx < 0) {
                ret = cmd_idx;
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
-               IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
+               IWL_DEBUG_QUIET_RFKILL(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
        }
@@ -1022,12 +1040,12 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                                &trans_pcie->txq[trans->shrd->cmd_queue];
                        struct iwl_queue *q = &txq->q;
 
-                       IWL_ERR(trans,
+                       IWL_DEBUG_QUIET_RFKILL(trans,
                                "Error sending %s: time out after %dms.\n",
                                get_cmd_string(cmd->id),
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
-                       IWL_ERR(trans,
+                       IWL_DEBUG_QUIET_RFKILL(trans,
                                "Current CMD queue read_ptr %d write_ptr %d\n",
                                q->read_ptr, q->write_ptr);
 
@@ -1039,18 +1057,6 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                }
        }
 
-       if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
-               IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
-                              get_cmd_string(cmd->id));
-               ret = -ECANCELED;
-               goto fail;
-       }
-       if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
-               IWL_ERR(trans, "Command %s failed: FW Error\n",
-                              get_cmd_string(cmd->id));
-               ret = -EIO;
-               goto fail;
-       }
        if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
                IWL_ERR(trans, "Error: Response NULL in '%s'\n",
                          get_cmd_string(cmd->id));
@@ -1071,7 +1077,7 @@ cancel:
                trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &=
                                                        ~CMD_WANT_SKB;
        }
-fail:
+
        if (cmd->reply_page) {
                iwl_free_pages(trans->shrd, cmd->reply_page);
                cmd->reply_page = 0;
index ce918980e97799a51fc3b0b9a732d28fe706c84a..93c4f56ac408b5beb783836b2d9ac0fc5e897784 100644 (file)
@@ -1232,7 +1232,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                        txq->need_update = 1;
                        iwl_txq_update_write_ptr(trans, txq);
                } else {
-                       iwl_stop_queue(trans, txq);
+                       iwl_stop_queue(trans, txq, "Queue is full");
                }
        }
        return 0;
@@ -1284,20 +1284,21 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
                /* aggregated HW queue */
                if ((txq_id  == tid_data->agg.txq_id) &&
                    (q->read_ptr == q->write_ptr)) {
-                       IWL_DEBUG_HT(trans,
+                       IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue DELBA flow\n");
                        iwl_trans_pcie_txq_agg_disable(trans, txq_id);
                        tid_data->agg.state = IWL_AGG_OFF;
                        iwl_stop_tx_ba_trans_ready(priv(trans),
                                                   NUM_IWL_RXON_CTX,
                                                   sta_id, tid);
-                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id],
+                                      "DELBA flow complete");
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
                /* We are reclaiming the last packet of the queue */
                if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(trans,
+                       IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
                        iwl_start_tx_ba_trans_ready(priv(trans),
@@ -1355,7 +1356,7 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                                ssn , tfd_num, txq_id, txq->swq_id);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
-                       iwl_wake_queue(trans, txq);
+                       iwl_wake_queue(trans, txq, "Packets reclaimed");
        }
 
        iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
@@ -1419,7 +1420,8 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 #endif /* CONFIG_PM_SLEEP */
 
 static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
-                                         enum iwl_rxon_context_id ctx)
+                                         enum iwl_rxon_context_id ctx,
+                                         const char *msg)
 {
        u8 ac, txq_id;
        struct iwl_trans_pcie *trans_pcie =
@@ -1427,11 +1429,11 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
 
        for (ac = 0; ac < AC_NUM; ac++) {
                txq_id = trans_pcie->ac_to_queue[ctx][ac];
-               IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
+               IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n",
                        ac,
                        (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
                              ? "stopped" : "awake");
-               iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+               iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg);
        }
 }
 
@@ -1454,11 +1456,12 @@ static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
        return iwl_trans;
 }
 
-static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
+static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id,
+                                     const char *msg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
+       iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg);
 }
 
 #define IWL_FLUSH_WAIT_MS      2000
index c5923125c3f96bb8fe7625e2b59e0ba1cde4b8d7..50227ebc0ee22243d9baffde3b8223663923c696 100644 (file)
@@ -171,7 +171,8 @@ struct iwl_trans_ops {
        void (*tx_start)(struct iwl_trans *trans);
 
        void (*wake_any_queue)(struct iwl_trans *trans,
-                              enum iwl_rxon_context_id ctx);
+                              enum iwl_rxon_context_id ctx,
+                              const char *msg);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -196,7 +197,7 @@ struct iwl_trans_ops {
 
        void (*free)(struct iwl_trans *trans);
 
-       void (*stop_queue)(struct iwl_trans *trans, int q);
+       void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg);
 
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
        int (*check_stuck_queue)(struct iwl_trans *trans, int q);
@@ -207,17 +208,48 @@ struct iwl_trans_ops {
 #endif
 };
 
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+       dma_addr_t p_addr;      /* hardware address */
+       void *v_addr;           /* software address */
+       u32 len;                /* size in bytes */
+};
+
+struct fw_img {
+       struct fw_desc code;    /* firmware code image */
+       struct fw_desc data;    /* firmware data image */
+};
+
+enum iwl_ucode_type {
+       IWL_UCODE_NONE,
+       IWL_UCODE_REGULAR,
+       IWL_UCODE_INIT,
+       IWL_UCODE_WOWLAN,
+};
+
 /**
  * struct iwl_trans - transport common data
  * @ops - pointer to iwl_trans_ops
  * @shrd - pointer to iwl_shared which holds shared data from the upper layer
  * @hcmd_lock: protects HCMD
+ * @ucode_write_complete: indicates that the ucode has been copied.
+ * @ucode_rt: run time ucode image
+ * @ucode_init: init ucode image
+ * @ucode_wowlan: wake on wireless ucode image (optional)
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
        struct iwl_shared *shrd;
        spinlock_t hcmd_lock;
 
+       u8 ucode_write_complete;        /* the image write is complete */
+       struct fw_img ucode_rt;
+       struct fw_img ucode_init;
+       struct fw_img ucode_wowlan;
+
+       /* eeprom related variables */
+       int    nvm_device_type;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __attribute__((__aligned__(sizeof(void *))));
@@ -249,9 +281,10 @@ static inline void iwl_trans_tx_start(struct iwl_trans *trans)
 }
 
 static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
-                                           enum iwl_rxon_context_id ctx)
+                                           enum iwl_rxon_context_id ctx,
+                                           const char *msg)
 {
-       trans->ops->wake_any_queue(trans, ctx);
+       trans->ops->wake_any_queue(trans, ctx, msg);
 }
 
 
@@ -311,9 +344,10 @@ static inline void iwl_trans_free(struct iwl_trans *trans)
        trans->ops->free(trans);
 }
 
-static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q)
+static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q,
+                                       const char *msg)
 {
-       trans->ops->stop_queue(trans, q);
+       trans->ops->stop_queue(trans, q, msg);
 }
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
@@ -348,4 +382,8 @@ static inline int iwl_trans_resume(struct iwl_trans *trans)
 ******************************************************/
 extern const struct iwl_trans_ops trans_ops_pcie;
 
+int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
+                     const void *data, size_t len);
+void iwl_dealloc_ucode(struct iwl_trans *trans);
+
 #endif /* __iwl_trans_h__ */
index c42be81e979ebd700742154922acce4fcb6acde7..48e8218fd23bc32ad79f56c007b10fbb49109ff9 100644 (file)
@@ -165,11 +165,15 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                struct key_params *params)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       struct iwm_key *key = &iwm->keys[key_index];
+       struct iwm_key *key;
        int ret;
 
        IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
+       key = &iwm->keys[key_index];
        memset(key, 0, sizeof(struct iwm_key));
        ret = iwm_key_init(key, key_index, mac_addr, params);
        if (ret < 0) {
@@ -214,8 +218,12 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
                                u8 key_index, bool pairwise, const u8 *mac_addr)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       struct iwm_key *key = &iwm->keys[key_index];
+       struct iwm_key *key;
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
+       key = &iwm->keys[key_index];
        if (!iwm->keys[key_index].key_len) {
                IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
                return 0;
@@ -236,6 +244,9 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 
        IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
        if (!iwm->keys[key_index].key_len) {
                IWM_ERR(iwm, "Key %d not used\n", key_index);
                return -EINVAL;
index a7f1ab28940d3ae6ad8e4fbda26b18087b4c21b4..d1d84e0e30fcfd2e6a19aa11dbdc6e6db2c77112 100644 (file)
@@ -485,6 +485,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
 static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
        struct cmd_header *resp)
 {
+       struct cfg80211_bss *bss;
        struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
        int bsssize;
        const u8 *pos;
@@ -632,12 +633,14 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                                     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
 
                        if (channel &&
-                           !(channel->flags & IEEE80211_CHAN_DISABLED))
-                               cfg80211_inform_bss(wiphy, channel,
+                           !(channel->flags & IEEE80211_CHAN_DISABLED)) {
+                               bss = cfg80211_inform_bss(wiphy, channel,
                                        bssid, get_unaligned_le64(tsfdesc),
                                        capa, intvl, ie, ielen,
                                        LBS_SCAN_RSSI_TO_MBM(rssi),
                                        GFP_KERNEL);
+                               cfg80211_put_bss(bss);
+                       }
                } else
                        lbs_deb_scan("scan response: missing BSS channel IE\n");
 
@@ -1720,6 +1723,7 @@ static void lbs_join_post(struct lbs_private *priv,
                   2 + 2 +                      /* atim */
                   2 + 8];                      /* extended rates */
        u8 *fake = fake_ie;
+       struct cfg80211_bss *bss;
 
        lbs_deb_enter(LBS_DEB_CFG80211);
 
@@ -1763,14 +1767,15 @@ static void lbs_join_post(struct lbs_private *priv,
        *fake++ = 0x6c;
        lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
 
-       cfg80211_inform_bss(priv->wdev->wiphy,
-                           params->channel,
-                           bssid,
-                           0,
-                           capability,
-                           params->beacon_interval,
-                           fake_ie, fake - fake_ie,
-                           0, GFP_KERNEL);
+       bss = cfg80211_inform_bss(priv->wdev->wiphy,
+                                 params->channel,
+                                 bssid,
+                                 0,
+                                 capability,
+                                 params->beacon_interval,
+                                 fake_ie, fake - fake_ie,
+                                 0, GFP_KERNEL);
+       cfg80211_put_bss(bss);
 
        memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
        priv->wdev->ssid_len = params->ssid_len;
index 523ad55a288501af3931b03ae56eef98756bbeb7..6cf6d6d25e217bd1718fe3cb98f40b5078ad60a6 100644 (file)
@@ -1748,6 +1748,8 @@ static int __init init_mac80211_hwsim(void)
                            IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                            IEEE80211_HW_AMPDU_AGGREGATION;
 
+               hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
                hw->sta_data_size = sizeof(struct hwsim_sta_priv);
index 7aa9aa0ac958eba09e8661d05b16a512ccec49d2..681d3f2a4c2885b82b0e76256403bca2c060f782 100644 (file)
@@ -33,7 +33,7 @@
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
  */
-static int
+static void
 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
                                         struct mwifiex_rx_reorder_tbl
                                         *rx_reor_tbl_ptr, int start_win)
@@ -71,8 +71,6 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
 
        rx_reor_tbl_ptr->start_win = start_win;
        spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-
-       return 0;
 }
 
 /*
@@ -83,7 +81,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
  */
-static int
+static void
 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                              struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
 {
@@ -119,7 +117,6 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
        rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
                &(MAX_TID_VALUE - 1);
        spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-       return 0;
 }
 
 /*
@@ -405,7 +402,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                                u8 *ta, u8 pkt_type, void *payload)
 {
        struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
-       int start_win, end_win, win_size, ret;
+       int start_win, end_win, win_size;
        u16 pkt_index;
 
        rx_reor_tbl_ptr =
@@ -452,11 +449,8 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                        start_win = (end_win - win_size) + 1;
                else
                        start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
-               ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
+               mwifiex_11n_dispatch_pkt_until_start_win(priv,
                                                rx_reor_tbl_ptr, start_win);
-
-               if (ret)
-                       return ret;
        }
 
        if (pkt_type != PKT_TYPE_BAR) {
@@ -475,9 +469,9 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
         * Dispatch all packets sequentially from start_win until a
         * hole is found and adjust the start_win appropriately
         */
-       ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+       mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
 
-       return ret;
+       return 0;
 }
 
 /*
index 462c71067bfb83d6d445946e6137991dbc3ab617..e9ab9a3fbe9c2cb70ac2da2c0dbf3e1226c21bad 100644 (file)
@@ -780,6 +780,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
 {
        struct ieee80211_channel *chan;
        struct mwifiex_bss_info bss_info;
+       struct cfg80211_bss *bss;
        int ie_len;
        u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
        enum ieee80211_band band;
@@ -800,9 +801,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                        ieee80211_channel_to_frequency(bss_info.bss_chan,
                                                       band));
 
-       cfg80211_inform_bss(priv->wdev->wiphy, chan,
+       bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
                bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
                0, ie_buf, ie_len, 0, GFP_KERNEL);
+       cfg80211_put_bss(bss);
        memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
 
        return 0;
index 0cc5d73cb0c1e99730b4ebcbd882bc765ac187f0..35cb29cbd96e5d083b438fa62c22e85493dec45d 100644 (file)
@@ -673,7 +673,7 @@ struct host_cmd_ds_802_11_ad_hoc_start {
        union ieee_types_phy_param_set phy_param_set;
        u16 reserved1;
        __le16 cap_info_bitmap;
-       u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+       u8 data_rate[HOSTCMD_SUPPORTED_RATES];
 } __packed;
 
 struct host_cmd_ds_802_11_ad_hoc_result {
index d792b3fb7c16ec407984288772eaa1e17a21c6b6..26940455255ba4637fdd31ec19a3407640f71e87 100644 (file)
@@ -187,8 +187,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL;
 
        skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm));
-       sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
-                                               (adapter->sleep_cfm->data);
 
        adapter->cmd_sent = false;
 
@@ -254,6 +252,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        mwifiex_wmm_init(adapter);
 
        if (adapter->sleep_cfm) {
+               sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
+                                               adapter->sleep_cfm->data;
                memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len);
                sleep_cfm_buf->command =
                                cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
index 62b4c2938608d67873d66afb8be9e288247820b9..1c4981367e508fbaa45fd6e5648452e75da5ee7c 100644 (file)
@@ -724,8 +724,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        u32 cmd_append_size = 0;
        u32 i;
        u16 tmp_cap;
-       uint16_t ht_cap_info;
        struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+       u8 radio_type;
 
        struct mwifiex_ie_types_htcap *ht_cap;
        struct mwifiex_ie_types_htinfo *ht_info;
@@ -837,8 +837,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
        }
 
-       memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
-       mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
+       memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate));
+       mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
        if ((adapter->adhoc_start_band & BAND_G) &&
            (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
                if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
@@ -850,20 +850,19 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                }
        }
        /* Find the last non zero */
-       for (i = 0; i < sizeof(adhoc_start->DataRate) &&
-                       adhoc_start->DataRate[i];
-                       i++)
-                       ;
+       for (i = 0; i < sizeof(adhoc_start->data_rate); i++)
+               if (!adhoc_start->data_rate[i])
+                       break;
 
        priv->curr_bss_params.num_of_rates = i;
 
        /* Copy the ad-hoc creating rates into Current BSS rate structure */
        memcpy(&priv->curr_bss_params.data_rates,
-              &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
+              &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
 
        dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
-              adhoc_start->DataRate[0], adhoc_start->DataRate[1],
-              adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
+              adhoc_start->data_rate[0], adhoc_start->data_rate[1],
+              adhoc_start->data_rate[2], adhoc_start->data_rate[3]);
 
        dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
 
@@ -914,55 +913,40 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        }
 
        if (adapter->adhoc_11n_enabled) {
-               {
-                       ht_cap = (struct mwifiex_ie_types_htcap *) pos;
-                       memset(ht_cap, 0,
-                              sizeof(struct mwifiex_ie_types_htcap));
-                       ht_cap->header.type =
-                               cpu_to_le16(WLAN_EID_HT_CAPABILITY);
-                       ht_cap->header.len =
-                              cpu_to_le16(sizeof(struct ieee80211_ht_cap));
-                       ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
-
-                       ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
-                       if (adapter->chan_offset) {
-                               ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
-                               ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
-                               ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-                               SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
-                       }
+               /* Fill HT CAPABILITY */
+               ht_cap = (struct mwifiex_ie_types_htcap *) pos;
+               memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+               ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+               ht_cap->header.len =
+                      cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+               radio_type = mwifiex_band_to_radio_type(
+                                       priv->adapter->config_bands);
+               mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+
+               pos += sizeof(struct mwifiex_ie_types_htcap);
+               cmd_append_size +=
+                       sizeof(struct mwifiex_ie_types_htcap);
 
-                       ht_cap->ht_cap.ampdu_params_info
-                                       = IEEE80211_HT_MAX_AMPDU_64K;
-                       ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
-                       pos += sizeof(struct mwifiex_ie_types_htcap);
-                       cmd_append_size +=
-                               sizeof(struct mwifiex_ie_types_htcap);
-               }
-               {
-                       ht_info = (struct mwifiex_ie_types_htinfo *) pos;
-                       memset(ht_info, 0,
-                              sizeof(struct mwifiex_ie_types_htinfo));
-                       ht_info->header.type =
-                               cpu_to_le16(WLAN_EID_HT_INFORMATION);
-                       ht_info->header.len =
-                               cpu_to_le16(sizeof(struct ieee80211_ht_info));
-                       ht_info->ht_info.control_chan =
-                               (u8) priv->curr_bss_params.bss_descriptor.
-                               channel;
-                       if (adapter->chan_offset) {
-                               ht_info->ht_info.ht_param =
-                                       adapter->chan_offset;
-                               ht_info->ht_info.ht_param |=
+               /* Fill HT INFORMATION */
+               ht_info = (struct mwifiex_ie_types_htinfo *) pos;
+               memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo));
+               ht_info->header.type = cpu_to_le16(WLAN_EID_HT_INFORMATION);
+               ht_info->header.len =
+                       cpu_to_le16(sizeof(struct ieee80211_ht_info));
+
+               ht_info->ht_info.control_chan =
+                       (u8) priv->curr_bss_params.bss_descriptor.channel;
+               if (adapter->chan_offset) {
+                       ht_info->ht_info.ht_param = adapter->chan_offset;
+                       ht_info->ht_info.ht_param |=
                                        IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
-                       }
-                       ht_info->ht_info.operation_mode =
-                            cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-                       ht_info->ht_info.basic_set[0] = 0xff;
-                       pos += sizeof(struct mwifiex_ie_types_htinfo);
-                       cmd_append_size +=
-                               sizeof(struct mwifiex_ie_types_htinfo);
                }
+               ht_info->ht_info.operation_mode =
+                    cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+               ht_info->ht_info.basic_set[0] = 0xff;
+               pos += sizeof(struct mwifiex_ie_types_htinfo);
+               cmd_append_size +=
+                       sizeof(struct mwifiex_ie_types_htinfo);
        }
 
        cmd->size = cpu_to_le16((u16)
index d34acf082d3ae03fdc0b35b58f19a924415915a0..a2f32008f9a80810355c8c4cc145ada8199d9516 100644 (file)
@@ -386,7 +386,6 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
        card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
        if (!card->txbd_ring_vbase) {
                dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n");
-               kfree(card->txbd_ring_vbase);
                return -1;
        }
        card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
@@ -1229,9 +1228,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
        if (!skb)
                return 0;
 
-       if (rdptr >= MWIFIEX_MAX_EVT_BD)
+       if (rdptr >= MWIFIEX_MAX_EVT_BD) {
                dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
                                        rdptr);
+               ret = -EINVAL;
+               goto done;
+       }
 
        /* Read the event ring write pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
@@ -1672,9 +1674,8 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
                                     struct sk_buff *skb,
                                     struct mwifiex_tx_param *tx_param)
 {
-       if (!adapter || !skb) {
-               dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n",
-                               __func__, adapter, skb);
+       if (!skb) {
+               dev_err(adapter->dev, "Passed NULL skb to %s\n", __func__);
                return -1;
        }
 
index 8d3ab378662b77ac4c55c40bceba1b8a53715552..b8b9d37b01a948673278f5beccb9ce87c916d922 100644 (file)
@@ -1537,11 +1537,6 @@ done:
        return 0;
 }
 
-static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
-{
-       kfree(bss->priv);
-}
-
 /*
  * This function handles the command response of scan.
  *
@@ -1767,7 +1762,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                              cap_info_bitmap, beacon_period,
                                              ie_buf, ie_len, rssi, GFP_KERNEL);
                                *(u8 *)bss->priv = band;
-                               bss->free_priv = mwifiex_free_bss_priv;
+                               cfg80211_put_bss(bss);
 
                                if (priv->media_connected && !memcmp(bssid,
                                        priv->curr_bss_params.bss_descriptor
index 283171bbcedf70a1b9cec51c33b3e7c7874196c4..ffaf3f3a57df047beea84986504a071b4b05e3ca 100644 (file)
@@ -1630,14 +1630,14 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        card->mpa_tx.pkt_cnt = 0;
        card->mpa_tx.start_port = 0;
 
-       card->mpa_tx.enabled = 0;
+       card->mpa_tx.enabled = 1;
        card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
 
        card->mpa_rx.buf_len = 0;
        card->mpa_rx.pkt_cnt = 0;
        card->mpa_rx.start_port = 0;
 
-       card->mpa_rx.enabled = 0;
+       card->mpa_rx.enabled = 1;
        card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
 
        /* Allocate buffers for SDIO MP-A */
index 27430512f7cd038a91d42d4848609991f297a72f..5e1ef7e5da4f3f5b2679c47d012588e642be093f 100644 (file)
@@ -126,6 +126,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
        u16 rx_pkt_type;
        struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
 
+       if (!priv)
+               return -1;
+
        local_rx_pd = (struct rxpd *) (skb->data);
        rx_pkt_type = local_rx_pd->rx_pkt_type;
 
@@ -189,12 +192,11 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
                                             (u8) local_rx_pd->rx_pkt_type,
                                             skb);
 
-       if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
-               if (priv && (ret == -1))
-                       priv->stats.rx_dropped++;
-
+       if (ret || (rx_pkt_type == PKT_TYPE_BAR))
                dev_kfree_skb_any(skb);
-       }
+
+       if (ret)
+               priv->stats.rx_dropped++;
 
        return ret;
 }
index e99ca1c1e0d8053689d7cbcabb5d07733dda03b1..96e39edfec770c58363237e9fa2955d4f16e567e 100644 (file)
@@ -76,6 +76,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *cbss;
        u8 *ie;
        u8 ie_buf[46];
        u64 timestamp;
@@ -121,9 +122,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
        beacon_interval = le16_to_cpu(bss->a.beacon_interv);
        signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
 
-       cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
-                           capability, beacon_interval, ie_buf, ie_len,
-                           signal, GFP_KERNEL);
+       cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+                                  capability, beacon_interval, ie_buf, ie_len,
+                                  signal, GFP_KERNEL);
+       cfg80211_put_bss(cbss);
 }
 
 void orinoco_add_extscan_result(struct orinoco_private *priv,
@@ -132,6 +134,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *cbss;
        const u8 *ie;
        u64 timestamp;
        s32 signal;
@@ -152,9 +155,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
        ie = bss->data;
        signal = SIGNAL_TO_MBM(bss->level);
 
-       cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
-                           capability, beacon_interval, ie, ie_len,
-                           signal, GFP_KERNEL);
+       cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+                                  capability, beacon_interval, ie, ie_len,
+                                  signal, GFP_KERNEL);
+       cfg80211_put_bss(cbss);
 }
 
 void orinoco_add_hostscan_results(struct orinoco_private *priv,
index 0c13840a7de57c0d675e026267a3ca3b95edc9fa..620e3c0e88e039152b39ddbe3f2173be46b6aa1e 100644 (file)
@@ -414,6 +414,7 @@ struct ndis_80211_pmkid {
 #define RNDIS_WLAN_ALG_TKIP    (1<<1)
 #define RNDIS_WLAN_ALG_CCMP    (1<<2)
 
+#define RNDIS_WLAN_NUM_KEYS            4
 #define RNDIS_WLAN_KEY_MGMT_NONE       0
 #define RNDIS_WLAN_KEY_MGMT_802_1X     (1<<0)
 #define RNDIS_WLAN_KEY_MGMT_PSK                (1<<1)
@@ -516,7 +517,7 @@ struct rndis_wlan_private {
 
        /* encryption stuff */
        int  encr_tx_key_index;
-       struct rndis_wlan_encr_key encr_keys[4];
+       struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS];
        int  wpa_version;
 
        u8 command_buffer[COMMAND_BUFFER_SIZE];
@@ -1535,6 +1536,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
        bool is_wpa;
        int ret;
 
+       if (index >= RNDIS_WLAN_NUM_KEYS)
+               return -ENOENT;
+
        if (priv->encr_keys[index].len == 0)
                return 0;
 
@@ -1972,11 +1976,12 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
-static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
-                                       struct ndis_80211_bssid_ex *bssid)
+static bool rndis_bss_info_update(struct usbnet *usbdev,
+                                 struct ndis_80211_bssid_ex *bssid)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *bss;
        s32 signal;
        u64 timestamp;
        u16 capability;
@@ -2015,9 +2020,12 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
        capability = le16_to_cpu(fixed->capabilities);
        beacon_interval = le16_to_cpu(fixed->beacon_interval);
 
-       return cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
                timestamp, capability, beacon_interval, ie, ie_len, signal,
                GFP_KERNEL);
+       cfg80211_put_bss(bss);
+
+       return (bss != NULL);
 }
 
 static struct ndis_80211_bssid_ex *next_bssid_list_item(
@@ -2451,6 +2459,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 
        netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index);
 
+       if (key_index >= RNDIS_WLAN_NUM_KEYS)
+               return -ENOENT;
+
        priv->encr_tx_key_index = key_index;
 
        if (is_wpa_key(priv, key_index))
@@ -2641,6 +2652,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
        struct ieee80211_channel *channel;
        struct ndis_80211_conf config;
        struct ndis_80211_ssid ssid;
+       struct cfg80211_bss *bss;
        s32 signal;
        u64 timestamp;
        u16 capability;
@@ -2714,9 +2726,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
                bssid, (u32)timestamp, capability, beacon_interval, ie_len,
                ssid.essid, signal);
 
-       cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
                timestamp, capability, beacon_interval, ie_buf, ie_len,
                signal, GFP_KERNEL);
+       cfg80211_put_bss(bss);
 }
 
 /*
index c244f2f1b83fb6658569cd545ac37ec3a2772a18..94a3e17061582e7afacab5cb590590bd69fbb8f2 100644 (file)
@@ -275,6 +275,8 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8191, rtl92cu_hal_cfg)},
 
        /****** 8188CU ********/
+       /* RTL8188CTV */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x018a, rtl92cu_hal_cfg)},
        /* 8188CE-VAU USB minCard */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8170, rtl92cu_hal_cfg)},
        /* 8188cu 1*1 dongle */
@@ -291,14 +293,14 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817e, rtl92cu_hal_cfg)},
        /* 8188RU in Alfa AWUS036NHR */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
+       /* RTL8188CUS-VL */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
        /* 8188 Combo for BC4 */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 
        /****** 8192CU ********/
-       /* 8191cu 1*2 */
-       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8177, rtl92cu_hal_cfg)},
        /* 8192cu 2*2 */
-       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817b, rtl92cu_hal_cfg)},
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8178, rtl92cu_hal_cfg)},
        /* 8192CE-VAU USB minCard */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817c, rtl92cu_hal_cfg)},
 
@@ -309,13 +311,17 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
        {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
        {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
-       {RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
        {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
        /* HP - Lite-On ,8188CUS Slim Combo */
        {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */
        {RTL_USB_DEVICE(0x2001, 0x3308, rtl92cu_hal_cfg)}, /*D-Link - Alpha*/
+       {RTL_USB_DEVICE(0x2019, 0x4902, rtl92cu_hal_cfg)}, /*Planex - Etop*/
        {RTL_USB_DEVICE(0x2019, 0xab2a, rtl92cu_hal_cfg)}, /*Planex - Abocom*/
+       /*SW-WF02-AD15 -Abocom*/
+       {RTL_USB_DEVICE(0x2019, 0xab2e, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x2019, 0xed17, rtl92cu_hal_cfg)}, /*PCI - Edimax*/
        {RTL_USB_DEVICE(0x20f4, 0x648b, rtl92cu_hal_cfg)}, /*TRENDnet - Cameo*/
        {RTL_USB_DEVICE(0x7392, 0x7811, rtl92cu_hal_cfg)}, /*Edimax - Edimax*/
@@ -326,14 +332,36 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x4855, 0x0091, rtl92cu_hal_cfg)}, /* NetweeN-Feixun */
        {RTL_USB_DEVICE(0x9846, 0x9041, rtl92cu_hal_cfg)}, /* Netgear Cameo */
 
+       /****** 8188 RU ********/
+       /* Netcore */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x317f, rtl92cu_hal_cfg)},
+
+       /****** 8188CUS Slim Solo********/
+       {RTL_USB_DEVICE(0x04f2, 0xaff7, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaff9, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffa, rtl92cu_hal_cfg)}, /*Xavi*/
+
+       /****** 8188CUS Slim Combo ********/
+       {RTL_USB_DEVICE(0x04f2, 0xaff8, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffb, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffc, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x2019, 0x1201, rtl92cu_hal_cfg)}, /*Planex-Vencer*/
+
        /****** 8192CU ********/
+       {RTL_USB_DEVICE(0x050d, 0x2102, rtl92cu_hal_cfg)}, /*Belcom-Sercomm*/
+       {RTL_USB_DEVICE(0x050d, 0x2103, rtl92cu_hal_cfg)}, /*Belcom-Edimax*/
        {RTL_USB_DEVICE(0x0586, 0x341f, rtl92cu_hal_cfg)}, /*Zyxel -Abocom*/
        {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/
        {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
+       {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
+       {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/
+       {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/
        {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
        {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/
+       {RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/
        {RTL_USB_DEVICE(0x7392, 0x7822, rtl92cu_hal_cfg)}, /*Edimax -Edimax*/
        {}
 };
index 182562952c792a9e347b9a0cc62744ee4e7a8f81..0b5c18feb3038284316ba4dd76cc37d7a36cc727 100644 (file)
@@ -165,7 +165,8 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu)
        return 0;
 }
 
-static u32 xenvif_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t xenvif_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct xenvif *vif = netdev_priv(dev);
 
index 226faab236032b9e6a9f28d5895cf194bc93ac65..4312db8cdeab20c5c3b5ea0e3348f19ab3875ee7 100644 (file)
@@ -201,7 +201,7 @@ static void xennet_sysfs_delif(struct net_device *netdev);
 #define xennet_sysfs_delif(dev) do { } while (0)
 #endif
 
-static int xennet_can_sg(struct net_device *dev)
+static bool xennet_can_sg(struct net_device *dev)
 {
        return dev->features & NETIF_F_SG;
 }
@@ -1190,7 +1190,8 @@ static void xennet_uninit(struct net_device *dev)
        gnttab_free_grant_references(np->gref_rx_head);
 }
 
-static u32 xennet_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t xennet_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct netfront_info *np = netdev_priv(dev);
        int val;
@@ -1216,7 +1217,8 @@ static u32 xennet_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int xennet_set_features(struct net_device *dev, u32 features)
+static int xennet_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) {
                netdev_info(dev, "Reducing MTU because no SG offload");
index 94f49ffa70ba22e5e27508c93d139a2b85983ab2..8af868bab20b52f9e2c11d4266a977c79ff99c01 100644 (file)
@@ -263,6 +263,11 @@ error:
        return PTR_ERR(vqs[i]);
 }
 
+static const char *kvm_bus_name(struct virtio_device *vdev)
+{
+       return "";
+}
+
 /*
  * The config ops structure as defined by virtio config
  */
@@ -276,6 +281,7 @@ static struct virtio_config_ops kvm_vq_configspace_ops = {
        .reset = kvm_reset,
        .find_vqs = kvm_find_vqs,
        .del_vqs = kvm_del_vqs,
+       .bus_name = kvm_bus_name,
 };
 
 /*
index 4d5307ddbe55b03ce78b89e423369927c171c2c1..63578925bc598d8fca3f880dcb7dd287a537791d 100644 (file)
@@ -3209,7 +3209,8 @@ static int qeth_l3_stop(struct net_device *dev)
        return 0;
 }
 
-static u32 qeth_l3_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t qeth_l3_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct qeth_card *card = dev->ml_priv;
 
@@ -3223,7 +3224,8 @@ static u32 qeth_l3_fix_features(struct net_device *dev, u32 features)
        return features;
 }
 
-static int qeth_l3_set_features(struct net_device *dev, u32 features)
+static int qeth_l3_set_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct qeth_card *card = dev->ml_priv;
        u32 changed = dev->features ^ features;
index acc5e43c373eb25c3d24410a70a39392caf551f4..2f57380d7ed4b6cb8283449d15a4c887eee6a912 100644 (file)
@@ -361,7 +361,12 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs,
        return 0;
 }
 
+static const char *vm_bus_name(struct virtio_device *vdev)
+{
+       struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
 
+       return vm_dev->pdev->name;
+}
 
 static struct virtio_config_ops virtio_mmio_config_ops = {
        .get            = vm_get,
@@ -373,6 +378,7 @@ static struct virtio_config_ops virtio_mmio_config_ops = {
        .del_vqs        = vm_del_vqs,
        .get_features   = vm_get_features,
        .finalize_features = vm_finalize_features,
+       .bus_name       = vm_bus_name,
 };
 
 
index 3d1bf41e8892b8e2150a51403726ebb52ea9d56c..91683e6e7af5b316cc2aaf7702cda77c659efae0 100644 (file)
@@ -580,6 +580,13 @@ static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
                                  false, false);
 }
 
+static const char *vp_bus_name(struct virtio_device *vdev)
+{
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+       return pci_name(vp_dev->pci_dev);
+}
+
 static struct virtio_config_ops virtio_pci_config_ops = {
        .get            = vp_get,
        .set            = vp_set,
@@ -590,6 +597,7 @@ static struct virtio_config_ops virtio_pci_config_ops = {
        .del_vqs        = vp_del_vqs,
        .get_features   = vp_get_features,
        .finalize_features = vp_finalize_features,
+       .bus_name       = vp_bus_name,
 };
 
 static void virtio_pci_release_dev(struct device *_d)
index 9a6115e7cf631583f808d6807619c0207c0a5a0c..49c1704173e757a5e75db1dca27fbf4081aa2dd7 100644 (file)
@@ -64,4 +64,7 @@
 #define SO_DOMAIN              39
 
 #define SO_RXQ_OVFL             40
+
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS        SO_WIFI_STATUS
 #endif /* __ASM_GENERIC_SOCKET_H */
index 619b5657af77b232541a56a6e3cd06d7f2693210..0b091b32267da47cb540280223f91f19e0d9d76c 100644 (file)
@@ -185,6 +185,7 @@ header-y += if_pppol2tp.h
 header-y += if_pppox.h
 header-y += if_slip.h
 header-y += if_strip.h
+header-y += if_team.h
 header-y += if_tr.h
 header-y += if_tun.h
 header-y += if_tunnel.h
index 034072cea853eafc7f4eb5bed66649ee129da448..c9f522bd17e4df214e297eafa73cae7003f1b763 100644 (file)
@@ -17,7 +17,8 @@ struct sock_extended_err {
 #define SO_EE_ORIGIN_LOCAL     1
 #define SO_EE_ORIGIN_ICMP      2
 #define SO_EE_ORIGIN_ICMP6     3
-#define SO_EE_ORIGIN_TIMESTAMPING 4
+#define SO_EE_ORIGIN_TXSTATUS  4
+#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
 
 #define SO_EE_OFFENDER(ee)     ((struct sockaddr*)((ee)+1))
 
index de33de1e205295150efb604dbcf6a56f9b4e91e5..20db5b275c3f588571f8e95d52964ff26c822a56 100644 (file)
@@ -724,9 +724,6 @@ enum ethtool_sfeatures_retval_bits {
 
 #include <linux/rculist.h>
 
-/* needed by dev_disable_lro() */
-extern int __ethtool_set_flags(struct net_device *dev, u32 flags);
-
 extern int __ethtool_get_settings(struct net_device *dev,
                                  struct ethtool_cmd *cmd);
 
@@ -750,19 +747,6 @@ struct net_device;
 
 /* Some generic methods drivers may use in their ethtool_ops */
 u32 ethtool_op_get_link(struct net_device *dev);
-u32 ethtool_op_get_tx_csum(struct net_device *dev);
-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
-int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
-int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
-u32 ethtool_op_get_sg(struct net_device *dev);
-int ethtool_op_set_sg(struct net_device *dev, u32 data);
-u32 ethtool_op_get_tso(struct net_device *dev);
-int ethtool_op_set_tso(struct net_device *dev, u32 data);
-u32 ethtool_op_get_ufo(struct net_device *dev);
-int ethtool_op_set_ufo(struct net_device *dev, u32 data);
-u32 ethtool_op_get_flags(struct net_device *dev);
-int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
-bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
 
 /**
  * struct ethtool_ops - optional netdev operations
@@ -807,22 +791,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
  * @get_pauseparam: Report pause parameters
  * @set_pauseparam: Set pause parameters.  Returns a negative error code
  *     or zero.
- * @get_rx_csum: Deprecated in favour of the netdev feature %NETIF_F_RXCSUM.
- *     Report whether receive checksums are turned on or off.
- * @set_rx_csum: Deprecated in favour of generic netdev features.  Turn
- *     receive checksum on or off.  Returns a negative error code or zero.
- * @get_tx_csum: Deprecated as redundant. Report whether transmit checksums
- *     are turned on or off.
- * @set_tx_csum: Deprecated in favour of generic netdev features.  Turn
- *     transmit checksums on or off.  Returns a negative error code or zero.
- * @get_sg: Deprecated as redundant.  Report whether scatter-gather is
- *     enabled.  
- * @set_sg: Deprecated in favour of generic netdev features.  Turn
- *     scatter-gather on or off. Returns a negative error code or zero.
- * @get_tso: Deprecated as redundant.  Report whether TCP segmentation
- *     offload is enabled.
- * @set_tso: Deprecated in favour of generic netdev features.  Turn TCP
- *     segmentation offload on or off.  Returns a negative error code or zero.
  * @self_test: Run specified self-tests
  * @get_strings: Return a set of strings that describe the requested objects
  * @set_phys_id: Identify the physical devices, e.g. by flashing an LED
@@ -844,15 +812,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
  *     negative error code or zero.
  * @complete: Function to be called after any other operation except
  *     @begin.  Will be called even if the other operation failed.
- * @get_ufo: Deprecated as redundant.  Report whether UDP fragmentation
- *     offload is enabled.
- * @set_ufo: Deprecated in favour of generic netdev features.  Turn UDP
- *     fragmentation offload on or off.  Returns a negative error code or zero.
- * @get_flags: Deprecated as redundant.  Report features included in
- *     &enum ethtool_flags that are enabled.  
- * @set_flags: Deprecated in favour of generic netdev features.  Turn
- *     features included in &enum ethtool_flags on or off.  Returns a
- *     negative error code or zero.
  * @get_priv_flags: Report driver-specific feature flags.
  * @set_priv_flags: Set driver-specific feature flags.  Returns a negative
  *     error code or zero.
@@ -917,14 +876,6 @@ struct ethtool_ops {
                                  struct ethtool_pauseparam*);
        int     (*set_pauseparam)(struct net_device *,
                                  struct ethtool_pauseparam*);
-       u32     (*get_rx_csum)(struct net_device *);
-       int     (*set_rx_csum)(struct net_device *, u32);
-       u32     (*get_tx_csum)(struct net_device *);
-       int     (*set_tx_csum)(struct net_device *, u32);
-       u32     (*get_sg)(struct net_device *);
-       int     (*set_sg)(struct net_device *, u32);
-       u32     (*get_tso)(struct net_device *);
-       int     (*set_tso)(struct net_device *, u32);
        void    (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
        void    (*get_strings)(struct net_device *, u32 stringset, u8 *);
        int     (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
@@ -932,10 +883,6 @@ struct ethtool_ops {
                                     struct ethtool_stats *, u64 *);
        int     (*begin)(struct net_device *);
        void    (*complete)(struct net_device *);
-       u32     (*get_ufo)(struct net_device *);
-       int     (*set_ufo)(struct net_device *, u32);
-       u32     (*get_flags)(struct net_device *);
-       int     (*set_flags)(struct net_device *, u32);
        u32     (*get_priv_flags)(struct net_device *);
        int     (*set_priv_flags)(struct net_device *, u32);
        int     (*get_sset_count)(struct net_device *, int);
index 48363c3c40f8f6de0e1ebb062a35eef498f6077a..66cedf6eb5c2421b3fda7339df9290dbb1e3492e 100644 (file)
 #define IEEE80211_QOS_CTL_ACK_POLICY_NOACK     0x0020
 #define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL   0x0040
 #define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK  0x0060
+#define IEEE80211_QOS_CTL_ACK_POLICY_MASK      0x0060
 /* A-MSDU 802.11n */
 #define IEEE80211_QOS_CTL_A_MSDU_PRESENT       0x0080
 /* Mesh Control 802.11s */
@@ -770,6 +771,9 @@ struct ieee80211_mgmt {
        } u;
 } __attribute__ ((packed));
 
+/* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
 /* mgmt header + 1 byte category code */
 #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
 
@@ -1552,6 +1556,8 @@ enum ieee80211_sa_query_action {
 #define WLAN_CIPHER_SUITE_WEP104       0x000FAC05
 #define WLAN_CIPHER_SUITE_AES_CMAC     0x000FAC06
 
+#define WLAN_CIPHER_SUITE_SMS4         0x00147201
+
 /* AKM suite selectors */
 #define WLAN_AKM_SUITE_8021X           0x000FAC01
 #define WLAN_AKM_SUITE_PSK             0x000FAC02
index db20bd4fd16b9189534a0cc15aa6335925cd3ace..06b6ef60c821a43be68135d8fb4055c2425ff441 100644 (file)
@@ -79,6 +79,7 @@
 #define IFF_TX_SKB_SHARING     0x10000 /* The interface supports sharing
                                         * skbs on transmit */
 #define IFF_UNICAST_FLT        0x20000         /* Supports unicast filtering   */
+#define IFF_TEAM_PORT  0x40000         /* device used as team port */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
new file mode 100644 (file)
index 0000000..828181f
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * include/linux/if_team.h - Network team device driver header
+ * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _LINUX_IF_TEAM_H_
+#define _LINUX_IF_TEAM_H_
+
+#ifdef __KERNEL__
+
+struct team_pcpu_stats {
+       u64                     rx_packets;
+       u64                     rx_bytes;
+       u64                     rx_multicast;
+       u64                     tx_packets;
+       u64                     tx_bytes;
+       struct u64_stats_sync   syncp;
+       u32                     rx_dropped;
+       u32                     tx_dropped;
+};
+
+struct team;
+
+struct team_port {
+       struct net_device *dev;
+       struct hlist_node hlist; /* node in hash list */
+       struct list_head list; /* node in ordinary list */
+       struct team *team;
+       int index;
+
+       /*
+        * A place for storing original values of the device before it
+        * become a port.
+        */
+       struct {
+               unsigned char dev_addr[MAX_ADDR_LEN];
+               unsigned int mtu;
+       } orig;
+
+       bool linkup;
+       u32 speed;
+       u8 duplex;
+
+       struct rcu_head rcu;
+};
+
+struct team_mode_ops {
+       int (*init)(struct team *team);
+       void (*exit)(struct team *team);
+       rx_handler_result_t (*receive)(struct team *team,
+                                      struct team_port *port,
+                                      struct sk_buff *skb);
+       bool (*transmit)(struct team *team, struct sk_buff *skb);
+       int (*port_enter)(struct team *team, struct team_port *port);
+       void (*port_leave)(struct team *team, struct team_port *port);
+       void (*port_change_mac)(struct team *team, struct team_port *port);
+};
+
+enum team_option_type {
+       TEAM_OPTION_TYPE_U32,
+       TEAM_OPTION_TYPE_STRING,
+};
+
+struct team_option {
+       struct list_head list;
+       const char *name;
+       enum team_option_type type;
+       int (*getter)(struct team *team, void *arg);
+       int (*setter)(struct team *team, void *arg);
+};
+
+struct team_mode {
+       struct list_head list;
+       const char *kind;
+       struct module *owner;
+       size_t priv_size;
+       const struct team_mode_ops *ops;
+};
+
+#define TEAM_PORT_HASHBITS 4
+#define TEAM_PORT_HASHENTRIES (1 << TEAM_PORT_HASHBITS)
+
+#define TEAM_MODE_PRIV_LONGS 4
+#define TEAM_MODE_PRIV_SIZE (sizeof(long) * TEAM_MODE_PRIV_LONGS)
+
+struct team {
+       struct net_device *dev; /* associated netdevice */
+       struct team_pcpu_stats __percpu *pcpu_stats;
+
+       struct mutex lock; /* used for overall locking, e.g. port lists write */
+
+       /*
+        * port lists with port count
+        */
+       int port_count;
+       struct hlist_head port_hlist[TEAM_PORT_HASHENTRIES];
+       struct list_head port_list;
+
+       struct list_head option_list;
+
+       const struct team_mode *mode;
+       struct team_mode_ops ops;
+       long mode_priv[TEAM_MODE_PRIV_LONGS];
+};
+
+static inline struct hlist_head *team_port_index_hash(struct team *team,
+                                                     int port_index)
+{
+       return &team->port_hlist[port_index & (TEAM_PORT_HASHENTRIES - 1)];
+}
+
+static inline struct team_port *team_get_port_by_index(struct team *team,
+                                                      int port_index)
+{
+       struct hlist_node *p;
+       struct team_port *port;
+       struct hlist_head *head = team_port_index_hash(team, port_index);
+
+       hlist_for_each_entry(port, p, head, hlist)
+               if (port->index == port_index)
+                       return port;
+       return NULL;
+}
+static inline struct team_port *team_get_port_by_index_rcu(struct team *team,
+                                                          int port_index)
+{
+       struct hlist_node *p;
+       struct team_port *port;
+       struct hlist_head *head = team_port_index_hash(team, port_index);
+
+       hlist_for_each_entry_rcu(port, p, head, hlist)
+               if (port->index == port_index)
+                       return port;
+       return NULL;
+}
+
+extern int team_port_set_team_mac(struct team_port *port);
+extern int team_options_register(struct team *team,
+                                const struct team_option *option,
+                                size_t option_count);
+extern void team_options_unregister(struct team *team,
+                                   const struct team_option *option,
+                                   size_t option_count);
+extern int team_mode_register(struct team_mode *mode);
+extern int team_mode_unregister(struct team_mode *mode);
+
+#endif /* __KERNEL__ */
+
+#define TEAM_STRING_MAX_LEN 32
+
+/**********************************
+ * NETLINK_GENERIC netlink family.
+ **********************************/
+
+enum {
+       TEAM_CMD_NOOP,
+       TEAM_CMD_OPTIONS_SET,
+       TEAM_CMD_OPTIONS_GET,
+       TEAM_CMD_PORT_LIST_GET,
+
+       __TEAM_CMD_MAX,
+       TEAM_CMD_MAX = (__TEAM_CMD_MAX - 1),
+};
+
+enum {
+       TEAM_ATTR_UNSPEC,
+       TEAM_ATTR_TEAM_IFINDEX,         /* u32 */
+       TEAM_ATTR_LIST_OPTION,          /* nest */
+       TEAM_ATTR_LIST_PORT,            /* nest */
+
+       __TEAM_ATTR_MAX,
+       TEAM_ATTR_MAX = __TEAM_ATTR_MAX - 1,
+};
+
+/* Nested layout of get/set msg:
+ *
+ *     [TEAM_ATTR_LIST_OPTION]
+ *             [TEAM_ATTR_ITEM_OPTION]
+ *                     [TEAM_ATTR_OPTION_*], ...
+ *             [TEAM_ATTR_ITEM_OPTION]
+ *                     [TEAM_ATTR_OPTION_*], ...
+ *             ...
+ *     [TEAM_ATTR_LIST_PORT]
+ *             [TEAM_ATTR_ITEM_PORT]
+ *                     [TEAM_ATTR_PORT_*], ...
+ *             [TEAM_ATTR_ITEM_PORT]
+ *                     [TEAM_ATTR_PORT_*], ...
+ *             ...
+ */
+
+enum {
+       TEAM_ATTR_ITEM_OPTION_UNSPEC,
+       TEAM_ATTR_ITEM_OPTION,          /* nest */
+
+       __TEAM_ATTR_ITEM_OPTION_MAX,
+       TEAM_ATTR_ITEM_OPTION_MAX = __TEAM_ATTR_ITEM_OPTION_MAX - 1,
+};
+
+enum {
+       TEAM_ATTR_OPTION_UNSPEC,
+       TEAM_ATTR_OPTION_NAME,          /* string */
+       TEAM_ATTR_OPTION_CHANGED,       /* flag */
+       TEAM_ATTR_OPTION_TYPE,          /* u8 */
+       TEAM_ATTR_OPTION_DATA,          /* dynamic */
+
+       __TEAM_ATTR_OPTION_MAX,
+       TEAM_ATTR_OPTION_MAX = __TEAM_ATTR_OPTION_MAX - 1,
+};
+
+enum {
+       TEAM_ATTR_ITEM_PORT_UNSPEC,
+       TEAM_ATTR_ITEM_PORT,            /* nest */
+
+       __TEAM_ATTR_ITEM_PORT_MAX,
+       TEAM_ATTR_ITEM_PORT_MAX = __TEAM_ATTR_ITEM_PORT_MAX - 1,
+};
+
+enum {
+       TEAM_ATTR_PORT_UNSPEC,
+       TEAM_ATTR_PORT_IFINDEX,         /* u32 */
+       TEAM_ATTR_PORT_CHANGED,         /* flag */
+       TEAM_ATTR_PORT_LINKUP,          /* flag */
+       TEAM_ATTR_PORT_SPEED,           /* u32 */
+       TEAM_ATTR_PORT_DUPLEX,          /* u8 */
+
+       __TEAM_ATTR_PORT_MAX,
+       TEAM_ATTR_PORT_MAX = __TEAM_ATTR_PORT_MAX - 1,
+};
+
+/*
+ * NETLINK_GENERIC related info
+ */
+#define TEAM_GENL_NAME "team"
+#define TEAM_GENL_VERSION 0x1
+#define TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME "change_event"
+
+#endif /* _LINUX_IF_TEAM_H_ */
index 0fe00cd4c93ca3b26fb8841b6becfd8ef10a02cd..76f52bbbb2f430b822524b4e60ef90fa05a4f476 100644 (file)
@@ -32,6 +32,8 @@ struct mdiobb_ops {
 
 struct mdiobb_ctrl {
        const struct mdiobb_ops *ops;
+       /* reset callback */
+       int (*reset)(struct mii_bus *bus);
 };
 
 /* The returned bus is not yet registered with the phy layer. */
index e9d3fdfe41d71a9dc42c1b456a928e93e049bbc7..7c9fe3c2be73a771d53fbf4208832203032cfa07 100644 (file)
@@ -20,6 +20,8 @@ struct mdio_gpio_platform_data {
 
        unsigned int phy_mask;
        int irqs[PHY_MAX_ADDR];
+       /* reset callback */
+       int (*reset)(struct mii_bus *bus);
 };
 
 #endif /* __LINUX_MDIO_GPIO_H */
index 27748230aa69440e9b6d728a61a2b9ac425ac9c0..6697b9112014910c2eaca8cfb646d99c4d31b4ba 100644 (file)
@@ -9,6 +9,7 @@
 #define __LINUX_MII_H__
 
 #include <linux/types.h>
+#include <linux/ethtool.h>
 
 /* Generic MII registers. */
 #define MII_BMCR               0x00    /* Basic mode control register */
@@ -239,6 +240,171 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock,
        return 0;
 }
 
+/**
+ * ethtool_adv_to_mii_100bt
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_ADVERTISE register.
+ */
+static inline u32 ethtool_adv_to_mii_100bt(u32 ethadv)
+{
+       u32 result = 0;
+
+       if (ethadv & ADVERTISED_10baseT_Half)
+               result |= ADVERTISE_10HALF;
+       if (ethadv & ADVERTISED_10baseT_Full)
+               result |= ADVERTISE_10FULL;
+       if (ethadv & ADVERTISED_100baseT_Half)
+               result |= ADVERTISE_100HALF;
+       if (ethadv & ADVERTISED_100baseT_Full)
+               result |= ADVERTISE_100FULL;
+       if (ethadv & ADVERTISED_Pause)
+               result |= ADVERTISE_PAUSE_CAP;
+       if (ethadv & ADVERTISED_Asym_Pause)
+               result |= ADVERTISE_PAUSE_ASYM;
+
+       return result;
+}
+
+/**
+ * mii_adv_to_ethtool_100bt
+ * @adv: value of the MII_ADVERTISE register
+ *
+ * A small helper function that translates MII_ADVERTISE bits
+ * to ethtool advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_100bt(u32 adv)
+{
+       u32 result = 0;
+
+       if (adv & ADVERTISE_10HALF)
+               result |= ADVERTISED_10baseT_Half;
+       if (adv & ADVERTISE_10FULL)
+               result |= ADVERTISED_10baseT_Full;
+       if (adv & ADVERTISE_100HALF)
+               result |= ADVERTISED_100baseT_Half;
+       if (adv & ADVERTISE_100FULL)
+               result |= ADVERTISED_100baseT_Full;
+       if (adv & ADVERTISE_PAUSE_CAP)
+               result |= ADVERTISED_Pause;
+       if (adv & ADVERTISE_PAUSE_ASYM)
+               result |= ADVERTISED_Asym_Pause;
+
+       return result;
+}
+
+/**
+ * ethtool_adv_to_mii_1000T
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_CTRL1000 register when in 1000T mode.
+ */
+static inline u32 ethtool_adv_to_mii_1000T(u32 ethadv)
+{
+       u32 result = 0;
+
+       if (ethadv & ADVERTISED_1000baseT_Half)
+               result |= ADVERTISE_1000HALF;
+       if (ethadv & ADVERTISED_1000baseT_Full)
+               result |= ADVERTISE_1000FULL;
+
+       return result;
+}
+
+/**
+ * mii_adv_to_ethtool_1000T
+ * @adv: value of the MII_CTRL1000 register
+ *
+ * A small helper function that translates MII_CTRL1000
+ * bits, when in 1000Base-T mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_1000T(u32 adv)
+{
+       u32 result = 0;
+
+       if (adv & ADVERTISE_1000HALF)
+               result |= ADVERTISED_1000baseT_Half;
+       if (adv & ADVERTISE_1000FULL)
+               result |= ADVERTISED_1000baseT_Full;
+
+       return result;
+}
+
+#define mii_lpa_to_ethtool_100bt(lpa)  mii_adv_to_ethtool_100bt(lpa)
+
+/**
+ * mii_lpa_to_ethtool_1000T
+ * @adv: value of the MII_STAT1000 register
+ *
+ * A small helper function that translates MII_STAT1000
+ * bits, when in 1000Base-T mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_lpa_to_ethtool_1000T(u32 lpa)
+{
+       u32 result = 0;
+
+       if (lpa & LPA_1000HALF)
+               result |= ADVERTISED_1000baseT_Half;
+       if (lpa & LPA_1000FULL)
+               result |= ADVERTISED_1000baseT_Full;
+
+       return result;
+}
+
+/**
+ * ethtool_adv_to_mii_1000X
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_CTRL1000 register when in 1000Base-X mode.
+ */
+static inline u32 ethtool_adv_to_mii_1000X(u32 ethadv)
+{
+       u32 result = 0;
+
+       if (ethadv & ADVERTISED_1000baseT_Half)
+               result |= ADVERTISE_1000XHALF;
+       if (ethadv & ADVERTISED_1000baseT_Full)
+               result |= ADVERTISE_1000XFULL;
+       if (ethadv & ADVERTISED_Pause)
+               result |= ADVERTISE_1000XPAUSE;
+       if (ethadv & ADVERTISED_Asym_Pause)
+               result |= ADVERTISE_1000XPSE_ASYM;
+
+       return result;
+}
+
+/**
+ * mii_adv_to_ethtool_1000X
+ * @adv: value of the MII_CTRL1000 register
+ *
+ * A small helper function that translates MII_CTRL1000
+ * bits, when in 1000Base-X mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_1000X(u32 adv)
+{
+       u32 result = 0;
+
+       if (adv & ADVERTISE_1000XHALF)
+               result |= ADVERTISED_1000baseT_Half;
+       if (adv & ADVERTISE_1000XFULL)
+               result |= ADVERTISED_1000baseT_Full;
+       if (adv & ADVERTISE_1000XPAUSE)
+               result |= ADVERTISED_Pause;
+       if (adv & ADVERTISE_1000XPSE_ASYM)
+               result |= ADVERTISED_Asym_Pause;
+
+       return result;
+}
+
 /**
  * mii_advertise_flowctrl - get flow control advertisement flags
  * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
index a7003b7a695d26ac366ae9204349c87ea358b0d3..b188f68a08c90bf8689ea784e618378aa5c9e978 100644 (file)
@@ -116,6 +116,7 @@ enum {
        NDTPA_PROXY_DELAY,              /* u64, msecs */
        NDTPA_PROXY_QLEN,               /* u32 */
        NDTPA_LOCKTIME,                 /* u64, msecs */
+       NDTPA_QUEUE_LENBYTES,           /* u32 */
        __NDTPA_MAX
 };
 #define NDTPA_MAX (__NDTPA_MAX - 1)
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
new file mode 100644 (file)
index 0000000..77f5202
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Network device features.
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_NETDEV_FEATURES_H
+#define _LINUX_NETDEV_FEATURES_H
+
+#include <linux/types.h>
+
+typedef u64 netdev_features_t;
+
+enum {
+       NETIF_F_SG_BIT,                 /* Scatter/gather IO. */
+       NETIF_F_IP_CSUM_BIT,            /* Can checksum TCP/UDP over IPv4. */
+       __UNUSED_NETIF_F_1,
+       NETIF_F_HW_CSUM_BIT,            /* Can checksum all the packets. */
+       NETIF_F_IPV6_CSUM_BIT,          /* Can checksum TCP/UDP over IPV6 */
+       NETIF_F_HIGHDMA_BIT,            /* Can DMA to high memory. */
+       NETIF_F_FRAGLIST_BIT,           /* Scatter/gather IO. */
+       NETIF_F_HW_VLAN_TX_BIT,         /* Transmit VLAN hw acceleration */
+       NETIF_F_HW_VLAN_RX_BIT,         /* Receive VLAN hw acceleration */
+       NETIF_F_HW_VLAN_FILTER_BIT,     /* Receive filtering on VLAN */
+       NETIF_F_VLAN_CHALLENGED_BIT,    /* Device cannot handle VLAN packets */
+       NETIF_F_GSO_BIT,                /* Enable software GSO. */
+       NETIF_F_LLTX_BIT,               /* LockLess TX - deprecated. Please */
+                                       /* do not use LLTX in new drivers */
+       NETIF_F_NETNS_LOCAL_BIT,        /* Does not change network namespaces */
+       NETIF_F_GRO_BIT,                /* Generic receive offload */
+       NETIF_F_LRO_BIT,                /* large receive offload */
+
+       /**/NETIF_F_GSO_SHIFT,          /* keep the order of SKB_GSO_* bits */
+       NETIF_F_TSO_BIT                 /* ... TCPv4 segmentation */
+               = NETIF_F_GSO_SHIFT,
+       NETIF_F_UFO_BIT,                /* ... UDPv4 fragmentation */
+       NETIF_F_GSO_ROBUST_BIT,         /* ... ->SKB_GSO_DODGY */
+       NETIF_F_TSO_ECN_BIT,            /* ... TCP ECN support */
+       NETIF_F_TSO6_BIT,               /* ... TCPv6 segmentation */
+       NETIF_F_FSO_BIT,                /* ... FCoE segmentation */
+       NETIF_F_GSO_RESERVED1,          /* ... free (fill GSO_MASK to 8 bits) */
+       /**/NETIF_F_GSO_LAST,           /* [can't be last bit, see GSO_MASK] */
+       NETIF_F_GSO_RESERVED2           /* ... free (fill GSO_MASK to 8 bits) */
+               = NETIF_F_GSO_LAST,
+
+       NETIF_F_FCOE_CRC_BIT,           /* FCoE CRC32 */
+       NETIF_F_SCTP_CSUM_BIT,          /* SCTP checksum offload */
+       NETIF_F_FCOE_MTU_BIT,           /* Supports max FCoE MTU, 2158 bytes*/
+       NETIF_F_NTUPLE_BIT,             /* N-tuple filters supported */
+       NETIF_F_RXHASH_BIT,             /* Receive hashing offload */
+       NETIF_F_RXCSUM_BIT,             /* Receive checksumming offload */
+       NETIF_F_NOCACHE_COPY_BIT,       /* Use no-cache copyfromuser */
+       NETIF_F_LOOPBACK_BIT,           /* Enable loopback */
+
+       /*
+        * Add your fresh new feature above and remember to update
+        * netdev_features_strings[] in net/core/ethtool.c and maybe
+        * some feature mask #defines below. Please also describe it
+        * in Documentation/networking/netdev-features.txt.
+        */
+
+       /**/NETDEV_FEATURE_COUNT
+};
+
+/* copy'n'paste compression ;) */
+#define __NETIF_F_BIT(bit)     ((netdev_features_t)1 << (bit))
+#define __NETIF_F(name)                __NETIF_F_BIT(NETIF_F_##name##_BIT)
+
+#define NETIF_F_FCOE_CRC       __NETIF_F(FCOE_CRC)
+#define NETIF_F_FCOE_MTU       __NETIF_F(FCOE_MTU)
+#define NETIF_F_FRAGLIST       __NETIF_F(FRAGLIST)
+#define NETIF_F_FSO            __NETIF_F(FSO)
+#define NETIF_F_GRO            __NETIF_F(GRO)
+#define NETIF_F_GSO            __NETIF_F(GSO)
+#define NETIF_F_GSO_ROBUST     __NETIF_F(GSO_ROBUST)
+#define NETIF_F_HIGHDMA                __NETIF_F(HIGHDMA)
+#define NETIF_F_HW_CSUM                __NETIF_F(HW_CSUM)
+#define NETIF_F_HW_VLAN_FILTER __NETIF_F(HW_VLAN_FILTER)
+#define NETIF_F_HW_VLAN_RX     __NETIF_F(HW_VLAN_RX)
+#define NETIF_F_HW_VLAN_TX     __NETIF_F(HW_VLAN_TX)
+#define NETIF_F_IP_CSUM                __NETIF_F(IP_CSUM)
+#define NETIF_F_IPV6_CSUM      __NETIF_F(IPV6_CSUM)
+#define NETIF_F_LLTX           __NETIF_F(LLTX)
+#define NETIF_F_LOOPBACK       __NETIF_F(LOOPBACK)
+#define NETIF_F_LRO            __NETIF_F(LRO)
+#define NETIF_F_NETNS_LOCAL    __NETIF_F(NETNS_LOCAL)
+#define NETIF_F_NOCACHE_COPY   __NETIF_F(NOCACHE_COPY)
+#define NETIF_F_NTUPLE         __NETIF_F(NTUPLE)
+#define NETIF_F_RXCSUM         __NETIF_F(RXCSUM)
+#define NETIF_F_RXHASH         __NETIF_F(RXHASH)
+#define NETIF_F_SCTP_CSUM      __NETIF_F(SCTP_CSUM)
+#define NETIF_F_SG             __NETIF_F(SG)
+#define NETIF_F_TSO6           __NETIF_F(TSO6)
+#define NETIF_F_TSO_ECN                __NETIF_F(TSO_ECN)
+#define NETIF_F_TSO            __NETIF_F(TSO)
+#define NETIF_F_UFO            __NETIF_F(UFO)
+#define NETIF_F_VLAN_CHALLENGED        __NETIF_F(VLAN_CHALLENGED)
+
+/* Features valid for ethtool to change */
+/* = all defined minus driver/device-class-related */
+#define NETIF_F_NEVER_CHANGE   (NETIF_F_VLAN_CHALLENGED | \
+                                NETIF_F_LLTX | NETIF_F_NETNS_LOCAL)
+
+/* remember that ((t)1 << t_BITS) is undefined in C99 */
+#define NETIF_F_ETHTOOL_BITS   ((__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) | \
+               (__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) - 1)) & \
+               ~NETIF_F_NEVER_CHANGE)
+
+/* Segmentation offload feature mask */
+#define NETIF_F_GSO_MASK       (__NETIF_F_BIT(NETIF_F_GSO_LAST + 1) - \
+               __NETIF_F_BIT(NETIF_F_GSO_SHIFT))
+
+/* List of features with software fallbacks. */
+#define NETIF_F_GSO_SOFTWARE   (NETIF_F_TSO | NETIF_F_TSO_ECN | \
+                                NETIF_F_TSO6 | NETIF_F_UFO)
+
+#define NETIF_F_GEN_CSUM       NETIF_F_HW_CSUM
+#define NETIF_F_V4_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
+#define NETIF_F_V6_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
+#define NETIF_F_ALL_CSUM       (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
+
+#define NETIF_F_ALL_TSO        (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+
+#define NETIF_F_ALL_FCOE       (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \
+                                NETIF_F_FSO)
+
+/*
+ * If one device supports one of these features, then enable them
+ * for all in netdev_increment_features.
+ */
+#define NETIF_F_ONE_FOR_ALL    (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
+                                NETIF_F_SG | NETIF_F_HIGHDMA |         \
+                                NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED)
+/*
+ * If one device doesn't support one of these features, then disable it
+ * for all in netdev_increment_features.
+ */
+#define NETIF_F_ALL_FOR_ALL    (NETIF_F_NOCACHE_COPY | NETIF_F_FSO)
+
+/* changeable features with no special hardware requirements */
+#define NETIF_F_SOFT_FEATURES  (NETIF_F_GSO | NETIF_F_GRO)
+
+#endif /* _LINUX_NETDEV_FEATURES_H */
index cbeb5867cff79d7d70952cc6285063c3feb92e7c..3eb383a9b5ed1676a91456804328c2d73066c093 100644 (file)
@@ -51,6 +51,8 @@
 #include <net/dcbnl.h>
 #endif
 
+#include <linux/netdev_features.h>
+
 struct vlan_group;
 struct netpoll_info;
 struct phy_device;
@@ -212,6 +214,11 @@ enum {
 #include <linux/cache.h>
 #include <linux/skbuff.h>
 
+#ifdef CONFIG_RPS
+#include <linux/jump_label.h>
+extern struct jump_label_key rps_needed;
+#endif
+
 struct neighbour;
 struct neigh_parms;
 struct sk_buff;
@@ -272,16 +279,11 @@ struct hh_cache {
  *
  * We could use other alignment values, but we must maintain the
  * relationship HH alignment <= LL alignment.
- *
- * LL_ALLOCATED_SPACE also takes into account the tailroom the device
- * may need.
  */
 #define LL_RESERVED_SPACE(dev) \
        ((((dev)->hard_header_len+(dev)->needed_headroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 #define LL_RESERVED_SPACE_EXTRA(dev,extra) \
        ((((dev)->hard_header_len+(dev)->needed_headroom+(extra))&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
-#define LL_ALLOCATED_SPACE(dev) \
-       ((((dev)->hard_header_len+(dev)->needed_headroom+(dev)->needed_tailroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD)
 
 struct header_ops {
        int     (*create) (struct sk_buff *skb, struct net_device *dev,
@@ -530,7 +532,7 @@ struct netdev_queue {
        struct Qdisc            *qdisc;
        unsigned long           state;
        struct Qdisc            *qdisc_sleeping;
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        struct kobject          kobj;
 #endif
 #if defined(CONFIG_XPS) && defined(CONFIG_NUMA)
@@ -545,6 +547,12 @@ struct netdev_queue {
         * please use this field instead of dev->trans_start
         */
        unsigned long           trans_start;
+
+       /*
+        * Number of TX timeouts for this queue
+        * (/sys/class/net/DEV/Q/trans_timeout)
+        */
+       unsigned long           trans_timeout;
 } ____cacheline_aligned_in_smp;
 
 static inline int netdev_queue_numa_node_read(const struct netdev_queue *q)
@@ -845,12 +853,13 @@ struct netdev_tc_txq {
  *     Called to release previously enslaved netdev.
  *
  *      Feature/offload setting functions.
- * u32 (*ndo_fix_features)(struct net_device *dev, u32 features);
+ * netdev_features_t (*ndo_fix_features)(struct net_device *dev,
+ *             netdev_features_t features);
  *     Adjusts the requested feature flags according to device-specific
  *     constraints, and returns the resulting flags. Must not modify
  *     the device state.
  *
- * int (*ndo_set_features)(struct net_device *dev, u32 features);
+ * int (*ndo_set_features)(struct net_device *dev, netdev_features_t features);
  *     Called to update device configuration to new features. Passed
  *     feature set might be less than what was returned by ndo_fix_features()).
  *     Must return >0 or -errno if it changed dev->features itself.
@@ -944,10 +953,10 @@ struct net_device_ops {
                                                 struct net_device *slave_dev);
        int                     (*ndo_del_slave)(struct net_device *dev,
                                                 struct net_device *slave_dev);
-       u32                     (*ndo_fix_features)(struct net_device *dev,
-                                                   u32 features);
+       netdev_features_t       (*ndo_fix_features)(struct net_device *dev,
+                                                   netdev_features_t features);
        int                     (*ndo_set_features)(struct net_device *dev,
-                                                   u32 features);
+                                                   netdev_features_t features);
 };
 
 /*
@@ -997,91 +1006,13 @@ struct net_device {
        struct list_head        unreg_list;
 
        /* currently active device features */
-       u32                     features;
+       netdev_features_t       features;
        /* user-changeable features */
-       u32                     hw_features;
+       netdev_features_t       hw_features;
        /* user-requested features */
-       u32                     wanted_features;
+       netdev_features_t       wanted_features;
        /* mask of features inheritable by VLAN devices */
-       u32                     vlan_features;
-
-       /* Net device feature bits; if you change something,
-        * also update netdev_features_strings[] in ethtool.c */
-
-#define NETIF_F_SG             1       /* Scatter/gather IO. */
-#define NETIF_F_IP_CSUM                2       /* Can checksum TCP/UDP over IPv4. */
-#define NETIF_F_NO_CSUM                4       /* Does not require checksum. F.e. loopack. */
-#define NETIF_F_HW_CSUM                8       /* Can checksum all the packets. */
-#define NETIF_F_IPV6_CSUM      16      /* Can checksum TCP/UDP over IPV6 */
-#define NETIF_F_HIGHDMA                32      /* Can DMA to high memory. */
-#define NETIF_F_FRAGLIST       64      /* Scatter/gather IO. */
-#define NETIF_F_HW_VLAN_TX     128     /* Transmit VLAN hw acceleration */
-#define NETIF_F_HW_VLAN_RX     256     /* Receive VLAN hw acceleration */
-#define NETIF_F_HW_VLAN_FILTER 512     /* Receive filtering on VLAN */
-#define NETIF_F_VLAN_CHALLENGED        1024    /* Device cannot handle VLAN packets */
-#define NETIF_F_GSO            2048    /* Enable software GSO. */
-#define NETIF_F_LLTX           4096    /* LockLess TX - deprecated. Please */
-                                       /* do not use LLTX in new drivers */
-#define NETIF_F_NETNS_LOCAL    8192    /* Does not change network namespaces */
-#define NETIF_F_GRO            16384   /* Generic receive offload */
-#define NETIF_F_LRO            32768   /* large receive offload */
-
-/* the GSO_MASK reserves bits 16 through 23 */
-#define NETIF_F_FCOE_CRC       (1 << 24) /* FCoE CRC32 */
-#define NETIF_F_SCTP_CSUM      (1 << 25) /* SCTP checksum offload */
-#define NETIF_F_FCOE_MTU       (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/
-#define NETIF_F_NTUPLE         (1 << 27) /* N-tuple filters supported */
-#define NETIF_F_RXHASH         (1 << 28) /* Receive hashing offload */
-#define NETIF_F_RXCSUM         (1 << 29) /* Receive checksumming offload */
-#define NETIF_F_NOCACHE_COPY   (1 << 30) /* Use no-cache copyfromuser */
-#define NETIF_F_LOOPBACK       (1 << 31) /* Enable loopback */
-
-       /* Segmentation offload features */
-#define NETIF_F_GSO_SHIFT      16
-#define NETIF_F_GSO_MASK       0x00ff0000
-#define NETIF_F_TSO            (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
-#define NETIF_F_UFO            (SKB_GSO_UDP << NETIF_F_GSO_SHIFT)
-#define NETIF_F_GSO_ROBUST     (SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
-#define NETIF_F_TSO_ECN                (SKB_GSO_TCP_ECN << NETIF_F_GSO_SHIFT)
-#define NETIF_F_TSO6           (SKB_GSO_TCPV6 << NETIF_F_GSO_SHIFT)
-#define NETIF_F_FSO            (SKB_GSO_FCOE << NETIF_F_GSO_SHIFT)
-
-       /* Features valid for ethtool to change */
-       /* = all defined minus driver/device-class-related */
-#define NETIF_F_NEVER_CHANGE   (NETIF_F_VLAN_CHALLENGED | \
-                                 NETIF_F_LLTX | NETIF_F_NETNS_LOCAL)
-#define NETIF_F_ETHTOOL_BITS   (0xff3fffff & ~NETIF_F_NEVER_CHANGE)
-
-       /* List of features with software fallbacks. */
-#define NETIF_F_GSO_SOFTWARE   (NETIF_F_TSO | NETIF_F_TSO_ECN | \
-                                NETIF_F_TSO6 | NETIF_F_UFO)
-
-
-#define NETIF_F_GEN_CSUM       (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
-#define NETIF_F_V4_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
-#define NETIF_F_V6_CSUM                (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
-#define NETIF_F_ALL_CSUM       (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
-
-#define NETIF_F_ALL_TSO        (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
-
-#define NETIF_F_ALL_FCOE       (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \
-                                NETIF_F_FSO)
-
-       /*
-        * If one device supports one of these features, then enable them
-        * for all in netdev_increment_features.
-        */
-#define NETIF_F_ONE_FOR_ALL    (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \
-                                NETIF_F_SG | NETIF_F_HIGHDMA |         \
-                                NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED)
-       /*
-        * If one device doesn't support one of these features, then disable it
-        * for all in netdev_increment_features.
-        */
-#define NETIF_F_ALL_FOR_ALL    (NETIF_F_NOCACHE_COPY | NETIF_F_FSO)
-
-       /* changeable features with no special hardware requirements */
-#define NETIF_F_SOFT_FEATURES  (NETIF_F_GSO | NETIF_F_GRO)
+       netdev_features_t       vlan_features;
 
        /* Interface index. Unique device identifier    */
        int                     ifindex;
@@ -1184,9 +1115,11 @@ struct net_device {
 
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
 
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        struct kset             *queues_kset;
+#endif
 
+#ifdef CONFIG_RPS
        struct netdev_rx_queue  *_rx;
 
        /* Number of RX queues allocated at register_netdev() time */
@@ -1515,7 +1448,7 @@ struct packet_type {
                                         struct packet_type *,
                                         struct net_device *);
        struct sk_buff          *(*gso_segment)(struct sk_buff *skb,
-                                               u32 features);
+                                               netdev_features_t features);
        int                     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff          **(*gro_receive)(struct sk_buff **head,
                                               struct sk_buff *skb);
@@ -2520,7 +2453,8 @@ extern int                netdev_set_master(struct net_device *dev, struct net_device *master)
 extern int netdev_set_bond_master(struct net_device *dev,
                                  struct net_device *master);
 extern int skb_checksum_help(struct sk_buff *skb);
-extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *skb_gso_segment(struct sk_buff *skb,
+       netdev_features_t features);
 #ifdef CONFIG_BUG
 extern void netdev_rx_csum_fault(struct net_device *dev);
 #else
@@ -2547,11 +2481,13 @@ extern const char *netdev_drivername(const struct net_device *dev);
 
 extern void linkwatch_run_queue(void);
 
-static inline u32 netdev_get_wanted_features(struct net_device *dev)
+static inline netdev_features_t netdev_get_wanted_features(
+       struct net_device *dev)
 {
        return (dev->features & ~dev->hw_features) | dev->wanted_features;
 }
-u32 netdev_increment_features(u32 all, u32 one, u32 mask);
+netdev_features_t netdev_increment_features(netdev_features_t all,
+       netdev_features_t one, netdev_features_t mask);
 int __netdev_update_features(struct net_device *dev);
 void netdev_update_features(struct net_device *dev);
 void netdev_change_features(struct net_device *dev);
@@ -2559,21 +2495,31 @@ void netdev_change_features(struct net_device *dev);
 void netif_stacked_transfer_operstate(const struct net_device *rootdev,
                                        struct net_device *dev);
 
-u32 netif_skb_features(struct sk_buff *skb);
+netdev_features_t netif_skb_features(struct sk_buff *skb);
 
-static inline int net_gso_ok(u32 features, int gso_type)
+static inline int net_gso_ok(netdev_features_t features, int gso_type)
 {
-       int feature = gso_type << NETIF_F_GSO_SHIFT;
+       netdev_features_t feature = gso_type << NETIF_F_GSO_SHIFT;
+
+       /* check flags correspondence */
+       BUILD_BUG_ON(SKB_GSO_TCPV4   != (NETIF_F_TSO >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_UDP     != (NETIF_F_UFO >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_DODGY   != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_TCPV6   != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_FCOE    != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT));
+
        return (features & feature) == feature;
 }
 
-static inline int skb_gso_ok(struct sk_buff *skb, u32 features)
+static inline int skb_gso_ok(struct sk_buff *skb, netdev_features_t features)
 {
        return net_gso_ok(features, skb_shinfo(skb)->gso_type) &&
               (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST));
 }
 
-static inline int netif_needs_gso(struct sk_buff *skb, int features)
+static inline int netif_needs_gso(struct sk_buff *skb,
+       netdev_features_t features)
 {
        return skb_is_gso(skb) && (!skb_gso_ok(skb, features) ||
                unlikely(skb->ip_summed != CHECKSUM_PARTIAL));
@@ -2592,22 +2538,6 @@ static inline int netif_is_bond_slave(struct net_device *dev)
 
 extern struct pernet_operations __net_initdata loopback_net_ops;
 
-static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
-{
-       if (dev->features & NETIF_F_RXCSUM)
-               return 1;
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_rx_csum)
-               return 0;
-       return dev->ethtool_ops->get_rx_csum(dev);
-}
-
-static inline u32 dev_ethtool_get_flags(struct net_device *dev)
-{
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_flags)
-               return 0;
-       return dev->ethtool_ops->get_flags(dev);
-}
-
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* netdev_printk helpers, similar to dev_printk */
index 8049bf77d799384bee4870c8e1e80bfe29b343ab..f9261c253735b362f22769f38aa4519f984118c3 100644 (file)
  * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
  * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
  *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *     (or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *     implement sending deauth to stations that send unexpected class 3
+ *     frames. Also used as the event sent by the kernel when such a frame
+ *     is received.
+ *     For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *     other attributes like the interface index are present.
+ *     If used as the command it must have an interface index and you can
+ *     only unsubscribe from the event by closing the socket. Subscription
+ *     is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *     associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *     and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *     to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *     by sending a null data frame to it and reporting when the frame is
+ *     acknowleged. This is used to allow timing out inactive clients. Uses
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *     direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *     up the event with the request. The event includes the same data and
+ *     has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *     other BSSes when any interfaces are in AP mode. This helps implement
+ *     OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *     messages. Note that per PHY only one application may register.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -638,6 +667,14 @@ enum nl80211_commands {
        NL80211_CMD_TDLS_OPER,
        NL80211_CMD_TDLS_MGMT,
 
+       NL80211_CMD_UNEXPECTED_FRAME,
+
+       NL80211_CMD_PROBE_CLIENT,
+
+       NL80211_CMD_REGISTER_BEACONS,
+
+       NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -658,6 +695,8 @@ enum nl80211_commands {
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
 
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
 /* source-level API compatibility */
 #define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
 #define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
@@ -1109,6 +1148,28 @@ enum nl80211_commands {
  *     %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver to perform a TDLS operation.
  *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *     that have AP support to indicate that they have the AP SME integrated
+ *     with support for the features listed in this attribute, see
+ *     &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *     the driver to not wait for an acknowledgement. Note that due to this,
+ *     it will also not give a status callback nor return a cookie. This is
+ *     mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *     &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *     requests while operating in AP-mode.
+ *     This attribute holds a bitmap of the supported protocols for
+ *     offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *     probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *     to be filled by the FW.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1337,6 +1398,16 @@ enum nl80211_attrs {
        NL80211_ATTR_TDLS_SUPPORT,
        NL80211_ATTR_TDLS_EXTERNAL_SETUP,
 
+       NL80211_ATTR_DEVICE_AP_SME,
+
+       NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+       NL80211_ATTR_FEATURE_FLAGS,
+
+       NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+       NL80211_ATTR_PROBE_RESP,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1371,6 +1442,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -2650,4 +2722,43 @@ enum nl80211_tdls_operation {
        NL80211_TDLS_DISABLE_LINK,
 };
 
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *     TX status to the socket error queue when requested with the
+ *     socket option.
+ */
+enum nl80211_feature_flags {
+       NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *     protocols for probe-response offloading by the driver/FW.
+ *     To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *     Each enum value represents a bit in the bitmap of supported
+ *     protocols. Typically a subset of probe-requests belonging to a
+ *     supported protocol will be excluded from offload and uploaded
+ *     to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =        1<<0,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =       1<<1,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =        1<<2,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =     1<<3,
+};
+
 #endif /* __LINUX_NL80211_H */
index f53a4167c5f41bb2d9ba9a30fdecc3805f97a2df..f48bfc80cb4bfc7736173f6687550867ed0fc882 100644 (file)
@@ -38,6 +38,7 @@
 #define PNPIPE_ENCAP           1
 #define PNPIPE_IFINDEX         2
 #define PNPIPE_HANDLE          3
+#define PNPIPE_INITSTATE       4
 
 #define PNADDR_ANY             0
 #define PNADDR_BROADCAST       0xFC
@@ -49,6 +50,7 @@
 
 /* ioctls */
 #define SIOCPNGETOBJECT                (SIOCPROTOPRIVATE + 0)
+#define SIOCPNENABLEPIPE       (SIOCPROTOPRIVATE + 13)
 #define SIOCPNADDRESOURCE      (SIOCPROTOPRIVATE + 14)
 #define SIOCPNDELRESOURCE      (SIOCPROTOPRIVATE + 15)
 
index fe864885c1edd5edbebc0504544e4950ebf2962f..09b7ea566d666506fb37af4bb5623134fe09987b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/dmaengine.h>
 #include <linux/hrtimer.h>
 #include <linux/dma-mapping.h>
+#include <linux/netdev_features.h>
 
 /* Don't change this without changing skb_csum_unnecessary! */
 #define CHECKSUM_NONE 0
@@ -87,7 +88,6 @@
  *     at device setup time.
  *     NETIF_F_HW_CSUM - it is clever device, it is able to checksum
  *                       everything.
- *     NETIF_F_NO_CSUM - loopback or reliable single hop media.
  *     NETIF_F_IP_CSUM - device is dumb. It is able to csum only
  *                       TCP/UDP over IPv4. Sigh. Vendors like this
  *                       way by an unknown reason. Though, see comment above
@@ -218,6 +218,9 @@ enum {
 
        /* device driver supports TX zero-copy buffers */
        SKBTX_DEV_ZEROCOPY = 1 << 4,
+
+       /* generate wifi status information (where possible) */
+       SKBTX_WIFI_STATUS = 1 << 5,
 };
 
 /*
@@ -352,6 +355,8 @@ typedef unsigned char *sk_buff_data_t;
  *     @ooo_okay: allow the mapping of a socket to a queue to be changed
  *     @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport
  *             ports.
+ *     @wifi_acked_valid: wifi_acked was set
+ *     @wifi_acked: whether frame was acked on wifi or not
  *     @dma_cookie: a cookie to one of several possible DMA operations
  *             done by skb DMA functions
  *     @secmark: security marking
@@ -445,10 +450,11 @@ struct sk_buff {
 #endif
        __u8                    ooo_okay:1;
        __u8                    l4_rxhash:1;
+       __u8                    wifi_acked_valid:1;
+       __u8                    wifi_acked:1;
+       /* 10/12 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
-       /* 0/13 bit hole */
-
 #ifdef CONFIG_NET_DMA
        dma_cookie_t            dma_cookie;
 #endif
@@ -540,6 +546,7 @@ extern void consume_skb(struct sk_buff *skb);
 extern void           __kfree_skb(struct sk_buff *skb);
 extern struct sk_buff *__alloc_skb(unsigned int size,
                                   gfp_t priority, int fclone, int node);
+extern struct sk_buff *build_skb(void *data);
 static inline struct sk_buff *alloc_skb(unsigned int size,
                                        gfp_t priority)
 {
@@ -2105,7 +2112,8 @@ extern void              skb_split(struct sk_buff *skb,
 extern int            skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
                                 int shiftlen);
 
-extern struct sk_buff *skb_segment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *skb_segment(struct sk_buff *skb,
+                                  netdev_features_t features);
 
 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
                                       int len, void *buffer)
@@ -2263,6 +2271,15 @@ static inline void skb_tx_timestamp(struct sk_buff *skb)
        sw_tx_timestamp(skb);
 }
 
+/**
+ * skb_complete_wifi_ack - deliver skb with wifi status
+ *
+ * @skb: the original outgoing packet
+ * @acked: ack status
+ *
+ */
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
index add4790b21fe4ee18635db9456a43db71bb39997..63f98d0a8efa1245b1b4dc6a04ea5a1aec41d7d1 100644 (file)
  *     vdev: the virtio_device
  *     This gives the final feature bits for the device: it can change
  *     the dev->feature bits if it wants.
+ * @bus_name: return the bus name associated with the device
+ *     vdev: the virtio_device
+ *      This returns a pointer to the bus name a la pci_name from which
+ *      the caller can then copy.
  */
 typedef void vq_callback_t(struct virtqueue *);
 struct virtio_config_ops {
@@ -117,6 +121,7 @@ struct virtio_config_ops {
        void (*del_vqs)(struct virtio_device *);
        u32 (*get_features)(struct virtio_device *vdev);
        void (*finalize_features)(struct virtio_device *vdev);
+       const char *(*bus_name)(struct virtio_device *vdev);
 };
 
 /* If driver didn't advertise the feature, it will never appear. */
@@ -182,5 +187,14 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
                return ERR_PTR(err);
        return vq;
 }
+
+static inline
+const char *virtio_bus_name(struct virtio_device *vdev)
+{
+       if (!vdev->config->bus_name)
+               return "virtio";
+       return vdev->config->bus_name(vdev);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_VIRTIO_CONFIG_H */
index e86af08293a8217153b48a98a4802015376185db..835f3b229b8450d53f2ec434078dd9a3c0e8be52 100644 (file)
@@ -77,6 +77,33 @@ struct bt_power {
 #define BT_POWER_FORCE_ACTIVE_OFF 0
 #define BT_POWER_FORCE_ACTIVE_ON  1
 
+#define BT_CHANNEL_POLICY      10
+
+/* BR/EDR only (default policy)
+ *   AMP controllers cannot be used.
+ *   Channel move requests from the remote device are denied.
+ *   If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_BREDR_ONLY           0
+
+/* BR/EDR Preferred
+ *   Allow use of AMP controllers.
+ *   If the L2CAP channel is currently on AMP, move it to BR/EDR.
+ *   Channel move requests from the remote device are allowed.
+ */
+#define BT_CHANNEL_POLICY_BREDR_PREFERRED      1
+
+/* AMP Preferred
+ *   Allow use of AMP controllers
+ *   If the L2CAP channel is currently on BR/EDR and AMP controller
+ *     resources are available, initiate a channel move to AMP.
+ *   Channel move requests from the remote device are allowed.
+ *   If the L2CAP socket has not been connected yet, try to create
+ *     and configure the channel directly on an AMP controller rather
+ *     than BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_AMP_PREFERRED                2
+
 __printf(2, 3)
 int bt_printk(const char *level, const char *fmt, ...);
 
@@ -158,7 +185,7 @@ struct bt_skb_cb {
        __u8 pkt_type;
        __u8 incoming;
        __u16 expect;
-       __u8 tx_seq;
+       __u16 tx_seq;
        __u8 retries;
        __u8 sar;
        unsigned short channel;
index aaf79af7243262592607924aa1e4dd609da7d2aa..139ce2aa6eee700ba396343a268eda4962daa142 100644 (file)
@@ -264,6 +264,13 @@ enum {
 #define HCI_LK_SMP_IRK                 0x82
 #define HCI_LK_SMP_CSRK                        0x83
 
+/* ---- HCI Error Codes ---- */
+#define HCI_ERROR_AUTH_FAILURE         0x05
+#define HCI_ERROR_REJ_BAD_ADDR         0x0f
+#define HCI_ERROR_REMOTE_USER_TERM     0x13
+#define HCI_ERROR_LOCAL_HOST_TERM      0x16
+#define HCI_ERROR_PAIRING_NOT_ALLOWED  0x18
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP                     0x0000
 
@@ -726,6 +733,21 @@ struct hci_cp_write_page_scan_activity {
        #define PAGE_SCAN_TYPE_STANDARD         0x00
        #define PAGE_SCAN_TYPE_INTERLACED       0x01
 
+#define HCI_OP_READ_LOCAL_AMP_INFO     0x1409
+struct hci_rp_read_local_amp_info {
+       __u8     status;
+       __u8     amp_status;
+       __le32   total_bw;
+       __le32   max_bw;
+       __le32   min_latency;
+       __le32   max_pdu;
+       __u8     amp_type;
+       __le16   pal_cap;
+       __le16   max_assoc_size;
+       __le32   max_flush_to;
+       __le32   be_flush_to;
+} __packed;
+
 #define HCI_OP_LE_SET_EVENT_MASK       0x2001
 struct hci_cp_le_set_event_mask {
        __u8     mask[8];
index 3779ea3622576e9746dc72ebac57780c0f377e11..f333e7682607b1dbcc86871e3d0fd6c93a94c6cf 100644 (file)
@@ -32,6 +32,9 @@
 #define HCI_PROTO_L2CAP        0
 #define HCI_PROTO_SCO  1
 
+/* HCI priority */
+#define HCI_PRIO_MAX   7
+
 /* HCI Core structures */
 struct inquiry_data {
        bdaddr_t        bdaddr;
@@ -64,6 +67,12 @@ struct hci_conn_hash {
        unsigned int     le_num;
 };
 
+struct hci_chan_hash {
+       struct list_head list;
+       spinlock_t       lock;
+       unsigned int     num;
+};
+
 struct bdaddr_list {
        struct list_head list;
        bdaddr_t bdaddr;
@@ -150,6 +159,17 @@ struct hci_dev {
        __u16           sniff_min_interval;
        __u16           sniff_max_interval;
 
+       __u8            amp_status;
+       __u32           amp_total_bw;
+       __u32           amp_max_bw;
+       __u32           amp_min_latency;
+       __u32           amp_max_pdu;
+       __u8            amp_type;
+       __u16           amp_pal_cap;
+       __u16           amp_assoc_size;
+       __u32           amp_max_flush_to;
+       __u32           amp_be_flush_to;
+
        unsigned int    auto_accept_delay;
 
        unsigned long   quirks;
@@ -173,8 +193,10 @@ struct hci_dev {
        struct workqueue_struct *workqueue;
 
        struct work_struct      power_on;
-       struct work_struct      power_off;
-       struct timer_list       off_timer;
+       struct delayed_work     power_off;
+
+       __u16                   discov_timeout;
+       struct delayed_work     discov_off;
 
        struct timer_list       cmd_timer;
        struct tasklet_struct   cmd_task;
@@ -195,6 +217,8 @@ struct hci_dev {
 
        __u16                   init_last_cmd;
 
+       struct list_head        mgmt_pending;
+
        struct inquiry_cache    inq_cache;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
@@ -273,6 +297,7 @@ struct hci_conn {
        unsigned int    sent;
 
        struct sk_buff_head data_q;
+       struct hci_chan_hash chan_hash;
 
        struct timer_list disc_timer;
        struct timer_list idle_timer;
@@ -295,6 +320,14 @@ struct hci_conn {
        void (*disconn_cfm_cb)  (struct hci_conn *conn, u8 reason);
 };
 
+struct hci_chan {
+       struct list_head list;
+
+       struct hci_conn *conn;
+       struct sk_buff_head data_q;
+       unsigned int    sent;
+};
+
 extern struct hci_proto *hci_proto[];
 extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
@@ -455,6 +488,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
        return NULL;
 }
 
+static inline void hci_chan_hash_init(struct hci_conn *c)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       INIT_LIST_HEAD(&h->list);
+       spin_lock_init(&h->lock);
+       h->num = 0;
+}
+
+static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       list_add(&chan->list, &h->list);
+       h->num++;
+}
+
+static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       list_del(&chan->list);
+       h->num--;
+}
+
 void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
@@ -466,6 +521,10 @@ int hci_conn_del(struct hci_conn *conn);
 void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
+struct hci_chan *hci_chan_create(struct hci_conn *conn);
+int hci_chan_del(struct hci_chan *chan);
+void hci_chan_hash_flush(struct hci_conn *conn);
+
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                                                __u8 sec_level, __u8 auth_type);
 int hci_conn_check_link_mode(struct hci_conn *conn);
@@ -545,7 +604,7 @@ struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
 int hci_register_dev(struct hci_dev *hdev);
-int hci_unregister_dev(struct hci_dev *hdev);
+void hci_unregister_dev(struct hci_dev *hdev);
 int hci_suspend_dev(struct hci_dev *hdev);
 int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
@@ -599,8 +658,9 @@ int hci_recv_frame(struct sk_buff *skb);
 int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
 
-int hci_register_sysfs(struct hci_dev *hdev);
-void hci_unregister_sysfs(struct hci_dev *hdev);
+void hci_init_sysfs(struct hci_dev *hdev);
+int hci_add_sysfs(struct hci_dev *hdev);
+void hci_del_sysfs(struct hci_dev *hdev);
 void hci_conn_init_sysfs(struct hci_conn *conn);
 void hci_conn_add_sysfs(struct hci_conn *conn);
 void hci_conn_del_sysfs(struct hci_conn *conn);
@@ -676,7 +736,7 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
 static inline int hci_proto_disconn_ind(struct hci_conn *conn)
 {
        register struct hci_proto *hp;
-       int reason = 0x13;
+       int reason = HCI_ERROR_REMOTE_USER_TERM;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
        if (hp && hp->disconn_ind)
@@ -836,7 +896,7 @@ int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
@@ -849,34 +909,41 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
 
 /* Management interface */
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
-int mgmt_index_added(u16 index);
-int mgmt_index_removed(u16 index);
-int mgmt_powered(u16 index, u8 powered);
-int mgmt_discoverable(u16 index, u8 discoverable);
-int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
-int mgmt_disconnect_failed(u16 index);
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint);
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
+int mgmt_index_added(struct hci_dev *hdev);
+int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_powered(struct hci_dev *hdev, u8 powered);
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent);
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_disconnect_failed(struct hci_dev *hdev);
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
                                                                u8 status);
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                                                u8 status);
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir);
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
-int mgmt_discovering(u16 index, u8 discovering);
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint);
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status);
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                       u8 *dev_class, s8 rssi, u8 *eir);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
+int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status);
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
@@ -915,4 +982,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
 void hci_le_ltk_neg_reply(struct hci_conn *conn);
 
+int hci_do_inquiry(struct hci_dev *hdev, u8 length);
+int hci_cancel_inquiry(struct hci_dev *hdev);
+
 #endif /* __HCI_CORE_H */
index 6cc18f37167519260e15d1ad20d7bf2f145c86c5..875021ad0675098e6e9bb5cfa1cfc5dea170bcad 100644 (file)
 #ifndef __L2CAP_H
 #define __L2CAP_H
 
+#include <asm/unaligned.h>
+
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU              672
 #define L2CAP_DEFAULT_MIN_MTU          48
 #define L2CAP_DEFAULT_FLUSH_TO         0xffff
 #define L2CAP_DEFAULT_TX_WINDOW                63
+#define L2CAP_DEFAULT_EXT_WINDOW       0x3FFF
 #define L2CAP_DEFAULT_MAX_TX           3
 #define L2CAP_DEFAULT_RETRANS_TO       2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO           200
 #define L2CAP_LE_DEFAULT_MTU           23
+#define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
+#define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
+#define L2CAP_DEFAULT_ACC_LAT          0xFFFFFFFF
 
 #define L2CAP_DISC_TIMEOUT             (100)
 #define L2CAP_DISC_REJ_TIMEOUT         (5000)  /*  5 seconds */
@@ -91,52 +97,82 @@ struct l2cap_conninfo {
 #define L2CAP_ECHO_RSP         0x09
 #define L2CAP_INFO_REQ         0x0a
 #define L2CAP_INFO_RSP         0x0b
+#define L2CAP_CREATE_CHAN_REQ  0x0c
+#define L2CAP_CREATE_CHAN_RSP  0x0d
+#define L2CAP_MOVE_CHAN_REQ    0x0e
+#define L2CAP_MOVE_CHAN_RSP    0x0f
+#define L2CAP_MOVE_CHAN_CFM    0x10
+#define L2CAP_MOVE_CHAN_CFM_RSP        0x11
 #define L2CAP_CONN_PARAM_UPDATE_REQ    0x12
 #define L2CAP_CONN_PARAM_UPDATE_RSP    0x13
 
-/* L2CAP feature mask */
+/* L2CAP extended feature mask */
 #define L2CAP_FEAT_FLOWCTL     0x00000001
 #define L2CAP_FEAT_RETRANS     0x00000002
+#define L2CAP_FEAT_BIDIR_QOS   0x00000004
 #define L2CAP_FEAT_ERTM                0x00000008
 #define L2CAP_FEAT_STREAMING   0x00000010
 #define L2CAP_FEAT_FCS         0x00000020
+#define L2CAP_FEAT_EXT_FLOW    0x00000040
 #define L2CAP_FEAT_FIXED_CHAN  0x00000080
+#define L2CAP_FEAT_EXT_WINDOW  0x00000100
+#define L2CAP_FEAT_UCD         0x00000200
 
 /* L2CAP checksum option */
 #define L2CAP_FCS_NONE         0x00
 #define L2CAP_FCS_CRC16                0x01
 
+/* L2CAP fixed channels */
+#define L2CAP_FC_L2CAP         0x02
+#define L2CAP_FC_A2MP          0x08
+
 /* L2CAP Control Field bit masks */
-#define L2CAP_CTRL_SAR               0xC000
-#define L2CAP_CTRL_REQSEQ            0x3F00
-#define L2CAP_CTRL_TXSEQ             0x007E
-#define L2CAP_CTRL_RETRANS           0x0080
-#define L2CAP_CTRL_FINAL             0x0080
-#define L2CAP_CTRL_POLL              0x0010
-#define L2CAP_CTRL_SUPERVISE         0x000C
-#define L2CAP_CTRL_FRAME_TYPE        0x0001 /* I- or S-Frame */
-
-#define L2CAP_CTRL_TXSEQ_SHIFT      1
-#define L2CAP_CTRL_REQSEQ_SHIFT     8
-#define L2CAP_CTRL_SAR_SHIFT       14
+#define L2CAP_CTRL_SAR                 0xC000
+#define L2CAP_CTRL_REQSEQ              0x3F00
+#define L2CAP_CTRL_TXSEQ               0x007E
+#define L2CAP_CTRL_SUPERVISE           0x000C
+
+#define L2CAP_CTRL_RETRANS             0x0080
+#define L2CAP_CTRL_FINAL               0x0080
+#define L2CAP_CTRL_POLL                        0x0010
+#define L2CAP_CTRL_FRAME_TYPE          0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT         1
+#define L2CAP_CTRL_SUPER_SHIFT         2
+#define L2CAP_CTRL_REQSEQ_SHIFT                8
+#define L2CAP_CTRL_SAR_SHIFT           14
+
+/* L2CAP Extended Control Field bit mask */
+#define L2CAP_EXT_CTRL_TXSEQ           0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR             0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE       0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ          0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL            0x00040000
+#define L2CAP_EXT_CTRL_FINAL           0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE      0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT    2
+#define L2CAP_EXT_CTRL_SAR_SHIFT       16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT     16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT     18
 
 /* L2CAP Supervisory Function */
-#define L2CAP_SUPER_RCV_READY           0x0000
-#define L2CAP_SUPER_REJECT              0x0004
-#define L2CAP_SUPER_RCV_NOT_READY       0x0008
-#define L2CAP_SUPER_SELECT_REJECT       0x000C
+#define L2CAP_SUPER_RR         0x00
+#define L2CAP_SUPER_REJ                0x01
+#define L2CAP_SUPER_RNR                0x02
+#define L2CAP_SUPER_SREJ       0x03
 
 /* L2CAP Segmentation and Reassembly */
-#define L2CAP_SDU_UNSEGMENTED       0x0000
-#define L2CAP_SDU_START             0x4000
-#define L2CAP_SDU_END               0x8000
-#define L2CAP_SDU_CONTINUE          0xC000
+#define L2CAP_SAR_UNSEGMENTED  0x00
+#define L2CAP_SAR_START                0x01
+#define L2CAP_SAR_END          0x02
+#define L2CAP_SAR_CONTINUE     0x03
 
 /* L2CAP Command rej. reasons */
-#define L2CAP_REJ_NOT_UNDERSTOOD      0x0000
-#define L2CAP_REJ_MTU_EXCEEDED        0x0001
-#define L2CAP_REJ_INVALID_CID         0x0002
-
+#define L2CAP_REJ_NOT_UNDERSTOOD       0x0000
+#define L2CAP_REJ_MTU_EXCEEDED         0x0001
+#define L2CAP_REJ_INVALID_CID          0x0002
 
 /* L2CAP structures */
 struct l2cap_hdr {
@@ -144,6 +180,12 @@ struct l2cap_hdr {
        __le16     cid;
 } __packed;
 #define L2CAP_HDR_SIZE         4
+#define L2CAP_ENH_HDR_SIZE     6
+#define L2CAP_EXT_HDR_SIZE     8
+
+#define L2CAP_FCS_SIZE         2
+#define L2CAP_SDULEN_SIZE      2
+#define L2CAP_PSMLEN_SIZE      2
 
 struct l2cap_cmd_hdr {
        __u8       code;
@@ -188,14 +230,15 @@ struct l2cap_conn_rsp {
 #define L2CAP_CID_DYN_START    0x0040
 #define L2CAP_CID_DYN_END      0xffff
 
-/* connect result */
+/* connect/create channel results */
 #define L2CAP_CR_SUCCESS       0x0000
 #define L2CAP_CR_PEND          0x0001
 #define L2CAP_CR_BAD_PSM       0x0002
 #define L2CAP_CR_SEC_BLOCK     0x0003
 #define L2CAP_CR_NO_MEM                0x0004
+#define L2CAP_CR_BAD_AMP       0x0005
 
-/* connect status */
+/* connect/create channel status */
 #define L2CAP_CS_NO_INFO       0x0000
 #define L2CAP_CS_AUTHEN_PEND   0x0001
 #define L2CAP_CS_AUTHOR_PEND   0x0002
@@ -217,6 +260,8 @@ struct l2cap_conf_rsp {
 #define L2CAP_CONF_UNACCEPT    0x0001
 #define L2CAP_CONF_REJECT      0x0002
 #define L2CAP_CONF_UNKNOWN     0x0003
+#define L2CAP_CONF_PENDING     0x0004
+#define L2CAP_CONF_EFS_REJECT  0x0005
 
 struct l2cap_conf_opt {
        __u8       type;
@@ -233,6 +278,8 @@ struct l2cap_conf_opt {
 #define L2CAP_CONF_QOS         0x03
 #define L2CAP_CONF_RFC         0x04
 #define L2CAP_CONF_FCS         0x05
+#define L2CAP_CONF_EFS         0x06
+#define L2CAP_CONF_EWS         0x07
 
 #define L2CAP_CONF_MAX_SIZE    22
 
@@ -251,6 +298,21 @@ struct l2cap_conf_rfc {
 #define L2CAP_MODE_ERTM                0x03
 #define L2CAP_MODE_STREAMING   0x04
 
+struct l2cap_conf_efs {
+       __u8    id;
+       __u8    stype;
+       __le16  msdu;
+       __le32  sdu_itime;
+       __le32  acc_lat;
+       __le32  flush_to;
+} __packed;
+
+#define L2CAP_SERV_NOTRAFIC    0x00
+#define L2CAP_SERV_BESTEFFORT  0x01
+#define L2CAP_SERV_GUARANTEED  0x02
+
+#define L2CAP_BESTEFFORT_ID    0x01
+
 struct l2cap_disconn_req {
        __le16     dcid;
        __le16     scid;
@@ -271,14 +333,57 @@ struct l2cap_info_rsp {
        __u8        data[0];
 } __packed;
 
+struct l2cap_create_chan_req {
+       __le16      psm;
+       __le16      scid;
+       __u8        amp_id;
+} __packed;
+
+struct l2cap_create_chan_rsp {
+       __le16      dcid;
+       __le16      scid;
+       __le16      result;
+       __le16      status;
+} __packed;
+
+struct l2cap_move_chan_req {
+       __le16      icid;
+       __u8        dest_amp_id;
+} __packed;
+
+struct l2cap_move_chan_rsp {
+       __le16      icid;
+       __le16      result;
+} __packed;
+
+#define L2CAP_MR_SUCCESS       0x0000
+#define L2CAP_MR_PEND          0x0001
+#define L2CAP_MR_BAD_ID                0x0002
+#define L2CAP_MR_SAME_ID       0x0003
+#define L2CAP_MR_NOT_SUPP      0x0004
+#define L2CAP_MR_COLLISION     0x0005
+#define L2CAP_MR_NOT_ALLOWED   0x0006
+
+struct l2cap_move_chan_cfm {
+       __le16      icid;
+       __le16      result;
+} __packed;
+
+#define L2CAP_MC_CONFIRMED     0x0000
+#define L2CAP_MC_UNCONFIRMED   0x0001
+
+struct l2cap_move_chan_cfm_rsp {
+       __le16      icid;
+} __packed;
+
 /* info type */
-#define L2CAP_IT_CL_MTU     0x0001
-#define L2CAP_IT_FEAT_MASK  0x0002
-#define L2CAP_IT_FIXED_CHAN 0x0003
+#define L2CAP_IT_CL_MTU                0x0001
+#define L2CAP_IT_FEAT_MASK     0x0002
+#define L2CAP_IT_FIXED_CHAN    0x0003
 
 /* info result */
-#define L2CAP_IR_SUCCESS    0x0000
-#define L2CAP_IR_NOTSUPP    0x0001
+#define L2CAP_IR_SUCCESS       0x0000
+#define L2CAP_IR_NOTSUPP       0x0001
 
 struct l2cap_conn_param_update_req {
        __le16      min;
@@ -297,7 +402,7 @@ struct l2cap_conn_param_update_rsp {
 
 /* ----- L2CAP channels and connections ----- */
 struct srej_list {
-       __u   tx_seq;
+       __u16   tx_seq;
        struct list_head list;
 };
 
@@ -319,14 +424,11 @@ struct l2cap_chan {
        __u16           flush_to;
        __u8            mode;
        __u8            chan_type;
+       __u8            chan_policy;
 
        __le16          sport;
 
        __u8            sec_level;
-       __u8            role_switch;
-       __u8            force_reliable;
-       __u8            flushable;
-       __u8            force_active;
 
        __u8            ident;
 
@@ -337,7 +439,8 @@ struct l2cap_chan {
 
        __u8            fcs;
 
-       __u8            tx_win;
+       __u16           tx_win;
+       __u16           tx_win_max;
        __u8            max_tx;
        __u16           retrans_timeout;
        __u16           monitor_timeout;
@@ -345,25 +448,40 @@ struct l2cap_chan {
 
        unsigned long   conf_state;
        unsigned long   conn_state;
-
-       __u8            next_tx_seq;
-       __u8            expected_ack_seq;
-       __u8            expected_tx_seq;
-       __u8            buffer_seq;
-       __u8            buffer_seq_srej;
-       __u8            srej_save_reqseq;
-       __u8            frames_sent;
-       __u8            unacked_frames;
+       unsigned long   flags;
+
+       __u16           next_tx_seq;
+       __u16           expected_ack_seq;
+       __u16           expected_tx_seq;
+       __u16           buffer_seq;
+       __u16           buffer_seq_srej;
+       __u16           srej_save_reqseq;
+       __u16           frames_sent;
+       __u16           unacked_frames;
        __u8            retry_count;
        __u8            num_acked;
        __u16           sdu_len;
        struct sk_buff  *sdu;
        struct sk_buff  *sdu_last_frag;
 
-       __u           remote_tx_win;
+       __u16           remote_tx_win;
        __u8            remote_max_tx;
        __u16           remote_mps;
 
+       __u8            local_id;
+       __u8            local_stype;
+       __u16           local_msdu;
+       __u32           local_sdu_itime;
+       __u32           local_acc_lat;
+       __u32           local_flush_to;
+
+       __u8            remote_id;
+       __u8            remote_stype;
+       __u16           remote_msdu;
+       __u32           remote_sdu_itime;
+       __u32           remote_acc_lat;
+       __u32           remote_flush_to;
+
        struct timer_list       chan_timer;
        struct timer_list       retrans_timer;
        struct timer_list       monitor_timer;
@@ -391,6 +509,7 @@ struct l2cap_ops {
 
 struct l2cap_conn {
        struct hci_conn *hcon;
+       struct hci_chan *hchan;
 
        bdaddr_t        *dst;
        bdaddr_t        *src;
@@ -445,6 +564,9 @@ enum {
        CONF_CONNECT_PEND,
        CONF_NO_FCS_RECV,
        CONF_STATE2_DEVICE,
+       CONF_EWS_RECV,
+       CONF_LOC_CONF_PEND,
+       CONF_REM_CONF_PEND,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -462,6 +584,16 @@ enum {
        CONN_RNR_SENT,
 };
 
+/* Definitions for flags in l2cap_chan */
+enum {
+       FLAG_ROLE_SWITCH,
+       FLAG_FORCE_ACTIVE,
+       FLAG_FORCE_RELIABLE,
+       FLAG_FLUSHABLE,
+       FLAG_EXT_CTRL,
+       FLAG_EFS_ENABLE,
+};
+
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
 #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
@@ -474,6 +606,22 @@ enum {
                L2CAP_DEFAULT_ACK_TO);
 #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
 
+static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
+{
+       int offset;
+
+       offset = (seq1 - seq2) % (chan->tx_win_max + 1);
+       if (offset < 0)
+               offset += (chan->tx_win_max + 1);
+
+       return offset;
+}
+
+static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
+{
+       return (seq + 1) % (chan->tx_win_max + 1);
+}
+
 static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 {
        int sub;
@@ -486,13 +634,165 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
        return sub == ch->remote_tx_win;
 }
 
-#define __get_txseq(ctrl)      (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
-#define __get_reqseq(ctrl)     (((ctrl) & L2CAP_CTRL_REQSEQ) >> 8)
-#define __is_iframe(ctrl)      (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
-#define __is_sframe(ctrl)      ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
-#define __is_sar_start(ctrl)   (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
+static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
+                                               L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
+}
+
+static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
+                                                       L2CAP_EXT_CTRL_REQSEQ;
+       else
+               return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+}
+
+static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
+                                               L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
+}
+
+static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
+                                                       L2CAP_EXT_CTRL_TXSEQ;
+       else
+               return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
+}
+
+static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
+       else
+               return ctrl & L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u32 __set_sframe(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_FRAME_TYPE;
+       else
+               return L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
+}
+
+static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
+       else
+               return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
+}
+
+static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
+{
+       return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
+}
+
+static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_SAR;
+       else
+               return L2CAP_CTRL_SAR;
+}
+
+static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
+                                               L2CAP_EXT_CTRL_SUPER_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
+}
+
+static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
+                                               L2CAP_EXT_CTRL_SUPERVISE;
+       else
+               return (super << L2CAP_CTRL_SUPER_SHIFT) &
+                                                       L2CAP_CTRL_SUPERVISE;
+}
+
+static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_FINAL;
+       else
+               return L2CAP_CTRL_FINAL;
+}
+
+static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_FINAL;
+       else
+               return ctrl & L2CAP_CTRL_FINAL;
+}
+
+static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_POLL;
+       else
+               return L2CAP_CTRL_POLL;
+}
+
+static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_POLL;
+       else
+               return ctrl & L2CAP_CTRL_POLL;
+}
+
+static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return get_unaligned_le32(p);
+       else
+               return get_unaligned_le16(p);
+}
+
+static inline void __put_control(struct l2cap_chan *chan, __u32 control,
+                                                               void *p)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return put_unaligned_le32(control, p);
+       else
+               return put_unaligned_le16(control, p);
+}
+
+static inline __u8 __ctrl_size(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
+       else
+               return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
+}
 
 extern int disable_ertm;
+extern int enable_hs;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
@@ -507,7 +807,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
 void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan);
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                                                               u32 priority);
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 
 #endif /* __L2CAP_H */
index d66da0f94f95ae60e4ceb1d2fe713bc90c376e08..3e320c9cae8ffc7238d1c1197dc45c828a90931b 100644 (file)
@@ -69,6 +69,10 @@ struct mgmt_mode {
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
+struct mgmt_cp_set_discoverable {
+       __u8 val;
+       __u16 timeout;
+} __packed;
 
 #define MGMT_OP_SET_CONNECTABLE                0x0007
 
@@ -96,24 +100,22 @@ struct mgmt_cp_set_service_cache {
        __u8 enable;
 } __packed;
 
-struct mgmt_key_info {
+struct mgmt_link_key_info {
        bdaddr_t bdaddr;
        u8 type;
        u8 val[16];
        u8 pin_len;
-       u8 dlen;
-       u8 data[0];
 } __packed;
 
-#define MGMT_OP_LOAD_KEYS              0x000D
-struct mgmt_cp_load_keys {
+#define MGMT_OP_LOAD_LINK_KEYS         0x000D
+struct mgmt_cp_load_link_keys {
        __u8 debug_keys;
        __le16 key_count;
-       struct mgmt_key_info keys[0];
+       struct mgmt_link_key_info keys[0];
 } __packed;
 
-#define MGMT_OP_REMOVE_KEY             0x000E
-struct mgmt_cp_remove_key {
+#define MGMT_OP_REMOVE_KEYS            0x000E
+struct mgmt_cp_remove_keys {
        bdaddr_t bdaddr;
        __u8 disconnect;
 } __packed;
@@ -126,10 +128,20 @@ struct mgmt_rp_disconnect {
        bdaddr_t bdaddr;
 } __packed;
 
+#define MGMT_ADDR_BREDR                        0x00
+#define MGMT_ADDR_LE                   0x01
+#define MGMT_ADDR_BREDR_LE             0x02
+#define MGMT_ADDR_INVALID              0xff
+
+struct mgmt_addr_info {
+       bdaddr_t bdaddr;
+       __u8 type;
+} __packed;
+
 #define MGMT_OP_GET_CONNECTIONS                0x0010
 struct mgmt_rp_get_connections {
        __le16 conn_count;
-       bdaddr_t conn[0];
+       struct mgmt_addr_info addr[0];
 } __packed;
 
 #define MGMT_OP_PIN_CODE_REPLY         0x0011
@@ -245,26 +257,19 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_PAIRABLE               0x0009
 
-#define MGMT_EV_NEW_KEY                        0x000A
-struct mgmt_ev_new_key {
+#define MGMT_EV_NEW_LINK_KEY           0x000A
+struct mgmt_ev_new_link_key {
        __u8 store_hint;
-       struct mgmt_key_info key;
+       struct mgmt_link_key_info key;
 } __packed;
 
 #define MGMT_EV_CONNECTED              0x000B
-struct mgmt_ev_connected {
-       bdaddr_t bdaddr;
-       __u8 link_type;
-} __packed;
 
 #define MGMT_EV_DISCONNECTED           0x000C
-struct mgmt_ev_disconnected {
-       bdaddr_t bdaddr;
-} __packed;
 
 #define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        __u8 status;
 } __packed;
 
@@ -294,7 +299,7 @@ struct mgmt_ev_local_name_changed {
 
 #define MGMT_EV_DEVICE_FOUND           0x0012
 struct mgmt_ev_device_found {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        __u8 dev_class[3];
        __s8 rssi;
        __u8 eir[HCI_MAX_EIR_LENGTH];
index 95852e36713b5e302e365033957d16910de01952..8d7ba0961d3e694115f60b7c17dbaadc396b93b0 100644 (file)
@@ -391,6 +391,8 @@ struct cfg80211_crypto_settings {
  * @assocresp_ies: extra information element(s) to add into (Re)Association
  *     Response frames or %NULL
  * @assocresp_ies_len: length of assocresp_ies in octets
+ * @probe_resp_len: length of probe response template (@probe_resp)
+ * @probe_resp: probe response template (AP mode only)
  */
 struct beacon_parameters {
        u8 *head, *tail;
@@ -408,6 +410,8 @@ struct beacon_parameters {
        size_t proberesp_ies_len;
        const u8 *assocresp_ies;
        size_t assocresp_ies_len;
+       int probe_resp_len;
+       u8 *probe_resp;
 };
 
 /**
@@ -1342,6 +1346,9 @@ struct cfg80211_gtk_rekey_data {
  *     doesn't verify much. Note, however, that the passed netdev may be
  *     %NULL as well if the user requested changing the channel for the
  *     device itself, or for a monitor interface.
+ * @get_channel: Get the current operating channel, should return %NULL if
+ *     there's no single defined operating channel if for example the
+ *     device implements channel hopping for multi-channel virtual interfaces.
  *
  * @scan: Request to do a scan. If returning zero, the scan request is given
  *     the driver, and will be valid until passed to cfg80211_scan_done().
@@ -1432,6 +1439,9 @@ struct cfg80211_gtk_rekey_data {
  *
  * @tdls_mgmt: Transmit a TDLS management frame.
  * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
+ *
+ * @probe_client: probe an associated client, must return a cookie that it
+ *     later passes to cfg80211_probe_status().
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1585,7 +1595,7 @@ struct cfg80211_ops {
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie);
+                         bool dont_wait_for_ack, u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct net_device *dev,
                                       u64 cookie);
@@ -1621,6 +1631,11 @@ struct cfg80211_ops {
                             u16 status_code, const u8 *buf, size_t len);
        int     (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
                             u8 *peer, enum nl80211_tdls_operation oper);
+
+       int     (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
+                               const u8 *peer, u64 *cookie);
+
+       struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
 };
 
 /*
@@ -1679,6 +1694,12 @@ struct cfg80211_ops {
  *     teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
  *     command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver/firmware to perform a TDLS operation.
+ * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
+ * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
+ *     when there are virtual interfaces in AP mode by calling
+ *     cfg80211_report_obss_beacon().
+ * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
+ *     responds to probe-requests in hardware.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -1697,6 +1718,9 @@ enum wiphy_flags {
        WIPHY_FLAG_AP_UAPSD                     = BIT(14),
        WIPHY_FLAG_SUPPORTS_TDLS                = BIT(15),
        WIPHY_FLAG_TDLS_EXTERNAL_SETUP          = BIT(16),
+       WIPHY_FLAG_HAVE_AP_SME                  = BIT(17),
+       WIPHY_FLAG_REPORTS_OBSS                 = BIT(18),
+       WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD        = BIT(19),
 };
 
 /**
@@ -1869,6 +1893,7 @@ struct wiphy_wowlan_support {
  * @software_iftypes: bitmask of software interface types, these are not
  *     subject to any restrictions since they are purely managed in SW.
  * @flags: wiphy flags, see &enum wiphy_flags
+ * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *     this variable determines its size
  * @max_scan_ssids: maximum number of SSIDs the device can scan for in
@@ -1907,6 +1932,8 @@ struct wiphy_wowlan_support {
  *     may request, if implemented.
  *
  * @wowlan: WoWLAN support information
+ *
+ * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -1928,7 +1955,9 @@ struct wiphy {
        /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
        u16 interface_modes;
 
-       u32 flags;
+       u32 flags, features;
+
+       u32 ap_sme_capa;
 
        enum cfg80211_signal_type signal_type;
 
@@ -1960,6 +1989,13 @@ struct wiphy {
        u32 available_antennas_tx;
        u32 available_antennas_rx;
 
+       /*
+        * Bitmap of supported protocols for probe response offloading
+        * see &enum nl80211_probe_resp_offload_support_attr. Only valid
+        * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
+        */
+       u32 probe_resp_offload;
+
        /* If multiple wiphys are registered and you're handed e.g.
         * a regular netdev with assigned ieee80211_ptr, you won't
         * know whether it points to a wiphy your driver has registered
@@ -2183,6 +2219,8 @@ struct wireless_dev {
 
        int beacon_interval;
 
+       u32 ap_unexpected_nlpid;
+
 #ifdef CONFIG_CFG80211_WEXT
        /* wext data */
        struct {
@@ -2636,8 +2674,10 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
  *
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
+ *
+ * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
  */
-struct cfg80211_bss*
+struct cfg80211_bss * __must_check
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
@@ -2659,8 +2699,10 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
  *
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
+ *
+ * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
  */
-struct cfg80211_bss*
+struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
                    struct ieee80211_channel *channel,
                    const u8 *bssid,
@@ -3189,6 +3231,64 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
 void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
                                     const u8 *bssid, bool preauth, gfp_t gfp);
 
+/**
+ * cfg80211_rx_spurious_frame - inform userspace about a spurious frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * a spurious class 3 frame was received, to be able to deauth the
+ * sender.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp);
+
+/**
+ * cfg80211_rx_unexpected_4addr_frame - inform about unexpected WDS frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * an associated station sent a 4addr frame but that wasn't expected.
+ * It is allowed and desirable to send this event only once for each
+ * station to avoid event flooding.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp);
+
+/**
+ * cfg80211_probe_status - notify userspace about probe status
+ * @dev: the device the probe was sent on
+ * @addr: the address of the peer
+ * @cookie: the cookie filled in @probe_client previously
+ * @acked: indicates whether probe was acked or not
+ * @gfp: allocation flags
+ */
+void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+                          u64 cookie, bool acked, gfp_t gfp);
+
+/**
+ * cfg80211_report_obss_beacon - report beacon from other APs
+ * @wiphy: The wiphy that received the beacon
+ * @frame: the frame
+ * @len: length of the frame
+ * @freq: frequency the frame was received on
+ * @gfp: allocation flags
+ *
+ * Use this function to report to userspace when a beacon was
+ * received. It is not useful to call this when there is no
+ * netdev that is in AP/GO mode.
+ */
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+                                const u8 *frame, size_t len,
+                                int freq, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index f0698b955b73c7ab41051fdf6508f4ab827932c0..75d615649071e39688b7f12a0e8a9c4066b8b31d 100644 (file)
@@ -31,8 +31,8 @@ struct icmp_err {
 extern const struct icmp_err icmp_err_convert[];
 #define ICMP_INC_STATS(net, field)     SNMP_INC_STATS((net)->mib.icmp_statistics, field)
 #define ICMP_INC_STATS_BH(net, field)  SNMP_INC_STATS_BH((net)->mib.icmp_statistics, field)
-#define ICMPMSGOUT_INC_STATS(net, field)       SNMP_INC_STATS((net)->mib.icmpmsg_statistics, field+256)
-#define ICMPMSGIN_INC_STATS_BH(net, field)     SNMP_INC_STATS_BH((net)->mib.icmpmsg_statistics, field)
+#define ICMPMSGOUT_INC_STATS(net, field)       SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field+256)
+#define ICMPMSGIN_INC_STATS_BH(net, field)     SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field)
 
 struct dst_entry;
 struct net_proto_family;
index 7e2c4d483ad0c4cf0ad1b39870baffdc92a78754..71392545d0a110906abbe4e51b8cb367cd4fc70f 100644 (file)
@@ -271,14 +271,6 @@ enum ieee80211_radiotap_type {
 #define IEEE80211_RADIOTAP_MCS_FEC_LDPC                0x10
 
 
-/* Ugly macro to convert literal channel numbers into their mhz equivalents
- * There are certianly some conditions that will break this (like feeding it '30')
- * but they shouldn't arise since nothing talks on channel 30. */
-#define ieee80211chan2mhz(x) \
-       (((x) <= 14) ? \
-       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
-       ((x) + 1000) * 5)
-
 /* helpers */
 static inline int ieee80211_get_radiotap_len(unsigned char *data)
 {
index d52685defb11e8e5fa7f277af4bb20d6dd1c9dc1..ee59f8b188ddfb081c948b27f54ac73839a9d2ef 100644 (file)
  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
  * Maxim Osipov <maxim.osipov@siemens.com>
  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
+ * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  */
 
 #ifndef NET_IEEE802154_H
 #define NET_IEEE802154_H
 
+#define IEEE802154_MTU                 127
+
 #define IEEE802154_FC_TYPE_BEACON      0x0     /* Frame is beacon */
 #define        IEEE802154_FC_TYPE_DATA         0x1     /* Frame is data */
 #define IEEE802154_FC_TYPE_ACK         0x2     /* Frame is acknowledgment */
@@ -56,6 +59,9 @@
        (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
 
 
+/* MAC footer size */
+#define IEEE802154_MFR_SIZE    2 /* 2 octets */
+
 /* MAC's Command Frames Identifiers */
 #define IEEE802154_CMD_ASSOCIATION_REQ         0x01
 #define IEEE802154_CMD_ASSOCIATION_RESP                0x02
index e6db62e756dc57b14db644c4c220aedb34f09051..dbf9aab34c82747d0c62f76e7f0d569eb14a0e48 100644 (file)
@@ -143,9 +143,9 @@ static inline void *inet_csk_ca(const struct sock *sk)
        return (void *)inet_csk(sk)->icsk_ca_priv;
 }
 
-extern struct sock *inet_csk_clone(struct sock *sk,
-                                  const struct request_sock *req,
-                                  const gfp_t priority);
+extern struct sock *inet_csk_clone_lock(const struct sock *sk,
+                                       const struct request_sock *req,
+                                       const gfp_t priority);
 
 enum inet_csk_ack_state_t {
        ICSK_ACK_SCHED  = 1,
index eca0ef7a495e9d1605b7705e73ee3377bd8aaae5..fd1561e88a1a54dfa1e239633c5cf4109790b3ab 100644 (file)
@@ -450,7 +450,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
  *     Functions provided by ip_sockglue.c
  */
 
-extern int     ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
+extern void    ipv4_pktinfo_prepare(struct sk_buff *skb);
 extern void    ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
 extern int     ip_cmsg_send(struct net *net,
                             struct msghdr *msg, struct ipcm_cookie *ipc);
index a366a8a1fe2380e92ce604a21d44e8e598e484f4..3f0258d2ef01f530685e11b0984027b8ef8a7fde 100644 (file)
@@ -132,6 +132,15 @@ extern struct ctl_path net_ipv6_ctl_path[];
        SNMP_INC_STATS##modifier((net)->mib.statname##_statistics, (field));\
 })
 
+/* per device and per net counters are atomic_long_t */
+#define _DEVINC_ATOMIC_ATOMIC(net, statname, idev, field)              \
+({                                                                     \
+       struct inet6_dev *_idev = (idev);                               \
+       if (likely(_idev != NULL))                                      \
+               SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \
+       SNMP_INC_STATS_ATOMIC_LONG((net)->mib.statname##_statistics, (field));\
+})
+
 #define _DEVADD(net, statname, modifier, idev, field, val)             \
 ({                                                                     \
        struct inet6_dev *_idev = (idev);                               \
@@ -168,11 +177,11 @@ extern struct ctl_path net_ipv6_ctl_path[];
                _DEVINCATOMIC(net, icmpv6, _BH, idev, field)
 
 #define ICMP6MSGOUT_INC_STATS(net, idev, field)                \
-       _DEVINCATOMIC(net, icmpv6msg, , idev, field +256)
+       _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256)
 #define ICMP6MSGOUT_INC_STATS_BH(net, idev, field)     \
-       _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field +256)
+       _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256)
 #define ICMP6MSGIN_INC_STATS_BH(net, idev, field)      \
-       _DEVINCATOMIC(net, icmpv6msg, _BH, idev, field)
+       _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field)
 
 struct ip6_ra_chain {
        struct ip6_ra_chain     *next;
index 72eddd1b410b9c8418216c17d74910585fdec975..0756049ae76d69c2a8cb9e2342deb868cefeaf94 100644 (file)
@@ -166,6 +166,7 @@ struct ieee80211_low_level_stats {
  *     that it is only ever disabled for station mode.
  * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
  * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
+ * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -184,6 +185,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_QOS                 = 1<<13,
        BSS_CHANGED_IDLE                = 1<<14,
        BSS_CHANGED_SSID                = 1<<15,
+       BSS_CHANGED_AP_PROBE_RESP       = 1<<16,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -518,7 +520,7 @@ struct ieee80211_tx_rate {
  * @flags: transmit info flags, defined above
  * @band: the band to transmit on (use for checking for races)
  * @antenna_sel_tx: antenna to use, 0 for automatic diversity
- * @pad: padding, ignore
+ * @ack_frame_id: internal frame ID for TX status, used internally
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
@@ -535,8 +537,7 @@ struct ieee80211_tx_info {
 
        u8 antenna_sel_tx;
 
-       /* 2 byte hole */
-       u8 pad[2];
+       u16 ack_frame_id;
 
        union {
                struct {
@@ -901,6 +902,10 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
  * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a
  *     CCMP key if it requires CCMP encryption of management frames (MFP) to
  *     be done in software.
+ * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
+ *     for a CCMP key if space should be prepared for the IV, but the IV
+ *     itself should not be generated. Do not set together with
+ *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
  */
 enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_WMM_STA      = 1<<0,
@@ -908,6 +913,7 @@ enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
        IEEE80211_KEY_FLAG_PAIRWISE     = 1<<3,
        IEEE80211_KEY_FLAG_SW_MGMT      = 1<<4,
+       IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5,
 };
 
 /**
@@ -1303,6 +1309,16 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
        return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
 }
 
+/**
+ * ieee80211_free_txskb - free TX skb
+ * @hw: the hardware
+ * @skb: the skb
+ *
+ * Free a transmit skb. Use this funtion when some failure
+ * to transmit happened and thus status cannot be reported.
+ */
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 /**
  * DOC: Hardware crypto acceleration
  *
@@ -2660,6 +2676,19 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        return ieee80211_beacon_get_tim(hw, vif, NULL, NULL);
 }
 
+/**
+ * ieee80211_proberesp_get - retrieve a Probe Response template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Creates a Probe Response template which can, for example, be uploaded to
+ * hardware. The destination address should be set by the caller.
+ *
+ * Can only be called in AP mode.
+ */
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif);
+
 /**
  * ieee80211_pspoll_get - retrieve a PS Poll template
  * @hw: pointer obtained from ieee80211_alloc_hw().
index 2720884287c3e72e34786a58522d0ee020957c87..7ae5acff96e9b42456e53cea5f86a98d9864dfd9 100644 (file)
@@ -59,7 +59,7 @@ struct neigh_parms {
        int     reachable_time;
        int     delay_probe_time;
 
-       int     queue_len;
+       int     queue_len_bytes;
        int     ucast_probes;
        int     app_probes;
        int     mcast_probes;
@@ -99,6 +99,7 @@ struct neighbour {
        rwlock_t                lock;
        atomic_t                refcnt;
        struct sk_buff_head     arp_queue;
+       unsigned int            arp_queue_len_bytes;
        struct timer_list       timer;
        unsigned long           used;
        atomic_t                probes;
index 0b44112e2366e535a8d6ab7a8fcc726f4aad8de6..30f6728ee98cbc251ae598f00175df5e1fd5bdce 100644 (file)
@@ -10,7 +10,7 @@ struct netns_mib {
        DEFINE_SNMP_STAT(struct udp_mib, udp_statistics);
        DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics);
        DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics);
-       DEFINE_SNMP_STAT(struct icmpmsg_mib, icmpmsg_statistics);
+       DEFINE_SNMP_STAT_ATOMIC(struct icmpmsg_mib, icmpmsg_statistics);
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
        struct proc_dir_entry *proc_net_devsnmp6;
@@ -18,7 +18,7 @@ struct netns_mib {
        DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6);
        DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
        DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
-       DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics);
+       DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib, icmpv6msg_statistics);
 #endif
 #ifdef CONFIG_XFRM_STATISTICS
        DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics);
index 39b85bc0804fbf7dd33d3c612b8a7d0e4a14ca73..cdbe671393432e92015920e9827c9614ace17666 100644 (file)
 /* NCI Status Codes */
 #define        NCI_STATUS_OK                                           0x00
 #define        NCI_STATUS_REJECTED                                     0x01
-#define        NCI_STATUS_MESSAGE_CORRUPTED                            0x02
-#define        NCI_STATUS_BUFFER_FULL                                  0x03
-#define        NCI_STATUS_FAILED                                       0x04
-#define        NCI_STATUS_NOT_INITIALIZED                              0x05
-#define        NCI_STATUS_SYNTAX_ERROR                                 0x06
-#define        NCI_STATUS_SEMANTIC_ERROR                               0x07
-#define        NCI_STATUS_UNKNOWN_GID                                  0x08
-#define        NCI_STATUS_UNKNOWN_OID                                  0x09
-#define        NCI_STATUS_INVALID_PARAM                                0x0a
-#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0b
+#define        NCI_STATUS_RF_FRAME_CORRUPTED                           0x02
+#define        NCI_STATUS_FAILED                                       0x03
+#define        NCI_STATUS_NOT_INITIALIZED                              0x04
+#define        NCI_STATUS_SYNTAX_ERROR                                 0x05
+#define        NCI_STATUS_SEMANTIC_ERROR                               0x06
+#define        NCI_STATUS_UNKNOWN_GID                                  0x07
+#define        NCI_STATUS_UNKNOWN_OID                                  0x08
+#define        NCI_STATUS_INVALID_PARAM                                0x09
+#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0a
 /* Discovery Specific Status Codes */
 #define        NCI_STATUS_DISCOVERY_ALREADY_STARTED                    0xa0
 #define        NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED           0xa1
+#define        NCI_STATUS_DISCOVERY_TEAR_DOWN                          0xa2
 /* RF Interface Specific Status Codes */
 #define        NCI_STATUS_RF_TRANSMISSION_ERROR                        0xb0
 #define        NCI_STATUS_RF_PROTOCOL_ERROR                            0xb1
 #define        NCI_STATUS_RF_TIMEOUT_ERROR                             0xb2
-#define        NCI_STATUS_RF_LINK_LOSS_ERROR                           0xb3
 /* NFCEE Interface Specific Status Codes */
 #define        NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED          0xc0
 #define        NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED            0xc1
 #define NCI_NFC_A_ACTIVE_LISTEN_MODE                           0x83
 #define NCI_NFC_F_ACTIVE_LISTEN_MODE                           0x85
 
+/* NCI RF Technologies */
+#define NCI_NFC_RF_TECHNOLOGY_A                                        0x00
+#define NCI_NFC_RF_TECHNOLOGY_B                                        0x01
+#define NCI_NFC_RF_TECHNOLOGY_F                                        0x02
+#define NCI_NFC_RF_TECHNOLOGY_15693                            0x03
+
+/* NCI Bit Rates */
+#define NCI_NFC_BIT_RATE_106                                   0x00
+#define NCI_NFC_BIT_RATE_212                                   0x01
+#define NCI_NFC_BIT_RATE_424                                   0x02
+#define NCI_NFC_BIT_RATE_848                                   0x03
+#define NCI_NFC_BIT_RATE_1696                                  0x04
+#define NCI_NFC_BIT_RATE_3392                                  0x05
+#define NCI_NFC_BIT_RATE_6784                                  0x06
+
 /* NCI RF Protocols */
 #define NCI_RF_PROTOCOL_UNKNOWN                                        0x00
 #define NCI_RF_PROTOCOL_T1T                                    0x01
 #define NCI_RF_PROTOCOL_NFC_DEP                                        0x05
 
 /* NCI RF Interfaces */
-#define NCI_RF_INTERFACE_RFU                                   0x00
+#define NCI_RF_INTERFACE_NFCEE_DIRECT                          0x00
 #define        NCI_RF_INTERFACE_FRAME                                  0x01
 #define        NCI_RF_INTERFACE_ISO_DEP                                0x02
 #define        NCI_RF_INTERFACE_NFC_DEP                                0x03
 
+/* NCI Reset types */
+#define NCI_RESET_TYPE_KEEP_CONFIG                             0x00
+#define NCI_RESET_TYPE_RESET_CONFIG                            0x01
+
+/* NCI Static RF connection ID */
+#define NCI_STATIC_RF_CONN_ID                                  0x00
+
+/* NCI Data Flow Control */
+#define NCI_DATA_FLOW_CONTROL_NOT_USED                         0xff
+
 /* NCI RF_DISCOVER_MAP_CMD modes */
 #define NCI_DISC_MAP_MODE_POLL                                 0x01
 #define NCI_DISC_MAP_MODE_LISTEN                               0x02
 #define        NCI_DISCOVERY_TYPE_POLL_F_PASSIVE                       0x02
 #define        NCI_DISCOVERY_TYPE_POLL_A_ACTIVE                        0x03
 #define        NCI_DISCOVERY_TYPE_POLL_F_ACTIVE                        0x05
-#define        NCI_DISCOVERY_TYPE_WAKEUP_A_PASSIVE                     0x06
-#define        NCI_DISCOVERY_TYPE_WAKEUP_B_PASSIVE                     0x07
 #define        NCI_DISCOVERY_TYPE_WAKEUP_A_ACTIVE                      0x09
 #define        NCI_DISCOVERY_TYPE_LISTEN_A_PASSIVE                     0x80
 #define        NCI_DISCOVERY_TYPE_LISTEN_B_PASSIVE                     0x81
 #define        NCI_DEACTIVATE_TYPE_IDLE_MODE                           0x00
 #define        NCI_DEACTIVATE_TYPE_SLEEP_MODE                          0x01
 #define        NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE                       0x02
-#define        NCI_DEACTIVATE_TYPE_RF_LINK_LOSS                        0x03
-#define        NCI_DEACTIVATE_TYPE_DISCOVERY_ERROR                     0x04
+#define        NCI_DEACTIVATE_TYPE_DISCOVERY                           0x03
 
 /* Message Type (MT) */
 #define NCI_MT_DATA_PKT                                                0x00
@@ -169,18 +190,11 @@ struct nci_data_hdr {
 /* -----  NCI Commands ---- */
 /* ------------------------ */
 #define NCI_OP_CORE_RESET_CMD          nci_opcode_pack(NCI_GID_CORE, 0x00)
-
-#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
-
-#define NCI_OP_CORE_SET_CONFIG_CMD     nci_opcode_pack(NCI_GID_CORE, 0x02)
-
-#define NCI_OP_CORE_CONN_CREATE_CMD    nci_opcode_pack(NCI_GID_CORE, 0x04)
-struct nci_core_conn_create_cmd {
-       __u8    target_handle;
-       __u8    num_target_specific_params;
+struct nci_core_reset_cmd {
+       __u8    reset_type;
 } __packed;
 
-#define NCI_OP_CORE_CONN_CLOSE_CMD     nci_opcode_pack(NCI_GID_CORE, 0x06)
+#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
 
 #define NCI_OP_RF_DISCOVER_MAP_CMD     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
 struct disc_map_config {
@@ -218,6 +232,7 @@ struct nci_rf_deactivate_cmd {
 struct nci_core_reset_rsp {
        __u8    status;
        __u8    nci_ver;
+       __u8    config_status;
 } __packed;
 
 #define NCI_OP_CORE_INIT_RSP           nci_opcode_pack(NCI_GID_CORE, 0x01)
@@ -232,24 +247,14 @@ struct nci_core_init_rsp_1 {
 struct nci_core_init_rsp_2 {
        __u8    max_logical_connections;
        __le16  max_routing_table_size;
-       __u8    max_control_packet_payload_length;
-       __le16  rf_sending_buffer_size;
-       __le16  rf_receiving_buffer_size;
-       __le16  manufacturer_id;
-} __packed;
-
-#define NCI_OP_CORE_SET_CONFIG_RSP     nci_opcode_pack(NCI_GID_CORE, 0x02)
-
-#define NCI_OP_CORE_CONN_CREATE_RSP    nci_opcode_pack(NCI_GID_CORE, 0x04)
-struct nci_core_conn_create_rsp {
-       __u8    status;
-       __u8    max_pkt_payload_size;
+       __u8    max_ctrl_pkt_payload_len;
+       __le16  max_size_for_large_params;
+       __u8    max_data_pkt_payload_size;
        __u8    initial_num_credits;
-       __u8    conn_id;
+       __u8    manufact_id;
+       __le32  manufact_specific_info;
 } __packed;
 
-#define NCI_OP_CORE_CONN_CLOSE_RSP     nci_opcode_pack(NCI_GID_CORE, 0x06)
-
 #define NCI_OP_RF_DISCOVER_MAP_RSP     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
 
 #define NCI_OP_RF_DISCOVER_RSP         nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
@@ -270,12 +275,7 @@ struct nci_core_conn_credit_ntf {
        struct conn_credit_entry        conn_entries[NCI_MAX_NUM_CONN];
 } __packed;
 
-#define NCI_OP_RF_FIELD_INFO_NTF       nci_opcode_pack(NCI_GID_CORE, 0x08)
-struct nci_rf_field_info_ntf {
-       __u8    rf_field_status;
-} __packed;
-
-#define NCI_OP_RF_ACTIVATE_NTF         nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
+#define NCI_OP_RF_INTF_ACTIVATED_NTF   nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
 struct rf_tech_specific_params_nfca_poll {
        __u16   sens_res;
        __u8    nfcid1_len;     /* 0, 4, 7, or 10 Bytes */
@@ -289,17 +289,20 @@ struct activation_params_nfca_poll_iso_dep {
        __u8    rats_res[20];
 };
 
-struct nci_rf_activate_ntf {
-       __u8    target_handle;
+struct nci_rf_intf_activated_ntf {
+       __u8    rf_discovery_id;
+       __u8    rf_interface_type;
        __u8    rf_protocol;
-       __u8    rf_tech_and_mode;
+       __u8    activation_rf_tech_and_mode;
        __u8    rf_tech_specific_params_len;
 
        union {
                struct rf_tech_specific_params_nfca_poll nfca_poll;
        } rf_tech_specific_params;
 
-       __u8    rf_interface_type;
+       __u8    data_exch_rf_tech_and_mode;
+       __u8    data_exch_tx_bit_rate;
+       __u8    data_exch_rx_bit_rate;
        __u8    activation_params_len;
 
        union {
@@ -309,5 +312,9 @@ struct nci_rf_activate_ntf {
 } __packed;
 
 #define NCI_OP_RF_DEACTIVATE_NTF       nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+struct nci_rf_deactivate_ntf {
+       __u8    type;
+       __u8    reason;
+} __packed;
 
 #endif /* __NCI_H */
index b8b4bbd7e0fc2d6abfa70ae5d2be24b11471bb76..c92b69d7e0c2a821e77a0019b28bed558caa1a4a 100644 (file)
@@ -109,15 +109,12 @@ struct nci_dev {
                                [NCI_MAX_SUPPORTED_RF_INTERFACES];
        __u8                    max_logical_connections;
        __u16                   max_routing_table_size;
-       __u8                    max_control_packet_payload_length;
-       __u16                   rf_sending_buffer_size;
-       __u16                   rf_receiving_buffer_size;
-       __u16                   manufacturer_id;
-
-       /* received during NCI_OP_CORE_CONN_CREATE_RSP for static conn 0 */
-       __u8                    max_pkt_payload_size;
+       __u8                    max_ctrl_pkt_payload_len;
+       __u16                   max_size_for_large_params;
+       __u8                    max_data_pkt_payload_size;
        __u8                    initial_num_credits;
-       __u8                    conn_id;
+       __u8                    manufact_id;
+       __u32                   manufact_specific_info;
 
        /* stored during nci_data_exchange */
        data_exchange_cb_t      data_exchange_cb;
index 6f7eb800974af3fae4c12a7d054d8e61d9e2cf9f..e182e13d6391e0f6f76f9b5d96f7ebfc810c9add 100644 (file)
@@ -38,7 +38,7 @@ struct net_protocol {
        void                    (*err_handler)(struct sk_buff *skb, u32 info);
        int                     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff         *(*gso_segment)(struct sk_buff *skb,
-                                              u32 features);
+                                              netdev_features_t features);
        struct sk_buff        **(*gro_receive)(struct sk_buff **head,
                                               struct sk_buff *skb);
        int                     (*gro_complete)(struct sk_buff *skb);
@@ -57,7 +57,7 @@ struct inet6_protocol {
 
        int     (*gso_send_check)(struct sk_buff *skb);
        struct sk_buff *(*gso_segment)(struct sk_buff *skb,
-                                      u32 features);
+                                      netdev_features_t features);
        struct sk_buff **(*gro_receive)(struct sk_buff **head,
                                        struct sk_buff *skb);
        int     (*gro_complete)(struct sk_buff *skb);
index e90e7a9935ddc5c70c8e920487bc1196c2cc49e2..3382615bd7104156b7b7ef1dfe3765b5fe80a066 100644 (file)
@@ -1085,6 +1085,7 @@ void sctp_transport_burst_reset(struct sctp_transport *);
 unsigned long sctp_transport_timeout(struct sctp_transport *);
 void sctp_transport_reset(struct sctp_transport *);
 void sctp_transport_update_pmtu(struct sctp_transport *, u32);
+void sctp_transport_immediate_rtx(struct sctp_transport *);
 
 
 /* This is the structure we use to queue packets as they come into
index 8f0f9ac0307ffc3ead58ce031f62d8ec8b2d1f7e..2f65e1686fc85f3b678106725053123b7b7b4747 100644 (file)
@@ -67,7 +67,7 @@ struct icmp_mib {
 
 #define ICMPMSG_MIB_MAX        __ICMPMSG_MIB_MAX
 struct icmpmsg_mib {
-       unsigned long   mibs[ICMPMSG_MIB_MAX];
+       atomic_long_t   mibs[ICMPMSG_MIB_MAX];
 };
 
 /* ICMP6 (IPv6-ICMP) */
@@ -84,7 +84,7 @@ struct icmpv6_mib_device {
 #define ICMP6MSG_MIB_MAX  __ICMP6MSG_MIB_MAX
 /* per network ns counters */
 struct icmpv6msg_mib {
-       unsigned long   mibs[ICMP6MSG_MIB_MAX];
+       atomic_long_t   mibs[ICMP6MSG_MIB_MAX];
 };
 /* per device counters, (shared on all cpus) */
 struct icmpv6msg_mib_device {
index abb6e0f0c3c3e59b79f23fc72d2e9d8d389e3774..1c28f394d8ec7a65c68a27ec060cbcd0995d3549 100644 (file)
@@ -306,8 +306,8 @@ struct sock {
        kmemcheck_bitfield_end(flags);
        int                     sk_wmem_queued;
        gfp_t                   sk_allocation;
-       int                     sk_route_caps;
-       int                     sk_route_nocaps;
+       netdev_features_t       sk_route_caps;
+       netdev_features_t       sk_route_nocaps;
        int                     sk_gso_type;
        unsigned int            sk_gso_max_size;
        int                     sk_rcvlowat;
@@ -563,6 +563,7 @@ enum sock_flags {
        SOCK_FASYNC, /* fasync() active */
        SOCK_RXQ_OVFL,
        SOCK_ZEROCOPY, /* buffers from userspace */
+       SOCK_WIFI_STATUS, /* push wifi status to userspace */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1089,8 +1090,8 @@ extern struct sock                *sk_alloc(struct net *net, int family,
                                          struct proto *prot);
 extern void                    sk_free(struct sock *sk);
 extern void                    sk_release_kernel(struct sock *sk);
-extern struct sock             *sk_clone(const struct sock *sk,
-                                         const gfp_t priority);
+extern struct sock             *sk_clone_lock(const struct sock *sk,
+                                              const gfp_t priority);
 
 extern struct sk_buff          *sock_wmalloc(struct sock *sk,
                                              unsigned long size, int force,
@@ -1393,7 +1394,7 @@ static inline int sk_can_gso(const struct sock *sk)
 
 extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst);
 
-static inline void sk_nocaps_add(struct sock *sk, int flags)
+static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags)
 {
        sk->sk_route_nocaps |= flags;
        sk->sk_route_caps &= ~flags;
@@ -1714,6 +1715,8 @@ static inline int sock_intr_errno(long timeo)
 
 extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb);
+extern void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb);
 
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
@@ -1741,6 +1744,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
                __sock_recv_timestamp(msg, sk, skb);
        else
                sk->sk_stamp = kt;
+
+       if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid)
+               __sock_recv_wifi_status(msg, sk, skb);
 }
 
 extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
index bb18c4d69aba1da89488af60999f03341648ee61..113160b845888a6e849c8b34e7d5a1311728090d 100644 (file)
@@ -1430,7 +1430,8 @@ extern struct request_sock_ops tcp6_request_sock_ops;
 extern void tcp_v4_destroy_sock(struct sock *sk);
 
 extern int tcp_v4_gso_send_check(struct sk_buff *skb);
-extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
+                                      netdev_features_t features);
 extern struct sk_buff **tcp_gro_receive(struct sk_buff **head,
                                        struct sk_buff *skb);
 extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head,
index 3b285f402f480e76aa9b69136447df9f6d66bb65..f54a5156b24881eb4db0ef04f326fdfc74a16750 100644 (file)
@@ -258,5 +258,6 @@ extern void udp4_proc_exit(void);
 extern void udp_init(void);
 
 extern int udp4_ufo_send_check(struct sk_buff *skb);
-extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, u32 features);
+extern struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
+       netdev_features_t features);
 #endif /* _UDP_H */
index 993599e66e5a91bf4a5ff22565b4a7560651128c..8e75003d62f632c52b8c0ea56ca62bdc72e560f0 100644 (file)
@@ -777,6 +777,18 @@ char *uuid_string(char *buf, char *end, const u8 *addr,
        return string(buf, end, uuid, spec);
 }
 
+static
+char *netdev_feature_string(char *buf, char *end, const u8 *addr,
+                     struct printf_spec spec)
+{
+       spec.flags |= SPECIAL | SMALL | ZEROPAD;
+       if (spec.field_width == -1)
+               spec.field_width = 2 + 2 * sizeof(netdev_features_t);
+       spec.base = 16;
+
+       return number(buf, end, *(const netdev_features_t *)addr, spec);
+}
+
 int kptr_restrict __read_mostly;
 
 /*
@@ -824,6 +836,7 @@ int kptr_restrict __read_mostly;
  *       Do not use this feature without some mechanism to verify the
  *       correctness of the format string and va_list arguments.
  * - 'K' For a kernel pointer that should be hidden from unprivileged users
+ * - 'NF' For a netdev_features_t
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -896,6 +909,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                       has_capability_noaudit(current, CAP_SYSLOG))))
                        ptr = NULL;
                break;
+       case 'N':
+               switch (fmt[1]) {
+               case 'F':
+                       return netdev_feature_string(buf, end, ptr, spec);
+               }
+               break;
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {
index bc252862458385ef5d37367a643fcdf9ef5ad9af..2b5fcde1f6294d3b2b53c7515dcdc2c902d6398d 100644 (file)
@@ -591,18 +591,17 @@ static void vlan_dev_uninit(struct net_device *dev)
        }
 }
 
-static u32 vlan_dev_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
        u32 old_features = features;
 
-       features &= real_dev->features;
        features &= real_dev->vlan_features;
+       features |= NETIF_F_RXCSUM;
+       features &= real_dev->features;
 
        features |= old_features & NETIF_F_SOFT_FEATURES;
-
-       if (dev_ethtool_get_rx_csum(real_dev))
-               features |= NETIF_F_RXCSUM;
        features |= NETIF_F_LLTX;
 
        return features;
index 852394072fa151956cec3e819da113024fbb6971..32c41b8a803e476c300df56756dfc43d45b094d9 100644 (file)
@@ -329,7 +329,7 @@ static struct neigh_table clip_tbl = {
                .gc_staletime           = 60 * HZ,
                .reachable_time         = 30 * HZ,
                .delay_probe_time       = 5 * HZ,
-               .queue_len              = 3,
+               .queue_len_bytes        = 64 * 1024,
                .ucast_probes           = 3,
                .mcast_probes           = 3,
                .anycast_delay          = 1 * HZ,
index 91bcd3a961ec22c501451ef588fe86b171c55ae3..a6cd856046ab247cb29da2d9831077153da8a642 100644 (file)
@@ -65,15 +65,13 @@ static DECLARE_RWSEM(bnep_session_sem);
 static struct bnep_session *__bnep_get_session(u8 *dst)
 {
        struct bnep_session *s;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &bnep_session_list) {
-               s = list_entry(p, struct bnep_session, list);
+       list_for_each_entry(s, &bnep_session_list, list)
                if (!compare_ether_addr(dst, s->eh.h_source))
                        return s;
-       }
+
        return NULL;
 }
 
@@ -667,17 +665,14 @@ static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
 
 int bnep_get_connlist(struct bnep_connlist_req *req)
 {
-       struct list_head *p;
+       struct bnep_session *s;
        int err = 0, n = 0;
 
        down_read(&bnep_session_sem);
 
-       list_for_each(p, &bnep_session_list) {
-               struct bnep_session *s;
+       list_for_each_entry(s, &bnep_session_list, list) {
                struct bnep_conninfo ci;
 
-               s = list_entry(p, struct bnep_session, list);
-
                __bnep_copy_ci(&ci, s);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index 7d00ddf9e9dcb55ab74cf768db31a3e15af647ac..9e8940b24bbad73c67dd37fd23b0e787090cacd8 100644 (file)
@@ -53,15 +53,13 @@ static LIST_HEAD(cmtp_session_list);
 static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
 {
        struct cmtp_session *session;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &cmtp_session_list) {
-               session = list_entry(p, struct cmtp_session, list);
+       list_for_each_entry(session, &cmtp_session_list, list)
                if (!bacmp(bdaddr, &session->bdaddr))
                        return session;
-       }
+
        return NULL;
 }
 
@@ -431,19 +429,16 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
 
 int cmtp_get_connlist(struct cmtp_connlist_req *req)
 {
-       struct list_head *p;
+       struct cmtp_session *session;
        int err = 0, n = 0;
 
        BT_DBG("");
 
        down_read(&cmtp_session_sem);
 
-       list_for_each(p, &cmtp_session_list) {
-               struct cmtp_session *session;
+       list_for_each_entry(session, &cmtp_session_list, list) {
                struct cmtp_conninfo ci;
 
-               session = list_entry(p, struct cmtp_session, list);
-
                __cmtp_copy_session(session, &ci);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index e0af7237cd9245fedfc8886ec446f670ddc48500..de0b93e45980138235044550be69f960cd8cf9ab 100644 (file)
@@ -374,6 +374,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
        skb_queue_head_init(&conn->data_q);
 
+       hci_chan_hash_init(conn);
+
        setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
        setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
        setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
@@ -432,6 +434,8 @@ int hci_conn_del(struct hci_conn *conn)
 
        tasklet_disable(&hdev->tx_task);
 
+       hci_chan_hash_flush(conn);
+
        hci_conn_hash_del(hdev, conn);
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -453,16 +457,13 @@ int hci_conn_del(struct hci_conn *conn)
 struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 {
        int use_src = bacmp(src, BDADDR_ANY);
-       struct hci_dev *hdev = NULL;
-       struct list_head *p;
+       struct hci_dev *hdev = NULL, *d;
 
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
        read_lock_bh(&hci_dev_list_lock);
 
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
+       list_for_each_entry(d, &hci_dev_list, list) {
                if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
                        continue;
 
@@ -819,7 +820,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
 
                c->state = BT_CLOSED;
 
-               hci_proto_disconn_cfm(c, 0x16);
+               hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
                hci_conn_del(c);
        }
 }
@@ -855,10 +856,10 @@ EXPORT_SYMBOL(hci_conn_put_device);
 
 int hci_get_conn_list(void __user *arg)
 {
+       register struct hci_conn *c;
        struct hci_conn_list_req req, *cl;
        struct hci_conn_info *ci;
        struct hci_dev *hdev;
-       struct list_head *p;
        int n = 0, size, err;
 
        if (copy_from_user(&req, arg, sizeof(req)))
@@ -882,10 +883,7 @@ int hci_get_conn_list(void __user *arg)
        ci = cl->conn_info;
 
        hci_dev_lock_bh(hdev);
-       list_for_each(p, &hdev->conn_hash.list) {
-               register struct hci_conn *c;
-               c = list_entry(p, struct hci_conn, list);
-
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
                bacpy(&(ci + n)->bdaddr, &c->dst);
                (ci + n)->handle = c->handle;
                (ci + n)->type  = c->type;
@@ -956,3 +954,52 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
 
        return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
 }
+
+struct hci_chan *hci_chan_create(struct hci_conn *conn)
+{
+       struct hci_dev *hdev = conn->hdev;
+       struct hci_chan *chan;
+
+       BT_DBG("%s conn %p", hdev->name, conn);
+
+       chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
+       if (!chan)
+               return NULL;
+
+       chan->conn = conn;
+       skb_queue_head_init(&chan->data_q);
+
+       tasklet_disable(&hdev->tx_task);
+       hci_chan_hash_add(conn, chan);
+       tasklet_enable(&hdev->tx_task);
+
+       return chan;
+}
+
+int hci_chan_del(struct hci_chan *chan)
+{
+       struct hci_conn *conn = chan->conn;
+       struct hci_dev *hdev = conn->hdev;
+
+       BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
+
+       tasklet_disable(&hdev->tx_task);
+       hci_chan_hash_del(conn, chan);
+       tasklet_enable(&hdev->tx_task);
+
+       skb_queue_purge(&chan->data_q);
+       kfree(chan);
+
+       return 0;
+}
+
+void hci_chan_hash_flush(struct hci_conn *conn)
+{
+       struct hci_chan_hash *h = &conn->chan_hash;
+       struct hci_chan *chan, *tmp;
+
+       BT_DBG("conn %p", conn);
+
+       list_for_each_entry_safe(chan, tmp, &h->list, list)
+               hci_chan_del(chan);
+}
index be84ae33ae36bec88f4f67502780b4fe5333e270..fb3feeb185d7098359bdd71b0156fa8a67d0157f 100644 (file)
@@ -319,8 +319,7 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
 {
-       struct hci_dev *hdev = NULL;
-       struct list_head *p;
+       struct hci_dev *hdev = NULL, *d;
 
        BT_DBG("%d", index);
 
@@ -328,8 +327,7 @@ struct hci_dev *hci_dev_get(int index)
                return NULL;
 
        read_lock(&hci_dev_list_lock);
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
+       list_for_each_entry(d, &hci_dev_list, list) {
                if (d->id == index) {
                        hdev = hci_dev_hold(d);
                        break;
@@ -551,8 +549,11 @@ int hci_dev_open(__u16 dev)
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
-               if (!test_bit(HCI_SETUP, &hdev->flags))
-                       mgmt_powered(hdev->id, 1);
+               if (!test_bit(HCI_SETUP, &hdev->flags)) {
+                       hci_dev_lock_bh(hdev);
+                       mgmt_powered(hdev, 1);
+                       hci_dev_unlock_bh(hdev);
+               }
        } else {
                /* Init failed, cleanup */
                tasklet_kill(&hdev->rx_task);
@@ -597,6 +598,14 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        tasklet_kill(&hdev->rx_task);
        tasklet_kill(&hdev->tx_task);
 
+       if (hdev->discov_timeout > 0) {
+               cancel_delayed_work(&hdev->discov_off);
+               hdev->discov_timeout = 0;
+       }
+
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work(&hdev->power_off);
+
        hci_dev_lock_bh(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -636,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
         * and no tasks are scheduled. */
        hdev->close(hdev);
 
-       mgmt_powered(hdev->id, 0);
+       hci_dev_lock_bh(hdev);
+       mgmt_powered(hdev, 0);
+       hci_dev_unlock_bh(hdev);
 
        /* Clear flags */
        hdev->flags = 0;
@@ -794,9 +805,9 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
 int hci_get_dev_list(void __user *arg)
 {
+       struct hci_dev *hdev;
        struct hci_dev_list_req *dl;
        struct hci_dev_req *dr;
-       struct list_head *p;
        int n = 0, size, err;
        __u16 dev_num;
 
@@ -815,12 +826,9 @@ int hci_get_dev_list(void __user *arg)
        dr = dl->dev_req;
 
        read_lock_bh(&hci_dev_list_lock);
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *hdev;
-
-               hdev = list_entry(p, struct hci_dev, list);
-
-               hci_del_off_timer(hdev);
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+                       cancel_delayed_work(&hdev->power_off);
 
                if (!test_bit(HCI_MGMT, &hdev->flags))
                        set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -855,7 +863,8 @@ int hci_get_dev_info(void __user *arg)
        if (!hdev)
                return -ENODEV;
 
-       hci_del_off_timer(hdev);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work_sync(&hdev->power_off);
 
        if (!test_bit(HCI_MGMT, &hdev->flags))
                set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -912,6 +921,7 @@ struct hci_dev *hci_alloc_dev(void)
        if (!hdev)
                return NULL;
 
+       hci_init_sysfs(hdev);
        skb_queue_head_init(&hdev->driver_init);
 
        return hdev;
@@ -938,39 +948,41 @@ static void hci_power_on(struct work_struct *work)
                return;
 
        if (test_bit(HCI_AUTO_OFF, &hdev->flags))
-               mod_timer(&hdev->off_timer,
-                               jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+               queue_delayed_work(hdev->workqueue, &hdev->power_off,
+                                       msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
-               mgmt_index_added(hdev->id);
+               mgmt_index_added(hdev);
 }
 
 static void hci_power_off(struct work_struct *work)
 {
-       struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                                       power_off.work);
 
        BT_DBG("%s", hdev->name);
 
+       clear_bit(HCI_AUTO_OFF, &hdev->flags);
+
        hci_dev_close(hdev->id);
 }
 
-static void hci_auto_off(unsigned long data)
+static void hci_discov_off(struct work_struct *work)
 {
-       struct hci_dev *hdev = (struct hci_dev *) data;
+       struct hci_dev *hdev;
+       u8 scan = SCAN_PAGE;
+
+       hdev = container_of(work, struct hci_dev, discov_off.work);
 
        BT_DBG("%s", hdev->name);
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
+       hci_dev_lock_bh(hdev);
 
-       queue_work(hdev->workqueue, &hdev->power_off);
-}
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
 
-void hci_del_off_timer(struct hci_dev *hdev)
-{
-       BT_DBG("%s", hdev->name);
+       hdev->discov_timeout = 0;
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
-       del_timer(&hdev->off_timer);
+       hci_dev_unlock_bh(hdev);
 }
 
 int hci_uuids_clear(struct hci_dev *hdev)
@@ -1007,16 +1019,11 @@ int hci_link_keys_clear(struct hci_dev *hdev)
 
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       struct list_head *p;
-
-       list_for_each(p, &hdev->link_keys) {
-               struct link_key *k;
-
-               k = list_entry(p, struct link_key, list);
+       struct link_key *k;
 
+       list_for_each_entry(k, &hdev->link_keys, list)
                if (bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
-       }
 
        return NULL;
 }
@@ -1138,7 +1145,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 
        persistent = hci_persistent_key(hdev, conn, type, old_key_type);
 
-       mgmt_new_key(hdev->id, key, persistent);
+       mgmt_new_link_key(hdev, key, persistent);
 
        if (!persistent) {
                list_del(&key->list);
@@ -1181,7 +1188,7 @@ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
        memcpy(id->rand, rand, sizeof(id->rand));
 
        if (new_key)
-               mgmt_new_key(hdev->id, key, old_key_type);
+               mgmt_new_link_key(hdev, key, old_key_type);
 
        return 0;
 }
@@ -1279,16 +1286,11 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
                                                bdaddr_t *bdaddr)
 {
-       struct list_head *p;
-
-       list_for_each(p, &hdev->blacklist) {
-               struct bdaddr_list *b;
-
-               b = list_entry(p, struct bdaddr_list, list);
+       struct bdaddr_list *b;
 
+       list_for_each_entry(b, &hdev->blacklist, list)
                if (bacmp(bdaddr, &b->bdaddr) == 0)
                        return b;
-       }
 
        return NULL;
 }
@@ -1327,7 +1329,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
        list_add(&entry->list, &hdev->blacklist);
 
-       return mgmt_device_blocked(hdev->id, bdaddr);
+       return mgmt_device_blocked(hdev, bdaddr);
 }
 
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
@@ -1346,7 +1348,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
        list_del(&entry->list);
        kfree(entry);
 
-       return mgmt_device_unblocked(hdev->id, bdaddr);
+       return mgmt_device_unblocked(hdev, bdaddr);
 }
 
 static void hci_clear_adv_cache(unsigned long arg)
@@ -1425,7 +1427,7 @@ int hci_add_adv_entry(struct hci_dev *hdev,
 int hci_register_dev(struct hci_dev *hdev)
 {
        struct list_head *head = &hci_dev_list, *p;
-       int i, id = 0;
+       int i, id, error;
 
        BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
                                                hdev->bus, hdev->owner);
@@ -1433,6 +1435,11 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
 
+       /* Do not allow HCI_AMP devices to register at index 0,
+        * so the index can be used as the AMP controller ID.
+        */
+       id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
+
        write_lock_bh(&hci_dev_list_lock);
 
        /* Find first available device id */
@@ -1479,6 +1486,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hci_conn_hash_init(hdev);
 
+       INIT_LIST_HEAD(&hdev->mgmt_pending);
+
        INIT_LIST_HEAD(&hdev->blacklist);
 
        INIT_LIST_HEAD(&hdev->uuids);
@@ -1492,8 +1501,9 @@ int hci_register_dev(struct hci_dev *hdev)
                                                (unsigned long) hdev);
 
        INIT_WORK(&hdev->power_on, hci_power_on);
-       INIT_WORK(&hdev->power_off, hci_power_off);
-       setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
+       INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
+
+       INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
 
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
@@ -1502,10 +1512,14 @@ int hci_register_dev(struct hci_dev *hdev)
        write_unlock_bh(&hci_dev_list_lock);
 
        hdev->workqueue = create_singlethread_workqueue(hdev->name);
-       if (!hdev->workqueue)
-               goto nomem;
+       if (!hdev->workqueue) {
+               error = -ENOMEM;
+               goto err;
+       }
 
-       hci_register_sysfs(hdev);
+       error = hci_add_sysfs(hdev);
+       if (error < 0)
+               goto err_wqueue;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
@@ -1524,17 +1538,19 @@ int hci_register_dev(struct hci_dev *hdev)
 
        return id;
 
-nomem:
+err_wqueue:
+       destroy_workqueue(hdev->workqueue);
+err:
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock_bh(&hci_dev_list_lock);
 
-       return -ENOMEM;
+       return error;
 }
 EXPORT_SYMBOL(hci_register_dev);
 
 /* Unregister HCI device */
-int hci_unregister_dev(struct hci_dev *hdev)
+void hci_unregister_dev(struct hci_dev *hdev)
 {
        int i;
 
@@ -1550,8 +1566,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
                kfree_skb(hdev->reassembly[i]);
 
        if (!test_bit(HCI_INIT, &hdev->flags) &&
-                                       !test_bit(HCI_SETUP, &hdev->flags))
-               mgmt_index_removed(hdev->id);
+                                       !test_bit(HCI_SETUP, &hdev->flags)) {
+               hci_dev_lock_bh(hdev);
+               mgmt_index_removed(hdev);
+               hci_dev_unlock_bh(hdev);
+       }
+
+       /* mgmt_index_removed should take care of emptying the
+        * pending list */
+       BUG_ON(!list_empty(&hdev->mgmt_pending));
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
@@ -1560,9 +1583,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
                rfkill_destroy(hdev->rfkill);
        }
 
-       hci_unregister_sysfs(hdev);
+       hci_del_sysfs(hdev);
 
-       hci_del_off_timer(hdev);
        del_timer(&hdev->adv_timer);
 
        destroy_workqueue(hdev->workqueue);
@@ -1576,8 +1598,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
        hci_dev_unlock_bh(hdev);
 
        __hci_dev_put(hdev);
-
-       return 0;
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1948,23 +1968,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
+                               struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
 
-       BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-
-       skb->dev = (void *) hdev;
-       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-       hci_add_acl_hdr(skb, conn->handle, flags);
-
        list = skb_shinfo(skb)->frag_list;
        if (!list) {
                /* Non fragmented */
                BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
 
-               skb_queue_tail(&conn->data_q, skb);
+               skb_queue_tail(queue, skb);
        } else {
                /* Fragmented */
                BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1972,9 +1987,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                skb_shinfo(skb)->frag_list = NULL;
 
                /* Queue all fragments atomically */
-               spin_lock_bh(&conn->data_q.lock);
+               spin_lock_bh(&queue->lock);
 
-               __skb_queue_tail(&conn->data_q, skb);
+               __skb_queue_tail(queue, skb);
 
                flags &= ~ACL_START;
                flags |= ACL_CONT;
@@ -1987,11 +2002,25 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
 
-                       __skb_queue_tail(&conn->data_q, skb);
+                       __skb_queue_tail(queue, skb);
                } while (list);
 
-               spin_unlock_bh(&conn->data_q.lock);
+               spin_unlock_bh(&queue->lock);
        }
+}
+
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
+{
+       struct hci_conn *conn = chan->conn;
+       struct hci_dev *hdev = conn->hdev;
+
+       BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
+
+       skb->dev = (void *) hdev;
+       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+       hci_add_acl_hdr(skb, conn->handle, flags);
+
+       hci_queue_acl(conn, &chan->data_q, skb, flags);
 
        tasklet_schedule(&hdev->tx_task);
 }
@@ -2026,16 +2055,12 @@ EXPORT_SYMBOL(hci_send_sco);
 static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct hci_conn *conn = NULL;
+       struct hci_conn *conn = NULL, *c;
        int num = 0, min = ~0;
-       struct list_head *p;
 
        /* We don't have to lock device here. Connections are always
         * added and removed with TX task disabled. */
-       list_for_each(p, &h->list) {
-               struct hci_conn *c;
-               c = list_entry(p, struct hci_conn, list);
-
+       list_for_each_entry(c, &h->list, list) {
                if (c->type != type || skb_queue_empty(&c->data_q))
                        continue;
 
@@ -2084,14 +2109,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct list_head *p;
-       struct hci_conn  *c;
+       struct hci_conn *c;
 
        BT_ERR("%s link tx timeout", hdev->name);
 
        /* Kill stalled connections */
-       list_for_each(p, &h->list) {
-               c = list_entry(p, struct hci_conn, list);
+       list_for_each_entry(c, &h->list, list) {
                if (c->type == type && c->sent) {
                        BT_ERR("%s killing stalled connection %s",
                                hdev->name, batostr(&c->dst));
@@ -2100,11 +2123,137 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        }
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+                                               int *quote)
 {
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_chan *chan = NULL;
+       int num = 0, min = ~0, cur_prio = 0;
        struct hci_conn *conn;
+       int cnt, q, conn_num = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       list_for_each_entry(conn, &h->list, list) {
+               struct hci_chan_hash *ch;
+               struct hci_chan *tmp;
+
+               if (conn->type != type)
+                       continue;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       continue;
+
+               conn_num++;
+
+               ch = &conn->chan_hash;
+
+               list_for_each_entry(tmp, &ch->list, list) {
+                       struct sk_buff *skb;
+
+                       if (skb_queue_empty(&tmp->data_q))
+                               continue;
+
+                       skb = skb_peek(&tmp->data_q);
+                       if (skb->priority < cur_prio)
+                               continue;
+
+                       if (skb->priority > cur_prio) {
+                               num = 0;
+                               min = ~0;
+                               cur_prio = skb->priority;
+                       }
+
+                       num++;
+
+                       if (conn->sent < min) {
+                               min  = conn->sent;
+                               chan = tmp;
+                       }
+               }
+
+               if (hci_conn_num(hdev, type) == conn_num)
+                       break;
+       }
+
+       if (!chan)
+               return NULL;
+
+       switch (chan->conn->type) {
+       case ACL_LINK:
+               cnt = hdev->acl_cnt;
+               break;
+       case SCO_LINK:
+       case ESCO_LINK:
+               cnt = hdev->sco_cnt;
+               break;
+       case LE_LINK:
+               cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+               break;
+       default:
+               cnt = 0;
+               BT_ERR("Unknown link type");
+       }
+
+       q = cnt / num;
+       *quote = q ? q : 1;
+       BT_DBG("chan %p quote %d", chan, *quote);
+       return chan;
+}
+
+static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_conn *conn;
+       int num = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       list_for_each_entry(conn, &h->list, list) {
+               struct hci_chan_hash *ch;
+               struct hci_chan *chan;
+
+               if (conn->type != type)
+                       continue;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       continue;
+
+               num++;
+
+               ch = &conn->chan_hash;
+               list_for_each_entry(chan, &ch->list, list) {
+                       struct sk_buff *skb;
+
+                       if (chan->sent) {
+                               chan->sent = 0;
+                               continue;
+                       }
+
+                       if (skb_queue_empty(&chan->data_q))
+                               continue;
+
+                       skb = skb_peek(&chan->data_q);
+                       if (skb->priority >= HCI_PRIO_MAX - 1)
+                               continue;
+
+                       skb->priority = HCI_PRIO_MAX - 1;
+
+                       BT_DBG("chan %p skb %p promoted to %d", chan, skb,
+                                                               skb->priority);
+               }
+
+               if (hci_conn_num(hdev, type) == num)
+                       break;
+       }
+}
+
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+       struct hci_chan *chan;
        struct sk_buff *skb;
        int quote;
+       unsigned int cnt;
 
        BT_DBG("%s", hdev->name);
 
@@ -2118,19 +2267,35 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
                        hci_link_tx_to(hdev, ACL_LINK);
        }
 
-       while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
+       cnt = hdev->acl_cnt;
+
+       while (hdev->acl_cnt &&
+                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote-- && (skb = skb_peek(&chan->data_q))) {
+                       BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+                                       skb->len, skb->priority);
 
-                       hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
+                       /* Stop if priority has changed */
+                       if (skb->priority < priority)
+                               break;
+
+                       skb = skb_dequeue(&chan->data_q);
+
+                       hci_conn_enter_active_mode(chan->conn,
+                                               bt_cb(skb)->force_active);
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
 
                        hdev->acl_cnt--;
-                       conn->sent++;
+                       chan->sent++;
+                       chan->conn->sent++;
                }
        }
+
+       if (cnt != hdev->acl_cnt)
+               hci_prio_recalculate(hdev, ACL_LINK);
 }
 
 /* Schedule SCO */
@@ -2182,9 +2347,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 
 static inline void hci_sched_le(struct hci_dev *hdev)
 {
-       struct hci_conn *conn;
+       struct hci_chan *chan;
        struct sk_buff *skb;
-       int quote, cnt;
+       int quote, cnt, tmp;
 
        BT_DBG("%s", hdev->name);
 
@@ -2200,21 +2365,35 @@ static inline void hci_sched_le(struct hci_dev *hdev)
        }
 
        cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
-       while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
+       tmp = cnt;
+       while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote-- && (skb = skb_peek(&chan->data_q))) {
+                       BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+                                       skb->len, skb->priority);
+
+                       /* Stop if priority has changed */
+                       if (skb->priority < priority)
+                               break;
+
+                       skb = skb_dequeue(&chan->data_q);
 
                        hci_send_frame(skb);
                        hdev->le_last_tx = jiffies;
 
                        cnt--;
-                       conn->sent++;
+                       chan->sent++;
+                       chan->conn->sent++;
                }
        }
+
        if (hdev->le_pkts)
                hdev->le_cnt = cnt;
        else
                hdev->acl_cnt = cnt;
+
+       if (cnt != tmp)
+               hci_prio_recalculate(hdev, LE_LINK);
 }
 
 static void hci_tx_task(unsigned long arg)
@@ -2407,3 +2586,31 @@ static void hci_cmd_task(unsigned long arg)
                }
        }
 }
+
+int hci_do_inquiry(struct hci_dev *hdev, u8 length)
+{
+       /* General inquiry access code (GIAC) */
+       u8 lap[3] = { 0x33, 0x8b, 0x9e };
+       struct hci_cp_inquiry cp;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_bit(HCI_INQUIRY, &hdev->flags))
+               return -EINPROGRESS;
+
+       memset(&cp, 0, sizeof(cp));
+       memcpy(&cp.lap, lap, sizeof(cp.lap));
+       cp.length  = length;
+
+       return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+}
+
+int hci_cancel_inquiry(struct hci_dev *hdev)
+{
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_INQUIRY, &hdev->flags))
+               return -EPERM;
+
+       return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+}
index d7d96b6b1f0d63b338e5ed58fb125fbc6290aff5..a89cf1f24e47697d14f009900ac8a3ee8fe0e549 100644 (file)
@@ -58,9 +58,11 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                       test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
+       clear_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 0);
+       hci_dev_unlock(hdev);
 
        hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
@@ -76,10 +78,6 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
-
        hci_conn_check_pending(hdev);
 }
 
@@ -205,13 +203,15 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_set_local_name_complete(hdev->id, sent, status);
+               mgmt_set_local_name_complete(hdev, sent, status);
 
-       if (status)
-               return;
+       if (status == 0)
+               memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
-       memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -274,7 +274,8 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status = *((__u8 *) skb->data);
+       __u8 param, status = *((__u8 *) skb->data);
+       int old_pscan, old_iscan;
        void *sent;
 
        BT_DBG("%s status 0x%x", hdev->name, status);
@@ -283,28 +284,40 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
-       if (!status) {
-               __u8 param = *((__u8 *) sent);
-               int old_pscan, old_iscan;
-
-               old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
-               old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+       param = *((__u8 *) sent);
 
-               if (param & SCAN_INQUIRY) {
-                       set_bit(HCI_ISCAN, &hdev->flags);
-                       if (!old_iscan)
-                               mgmt_discoverable(hdev->id, 1);
-               } else if (old_iscan)
-                       mgmt_discoverable(hdev->id, 0);
+       hci_dev_lock(hdev);
 
-               if (param & SCAN_PAGE) {
-                       set_bit(HCI_PSCAN, &hdev->flags);
-                       if (!old_pscan)
-                               mgmt_connectable(hdev->id, 1);
-               } else if (old_pscan)
-                       mgmt_connectable(hdev->id, 0);
+       if (status != 0) {
+               mgmt_write_scan_failed(hdev, param, status);
+               hdev->discov_timeout = 0;
+               goto done;
        }
 
+       old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
+       old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+
+       if (param & SCAN_INQUIRY) {
+               set_bit(HCI_ISCAN, &hdev->flags);
+               if (!old_iscan)
+                       mgmt_discoverable(hdev, 1);
+               if (hdev->discov_timeout > 0) {
+                       int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
+                       queue_delayed_work(hdev->workqueue, &hdev->discov_off,
+                                                                       to);
+               }
+       } else if (old_iscan)
+               mgmt_discoverable(hdev, 0);
+
+       if (param & SCAN_PAGE) {
+               set_bit(HCI_PSCAN, &hdev->flags);
+               if (!old_pscan)
+                       mgmt_connectable(hdev, 1);
+       } else if (old_pscan)
+               mgmt_connectable(hdev, 0);
+
+done:
+       hci_dev_unlock(hdev);
        hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
 }
 
@@ -748,6 +761,30 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
 }
 
+static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
+               struct sk_buff *skb)
+{
+       struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->amp_status = rp->amp_status;
+       hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
+       hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
+       hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
+       hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
+       hdev->amp_type = rp->amp_type;
+       hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
+       hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
+       hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
+       hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
+
+       hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+}
+
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
                                                        struct sk_buff *skb)
 {
@@ -804,19 +841,24 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
+               mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
        if (rp->status != 0)
-               return;
+               goto unlock;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
        if (!cp)
-               return;
+               goto unlock;
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
        if (conn)
                conn->pin_length = cp->pin_len;
+
+unlock:
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -825,10 +867,15 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
+
 static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
                                       struct sk_buff *skb)
 {
@@ -855,9 +902,13 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
@@ -867,9 +918,13 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
@@ -879,8 +934,10 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-       mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+       hci_dev_lock(hdev);
+       mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
                                                rp->randomizer, rp->status);
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -955,12 +1012,18 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
        if (status) {
                hci_req_complete(hdev, HCI_OP_INQUIRY, status);
                hci_conn_check_pending(hdev);
+               hci_dev_lock(hdev);
+               if (test_bit(HCI_MGMT, &hdev->flags))
+                       mgmt_inquiry_failed(hdev, status);
+               hci_dev_unlock(hdev);
                return;
        }
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 1);
+       set_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 1);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1339,13 +1402,16 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        BT_DBG("%s status %d", hdev->name, status);
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
-
        hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
        hci_conn_check_pending(hdev);
+
+       if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+               return;
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 0);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1361,12 +1427,6 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 
        hci_dev_lock(hdev);
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
@@ -1377,8 +1437,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                data.rssi               = 0x00;
                data.ssp_mode           = 0x00;
                hci_inquiry_cache_update(hdev, &data);
-               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
-                                                                       NULL);
+               mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
+                                               info->dev_class, 0, NULL);
        }
 
        hci_dev_unlock(hdev);
@@ -1412,7 +1472,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
                        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-                       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
+                       mgmt_connected(hdev, &ev->bdaddr, conn->type);
                } else
                        conn->state = BT_CONNECTED;
 
@@ -1444,7 +1504,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
-                       mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
+                       mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
+                                                               ev->status);
        }
 
        if (conn->type == ACL_LINK)
@@ -1531,7 +1592,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                struct hci_cp_reject_conn_req cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x0f;
+               cp.reason = HCI_ERROR_REJ_BAD_ADDR;
                hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
        }
 }
@@ -1544,7 +1605,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        BT_DBG("%s status %d", hdev->name, ev->status);
 
        if (ev->status) {
-               mgmt_disconnect_failed(hdev->id);
+               hci_dev_lock(hdev);
+               mgmt_disconnect_failed(hdev);
+               hci_dev_unlock(hdev);
                return;
        }
 
@@ -1557,7 +1620,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        conn->state = BT_CLOSED;
 
        if (conn->type == ACL_LINK || conn->type == LE_LINK)
-               mgmt_disconnected(hdev->id, &conn->dst);
+               mgmt_disconnected(hdev, &conn->dst, conn->type);
 
        hci_proto_disconn_cfm(conn, ev->reason);
        hci_conn_del(conn);
@@ -1588,7 +1651,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->sec_level = conn->pending_sec_level;
                }
        } else {
-               mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, ev->status);
        }
 
        clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
@@ -1643,7 +1706,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
        hci_dev_lock(hdev);
 
        if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
+               mgmt_remote_name(hdev, &ev->bdaddr, ev->name);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (!conn)
@@ -1898,6 +1961,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_write_ca_timeout(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_AMP_INFO:
+               hci_cc_read_local_amp_info(hdev, skb);
+               break;
+
        case HCI_OP_DELETE_STORED_LINK_KEY:
                hci_cc_delete_stored_link_key(hdev, skb);
                break;
@@ -2029,7 +2096,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        case HCI_OP_DISCONNECT:
                if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev->id);
+                       mgmt_disconnect_failed(hdev);
                break;
 
        case HCI_OP_LE_CREATE_CONN:
@@ -2194,7 +2261,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
                else
                        secure = 0;
 
-               mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
+               mgmt_pin_code_request(hdev, &ev->bdaddr, secure);
        }
 
 unlock:
@@ -2363,12 +2430,6 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
        hci_dev_lock(hdev);
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
                struct inquiry_info_with_rssi_and_pscan_mode *info;
                info = (void *) (skb->data + 1);
@@ -2383,7 +2444,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        hci_inquiry_cache_update(hdev, &data);
-                       mgmt_device_found(hdev->id, &info->bdaddr,
+                       mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
                                                info->dev_class, info->rssi,
                                                NULL);
                }
@@ -2400,7 +2461,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        hci_inquiry_cache_update(hdev, &data);
-                       mgmt_device_found(hdev->id, &info->bdaddr,
+                       mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
                                                info->dev_class, info->rssi,
                                                NULL);
                }
@@ -2531,12 +2592,6 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        if (!num_rsp)
                return;
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        hci_dev_lock(hdev);
 
        for (; num_rsp; num_rsp--, info++) {
@@ -2549,8 +2604,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
                data.rssi               = info->rssi;
                data.ssp_mode           = 0x01;
                hci_inquiry_cache_update(hdev, &data);
-               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
-                                               info->rssi, info->data);
+               mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
+                               info->dev_class, info->rssi, info->data);
        }
 
        hci_dev_unlock(hdev);
@@ -2614,7 +2669,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                struct hci_cp_io_capability_neg_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x18; /* Pairing not allowed */
+               cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
 
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
                                                        sizeof(cp), &cp);
@@ -2706,7 +2761,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
                                                                confirm_hint);
 
 unlock:
@@ -2732,7 +2787,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
         * event gets always produced as initiator and is also mapped to
         * the mgmt_auth_failed event */
        if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0)
-               mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, ev->status);
 
        hci_conn_put(conn);
 
@@ -2813,14 +2868,14 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
        }
 
        if (ev->status) {
-               mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
+               mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
                hci_proto_connect_cfm(conn, ev->status);
                conn->state = BT_CLOSED;
                hci_conn_del(conn);
                goto unlock;
        }
 
-       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
+       mgmt_connected(hdev, &ev->bdaddr, conn->type);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
@@ -3104,5 +3159,5 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
        kfree_skb(skb);
 }
 
-module_param(enable_le, bool, 0444);
+module_param(enable_le, bool, 0644);
 MODULE_PARM_DESC(enable_le, "Enable LE support");
index 661b461cf0b0873983b8fae4dbb83ad80d4de505..c62d254a1379f5cf255b97863f6df4009ce4a7d4 100644 (file)
@@ -436,17 +436,12 @@ static const struct file_operations inquiry_cache_fops = {
 static int blacklist_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *l;
+       struct bdaddr_list *b;
 
        hci_dev_lock_bh(hdev);
 
-       list_for_each(l, &hdev->blacklist) {
-               struct bdaddr_list *b;
-
-               b = list_entry(l, struct bdaddr_list, list);
-
+       list_for_each_entry(b, &hdev->blacklist, list)
                seq_printf(f, "%s\n", batostr(&b->bdaddr));
-       }
 
        hci_dev_unlock_bh(hdev);
 
@@ -485,17 +480,12 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
 static int uuids_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *l;
+       struct bt_uuid *uuid;
 
        hci_dev_lock_bh(hdev);
 
-       list_for_each(l, &hdev->uuids) {
-               struct bt_uuid *uuid;
-
-               uuid = list_entry(l, struct bt_uuid, list);
-
+       list_for_each_entry(uuid, &hdev->uuids, list)
                print_bt_uuid(f, uuid->uuid);
-       }
 
        hci_dev_unlock_bh(hdev);
 
@@ -543,22 +533,28 @@ static int auto_accept_delay_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
                                        auto_accept_delay_set, "%llu\n");
 
-int hci_register_sysfs(struct hci_dev *hdev)
+void hci_init_sysfs(struct hci_dev *hdev)
+{
+       struct device *dev = &hdev->dev;
+
+       dev->type = &bt_host;
+       dev->class = bt_class;
+
+       dev_set_drvdata(dev, hdev);
+       device_initialize(dev);
+}
+
+int hci_add_sysfs(struct hci_dev *hdev)
 {
        struct device *dev = &hdev->dev;
        int err;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       dev->type = &bt_host;
-       dev->class = bt_class;
        dev->parent = hdev->parent;
-
        dev_set_name(dev, "%s", hdev->name);
 
-       dev_set_drvdata(dev, hdev);
-
-       err = device_register(dev);
+       err = device_add(dev);
        if (err < 0)
                return err;
 
@@ -582,7 +578,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
        return 0;
 }
 
-void hci_unregister_sysfs(struct hci_dev *hdev)
+void hci_del_sysfs(struct hci_dev *hdev)
 {
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
index 075a3e920caffcbd44ff2f5a1e9e6ab4cc560e45..3c2d888925d7a8436b19ef8d1562fe9a7943a780 100644 (file)
@@ -81,24 +81,20 @@ static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
 static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
 {
        struct hidp_session *session;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &hidp_session_list) {
-               session = list_entry(p, struct hidp_session, list);
+       list_for_each_entry(session, &hidp_session_list, list) {
                if (!bacmp(bdaddr, &session->bdaddr))
                        return session;
        }
+
        return NULL;
 }
 
 static void __hidp_link_session(struct hidp_session *session)
 {
-       __module_get(THIS_MODULE);
        list_add(&session->list, &hidp_session_list);
-
-       hci_conn_hold_device(session->conn);
 }
 
 static void __hidp_unlink_session(struct hidp_session *session)
@@ -106,7 +102,6 @@ static void __hidp_unlink_session(struct hidp_session *session)
        hci_conn_put_device(session->conn);
 
        list_del(&session->list);
-       module_put(THIS_MODULE);
 }
 
 static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
@@ -255,6 +250,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
 
        BT_DBG("session %p data %p size %d", session, data, size);
 
+       if (atomic_read(&session->terminate))
+               return -EIO;
+
        skb = alloc_skb(size + 1, GFP_ATOMIC);
        if (!skb) {
                BT_ERR("Can't allocate memory for new frame");
@@ -329,6 +327,7 @@ static int hidp_get_raw_report(struct hid_device *hid,
        struct sk_buff *skb;
        size_t len;
        int numbered_reports = hid->report_enum[report_type].numbered;
+       int ret;
 
        switch (report_type) {
        case HID_FEATURE_REPORT:
@@ -352,8 +351,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
        session->waiting_report_number = numbered_reports ? report_number : -1;
        set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
        data[0] = report_number;
-       if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1))
-               goto err_eio;
+       ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
+       if (ret)
+               goto err;
 
        /* Wait for the return of the report. The returned report
           gets put in session->report_return.  */
@@ -365,11 +365,13 @@ static int hidp_get_raw_report(struct hid_device *hid,
                        5*HZ);
                if (res == 0) {
                        /* timeout */
-                       goto err_eio;
+                       ret = -EIO;
+                       goto err;
                }
                if (res < 0) {
                        /* signal */
-                       goto err_restartsys;
+                       ret = -ERESTARTSYS;
+                       goto err;
                }
        }
 
@@ -390,14 +392,10 @@ static int hidp_get_raw_report(struct hid_device *hid,
 
        return len;
 
-err_restartsys:
-       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
-       mutex_unlock(&session->report_mutex);
-       return -ERESTARTSYS;
-err_eio:
+err:
        clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
        mutex_unlock(&session->report_mutex);
-       return -EIO;
+       return ret;
 }
 
 static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
@@ -422,11 +420,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
 
        /* Set up our wait, and send the report request to the device. */
        set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
-       if (hidp_send_ctrl_message(hid->driver_data, report_type,
-                       data, count)) {
-               ret = -ENOMEM;
+       ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
+                                                                       count);
+       if (ret)
                goto err;
-       }
 
        /* Wait for the ACK from the device. */
        while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
@@ -496,10 +493,9 @@ static void hidp_process_handshake(struct hidp_session *session,
        case HIDP_HSHK_ERR_INVALID_REPORT_ID:
        case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
        case HIDP_HSHK_ERR_INVALID_PARAMETER:
-               if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
-                       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+               if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
                        wake_up_interruptible(&session->report_queue);
-               }
+
                /* FIXME: Call into SET_ GET_ handlers here */
                break;
 
@@ -520,10 +516,8 @@ static void hidp_process_handshake(struct hidp_session *session,
        }
 
        /* Wake up the waiting thread. */
-       if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
-               clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+       if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
                wake_up_interruptible(&session->report_queue);
-       }
 }
 
 static void hidp_process_hid_control(struct hidp_session *session,
@@ -663,25 +657,32 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
-static void hidp_process_transmit(struct hidp_session *session)
+static void hidp_process_intr_transmit(struct hidp_session *session)
 {
        struct sk_buff *skb;
 
        BT_DBG("session %p", session);
 
-       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
-               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
-                       skb_queue_head(&session->ctrl_transmit, skb);
+       while ((skb = skb_dequeue(&session->intr_transmit))) {
+               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->intr_transmit, skb);
                        break;
                }
 
                hidp_set_timer(session);
                kfree_skb(skb);
        }
+}
 
-       while ((skb = skb_dequeue(&session->intr_transmit))) {
-               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
-                       skb_queue_head(&session->intr_transmit, skb);
+static void hidp_process_ctrl_transmit(struct hidp_session *session)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("session %p", session);
+
+       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
+               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->ctrl_transmit, skb);
                        break;
                }
 
@@ -700,6 +701,7 @@ static int hidp_session(void *arg)
 
        BT_DBG("session %p", session);
 
+       __module_get(THIS_MODULE);
        set_user_nice(current, -15);
 
        init_waitqueue_entry(&ctrl_wait, current);
@@ -714,23 +716,25 @@ static int hidp_session(void *arg)
                                intr_sk->sk_state != BT_CONNECTED)
                        break;
 
-               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
+               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
                        skb_orphan(skb);
                        if (!skb_linearize(skb))
-                               hidp_recv_ctrl_frame(session, skb);
+                               hidp_recv_intr_frame(session, skb);
                        else
                                kfree_skb(skb);
                }
 
-               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
+               hidp_process_intr_transmit(session);
+
+               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
                        skb_orphan(skb);
                        if (!skb_linearize(skb))
-                               hidp_recv_intr_frame(session, skb);
+                               hidp_recv_ctrl_frame(session, skb);
                        else
                                kfree_skb(skb);
                }
 
-               hidp_process_transmit(session);
+               hidp_process_ctrl_transmit(session);
 
                schedule();
                set_current_state(TASK_INTERRUPTIBLE);
@@ -739,6 +743,10 @@ static int hidp_session(void *arg)
        remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
        remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
 
+       clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+       wake_up_interruptible(&session->report_queue);
+
        down_write(&hidp_session_sem);
 
        hidp_del_timer(session);
@@ -772,34 +780,37 @@ static int hidp_session(void *arg)
 
        kfree(session->rd_data);
        kfree(session);
+       module_put_and_exit(0);
        return 0;
 }
 
-static struct device *hidp_get_device(struct hidp_session *session)
+static struct hci_conn *hidp_get_connection(struct hidp_session *session)
 {
        bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
        bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
-       struct device *device = NULL;
+       struct hci_conn *conn;
        struct hci_dev *hdev;
 
        hdev = hci_get_route(dst, src);
        if (!hdev)
                return NULL;
 
-       session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-       if (session->conn)
-               device = &session->conn->dev;
+       hci_dev_lock_bh(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+       if (conn)
+               hci_conn_hold_device(conn);
+       hci_dev_unlock_bh(hdev);
 
        hci_dev_put(hdev);
 
-       return device;
+       return conn;
 }
 
 static int hidp_setup_input(struct hidp_session *session,
                                struct hidp_connadd_req *req)
 {
        struct input_dev *input;
-       int err, i;
+       int i;
 
        input = input_allocate_device();
        if (!input)
@@ -842,17 +853,10 @@ static int hidp_setup_input(struct hidp_session *session,
                input->relbit[0] |= BIT_MASK(REL_WHEEL);
        }
 
-       input->dev.parent = hidp_get_device(session);
+       input->dev.parent = &session->conn->dev;
 
        input->event = hidp_input_event;
 
-       err = input_register_device(input);
-       if (err < 0) {
-               input_free_device(input);
-               session->input = NULL;
-               return err;
-       }
-
        return 0;
 }
 
@@ -949,7 +953,7 @@ static int hidp_setup_hid(struct hidp_session *session,
        strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
        strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
 
-       hid->dev.parent = hidp_get_device(session);
+       hid->dev.parent = &session->conn->dev;
        hid->ll_driver = &hidp_hid_driver;
 
        hid->hid_get_raw_report = hidp_get_raw_report;
@@ -976,18 +980,20 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
                return -ENOTUNIQ;
 
-       session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
-       if (!session)
-               return -ENOMEM;
-
        BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
 
        down_write(&hidp_session_sem);
 
        s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
        if (s && s->state == BT_CONNECTED) {
-               err = -EEXIST;
-               goto failed;
+               up_write(&hidp_session_sem);
+               return -EEXIST;
+       }
+
+       session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
+       if (!session) {
+               up_write(&hidp_session_sem);
+               return -ENOMEM;
        }
 
        bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
@@ -1003,6 +1009,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->intr_sock = intr_sock;
        session->state     = BT_CONNECTED;
 
+       session->conn = hidp_get_connection(session);
+       if (!session->conn) {
+               err = -ENOTCONN;
+               goto failed;
+       }
+
        setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
 
        skb_queue_head_init(&session->ctrl_transmit);
@@ -1015,9 +1027,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
        session->idle_to = req->idle_to;
 
+       __hidp_link_session(session);
+
        if (req->rd_size > 0) {
                err = hidp_setup_hid(session, req);
-               if (err && err != -ENODEV)
+               if (err)
                        goto purge;
        }
 
@@ -1027,8 +1041,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        goto purge;
        }
 
-       __hidp_link_session(session);
-
        hidp_set_timer(session);
 
        if (session->hid) {
@@ -1054,7 +1066,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        !session->waiting_for_startup);
        }
 
-       err = hid_add_device(session->hid);
+       if (session->hid)
+               err = hid_add_device(session->hid);
+       else
+               err = input_register_device(session->input);
+
        if (err < 0) {
                atomic_inc(&session->terminate);
                wake_up_process(session->task);
@@ -1077,8 +1093,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
 unlink:
        hidp_del_timer(session);
 
-       __hidp_unlink_session(session);
-
        if (session->input) {
                input_unregister_device(session->input);
                session->input = NULL;
@@ -1093,6 +1107,8 @@ unlink:
        session->rd_data = NULL;
 
 purge:
+       __hidp_unlink_session(session);
+
        skb_queue_purge(&session->ctrl_transmit);
        skb_queue_purge(&session->intr_transmit);
 
@@ -1134,19 +1150,16 @@ int hidp_del_connection(struct hidp_conndel_req *req)
 
 int hidp_get_connlist(struct hidp_connlist_req *req)
 {
-       struct list_head *p;
+       struct hidp_session *session;
        int err = 0, n = 0;
 
        BT_DBG("");
 
        down_read(&hidp_session_sem);
 
-       list_for_each(p, &hidp_session_list) {
-               struct hidp_session *session;
+       list_for_each_entry(session, &hidp_session_list, list) {
                struct hidp_conninfo ci;
 
-               session = list_entry(p, struct hidp_session, list);
-
                __hidp_copy_session(session, &ci);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index 5ea94a1eecf2f9a4338aa116d645b03b77fa7bd6..e8a6837996cf311c3156c6c7b18ffc92cb0fba84 100644 (file)
 #include <net/bluetooth/smp.h>
 
 int disable_ertm;
+int enable_hs;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
-static u8 l2cap_fixed_chan[8] = { 0x02, };
+static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
 
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
@@ -219,7 +220,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 
 static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
 {
-       BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
+       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
 
        if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
                chan_hold(chan);
@@ -293,6 +294,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
        atomic_set(&chan->refcnt, 1);
 
+       BT_DBG("sk %p chan %p", sk, chan);
+
        return chan;
 }
 
@@ -310,7 +313,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        chan->psm, chan->dcid);
 
-       conn->disc_reason = 0x13;
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        chan->conn = conn;
 
@@ -337,6 +340,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                chan->omtu = L2CAP_DEFAULT_MTU;
        }
 
+       chan->local_id          = L2CAP_BESTEFFORT_ID;
+       chan->local_stype       = L2CAP_SERV_BESTEFFORT;
+       chan->local_msdu        = L2CAP_DEFAULT_MAX_SDU_SIZE;
+       chan->local_sdu_itime   = L2CAP_DEFAULT_SDU_ITIME;
+       chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
+       chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
+
        chan_hold(chan);
 
        list_add(&chan->list, &conn->chan_l);
@@ -556,34 +566,58 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
                flags = ACL_START;
 
        bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
+       skb->priority = HCI_PRIO_MAX;
+
+       hci_send_acl(conn->hchan, skb, flags);
+}
+
+static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+       struct hci_conn *hcon = chan->conn->hcon;
+       u16 flags;
+
+       BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
+                                                       skb->priority);
+
+       if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
+                                       lmp_no_flush_capable(hcon->hdev))
+               flags = ACL_START_NO_FLUSH;
+       else
+               flags = ACL_START;
 
-       hci_send_acl(conn->hcon, skb, flags);
+       bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+       hci_send_acl(chan->conn->hchan, skb, flags);
 }
 
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 {
        struct sk_buff *skb;
        struct l2cap_hdr *lh;
        struct l2cap_conn *conn = chan->conn;
-       int count, hlen = L2CAP_HDR_SIZE + 2;
-       u8 flags;
+       int count, hlen;
 
        if (chan->state != BT_CONNECTED)
                return;
 
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hlen = L2CAP_EXT_HDR_SIZE;
+       else
+               hlen = L2CAP_ENH_HDR_SIZE;
+
        if (chan->fcs == L2CAP_FCS_CRC16)
-               hlen += 2;
+               hlen += L2CAP_FCS_SIZE;
 
-       BT_DBG("chan %p, control 0x%2.2x", chan, control);
+       BT_DBG("chan %p, control 0x%8.8x", chan, control);
 
        count = min_t(unsigned int, conn->mtu, hlen);
-       control |= L2CAP_CTRL_FRAME_TYPE;
+
+       control |= __set_sframe(chan);
 
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_FINAL;
+               control |= __set_ctrl_final(chan);
 
        if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_POLL;
+               control |= __set_ctrl_poll(chan);
 
        skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
@@ -592,32 +626,27 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
-       put_unaligned_le16(control, skb_put(skb, 2));
+
+       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               u16 fcs = crc16(0, (u8 *)lh, count - 2);
-               put_unaligned_le16(fcs, skb_put(skb, 2));
+               u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
+               put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
        }
 
-       if (lmp_no_flush_capable(conn->hcon->hdev))
-               flags = ACL_START_NO_FLUSH;
-       else
-               flags = ACL_START;
-
-       bt_cb(skb)->force_active = chan->force_active;
-
-       hci_send_acl(chan->conn->hcon, skb, flags);
+       skb->priority = HCI_PRIO_MAX;
+       l2cap_do_send(chan, skb);
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
 {
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
        } else
-               control |= L2CAP_SUPER_RCV_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        l2cap_send_sframe(chan, control);
 }
@@ -947,7 +976,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
        list_for_each_entry(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
 
-               if (chan->force_reliable)
+               if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        sk->sk_err = err;
        }
 
@@ -986,6 +1015,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
                chan->ops->close(chan->data);
        }
 
+       hci_chan_del(conn->hchan);
+
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                del_timer_sync(&conn->info_timer);
 
@@ -1008,18 +1039,26 @@ static void security_timeout(unsigned long arg)
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
+       struct hci_chan *hchan;
 
        if (conn || status)
                return conn;
 
+       hchan = hci_chan_create(hcon);
+       if (!hchan)
+               return NULL;
+
        conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
-       if (!conn)
+       if (!conn) {
+               hci_chan_del(hchan);
                return NULL;
+       }
 
        hcon->l2cap_data = conn;
        conn->hcon = hcon;
+       conn->hchan = hchan;
 
-       BT_DBG("hcon %p conn %p", hcon, conn);
+       BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
 
        if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
                conn->mtu = hcon->hdev->le_mtu;
@@ -1043,7 +1082,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
                setup_timer(&conn->info_timer, l2cap_info_timeout,
                                                (unsigned long) conn);
 
-       conn->disc_reason = 0x13;
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        return conn;
 }
@@ -1245,47 +1284,35 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
                __clear_retrans_timer(chan);
 }
 
-static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
-{
-       struct hci_conn *hcon = chan->conn->hcon;
-       u16 flags;
-
-       BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
-
-       if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
-               flags = ACL_START_NO_FLUSH;
-       else
-               flags = ACL_START;
-
-       bt_cb(skb)->force_active = chan->force_active;
-       hci_send_acl(hcon, skb, flags);
-}
-
 static void l2cap_streaming_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb;
-       u16 control, fcs;
+       u32 control;
+       u16 fcs;
 
        while ((skb = skb_dequeue(&chan->tx_q))) {
-               control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
-               control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
-               put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
+               control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
+               control |= __set_txseq(chan, chan->next_tx_seq);
+               __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
-                       put_unaligned_le16(fcs, skb->data + skb->len - 2);
+                       fcs = crc16(0, (u8 *)skb->data,
+                                               skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs,
+                                       skb->data + skb->len - L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, skb);
 
-               chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
        }
 }
 
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 control, fcs;
+       u16 fcs;
+       u32 control;
 
        skb = skb_peek(&chan->tx_q);
        if (!skb)
@@ -1308,20 +1335,23 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 
        tx_skb = skb_clone(skb, GFP_ATOMIC);
        bt_cb(skb)->retries++;
-       control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-       control &= L2CAP_CTRL_SAR;
+
+       control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+       control &= __get_sar_mask(chan);
 
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_FINAL;
+               control |= __set_ctrl_final(chan);
 
-       control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                       | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+       control |= __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_txseq(chan, tx_seq);
 
-       put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+       __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
-               put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+               fcs = crc16(0, (u8 *)tx_skb->data,
+                                               tx_skb->len - L2CAP_FCS_SIZE);
+               put_unaligned_le16(fcs,
+                               tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
        }
 
        l2cap_do_send(chan, tx_skb);
@@ -1330,7 +1360,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 static int l2cap_ertm_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 control, fcs;
+       u16 fcs;
+       u32 control;
        int nsent = 0;
 
        if (chan->state != BT_CONNECTED)
@@ -1348,20 +1379,22 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
                bt_cb(skb)->retries++;
 
-               control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-               control &= L2CAP_CTRL_SAR;
+               control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+               control &= __get_sar_mask(chan);
 
                if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-                       control |= L2CAP_CTRL_FINAL;
+                       control |= __set_ctrl_final(chan);
 
-               control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                               | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
-               put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+               control |= __set_reqseq(chan, chan->buffer_seq);
+               control |= __set_txseq(chan, chan->next_tx_seq);
 
+               __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
-                       put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
+                       fcs = crc16(0, (u8 *)skb->data,
+                                               tx_skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs, skb->data +
+                                               tx_skb->len - L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, tx_skb);
@@ -1369,7 +1402,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
                __set_retrans_timer(chan);
 
                bt_cb(skb)->tx_seq = chan->next_tx_seq;
-               chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
                if (bt_cb(skb)->retries == 1)
                        chan->unacked_frames++;
@@ -1401,12 +1435,12 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 
 static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-       u16 control = 0;
+       u32 control = 0;
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
                l2cap_send_sframe(chan, control);
                return;
@@ -1415,20 +1449,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
        if (l2cap_ertm_send(chan) > 0)
                return;
 
-       control |= L2CAP_SUPER_RCV_READY;
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
        l2cap_send_sframe(chan, control);
 }
 
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
        struct srej_list *tail;
-       u16 control;
+       u32 control;
 
-       control = L2CAP_SUPER_SELECT_REJECT;
-       control |= L2CAP_CTRL_FINAL;
+       control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+       control |= __set_ctrl_final(chan);
 
        tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-       control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, tail->tx_seq);
 
        l2cap_send_sframe(chan, control);
 }
@@ -1456,6 +1490,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
                if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
                        return -EFAULT;
 
+               (*frag)->priority = skb->priority;
+
                sent += count;
                len  -= count;
 
@@ -1465,15 +1501,17 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
        return sent;
 }
 
-static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u32 priority)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
-       int err, count, hlen = L2CAP_HDR_SIZE + 2;
+       int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
        skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1481,6 +1519,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
        if (!skb)
                return ERR_PTR(err);
 
+       skb->priority = priority;
+
        /* Create L2CAP header */
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
@@ -1495,7 +1535,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
        return skb;
 }
 
-static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u32 priority)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
@@ -1511,6 +1553,8 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
        if (!skb)
                return ERR_PTR(err);
 
+       skb->priority = priority;
+
        /* Create L2CAP header */
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
@@ -1526,12 +1570,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
 
 static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
-                                               u16 control, u16 sdulen)
+                                               u32 control, u16 sdulen)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
-       int err, count, hlen = L2CAP_HDR_SIZE + 2;
+       int err, count, hlen;
        struct l2cap_hdr *lh;
 
        BT_DBG("sk %p len %d", sk, (int)len);
@@ -1539,11 +1583,16 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        if (!conn)
                return ERR_PTR(-ENOTCONN);
 
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hlen = L2CAP_EXT_HDR_SIZE;
+       else
+               hlen = L2CAP_ENH_HDR_SIZE;
+
        if (sdulen)
-               hlen += 2;
+               hlen += L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               hlen += 2;
+               hlen += L2CAP_FCS_SIZE;
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
        skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1555,9 +1604,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-       put_unaligned_le16(control, skb_put(skb, 2));
+
+       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+
        if (sdulen)
-               put_unaligned_le16(sdulen, skb_put(skb, 2));
+               put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
        err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
        if (unlikely(err < 0)) {
@@ -1566,7 +1617,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        }
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               put_unaligned_le16(0, skb_put(skb, 2));
+               put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
 
        bt_cb(skb)->retries = 0;
        return skb;
@@ -1576,11 +1627,11 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 {
        struct sk_buff *skb;
        struct sk_buff_head sar_queue;
-       u16 control;
+       u32 control;
        size_t size = 0;
 
        skb_queue_head_init(&sar_queue);
-       control = L2CAP_SDU_START;
+       control = __set_ctrl_sar(chan, L2CAP_SAR_START);
        skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
        if (IS_ERR(skb))
                return PTR_ERR(skb);
@@ -1593,10 +1644,10 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
                size_t buflen;
 
                if (len > chan->remote_mps) {
-                       control = L2CAP_SDU_CONTINUE;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
                        buflen = chan->remote_mps;
                } else {
-                       control = L2CAP_SDU_END;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_END);
                        buflen = len;
                }
 
@@ -1617,15 +1668,16 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
        return size;
 }
 
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                                                               u32 priority)
 {
        struct sk_buff *skb;
-       u16 control;
+       u32 control;
        int err;
 
        /* Connectionless channel */
        if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
-               skb = l2cap_create_connless_pdu(chan, msg, len);
+               skb = l2cap_create_connless_pdu(chan, msg, len, priority);
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
@@ -1640,7 +1692,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                        return -EMSGSIZE;
 
                /* Create a basic PDU */
-               skb = l2cap_create_basic_pdu(chan, msg, len);
+               skb = l2cap_create_basic_pdu(chan, msg, len, priority);
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
@@ -1652,7 +1704,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
        case L2CAP_MODE_STREAMING:
                /* Entire SDU fits into one PDU */
                if (len <= chan->remote_mps) {
-                       control = L2CAP_SDU_UNSEGMENTED;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
                        skb = l2cap_create_iframe_pdu(chan, msg, len, control,
                                                                        0);
                        if (IS_ERR(skb))
@@ -1850,6 +1902,37 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
        *ptr += L2CAP_CONF_OPT_SIZE + len;
 }
 
+static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
+{
+       struct l2cap_conf_efs efs;
+
+       switch(chan->mode) {
+       case L2CAP_MODE_ERTM:
+               efs.id          = chan->local_id;
+               efs.stype       = chan->local_stype;
+               efs.msdu        = cpu_to_le16(chan->local_msdu);
+               efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
+               efs.acc_lat     = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
+               efs.flush_to    = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+               break;
+
+       case L2CAP_MODE_STREAMING:
+               efs.id          = 1;
+               efs.stype       = L2CAP_SERV_BESTEFFORT;
+               efs.msdu        = cpu_to_le16(chan->local_msdu);
+               efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
+               efs.acc_lat     = 0;
+               efs.flush_to    = 0;
+               break;
+
+       default:
+               return;
+       }
+
+       l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
+                                                       (unsigned long) &efs);
+}
+
 static void l2cap_ack_timeout(unsigned long arg)
 {
        struct l2cap_chan *chan = (void *) arg;
@@ -1896,11 +1979,36 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
        }
 }
 
+static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
+{
+       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
+}
+
+static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
+{
+       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
+}
+
+static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
+{
+       if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
+                                               __l2cap_ews_supported(chan)) {
+               /* use extended control field */
+               set_bit(FLAG_EXT_CTRL, &chan->flags);
+               chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
+       } else {
+               chan->tx_win = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_TX_WINDOW);
+               chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
+       }
+}
+
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
        struct l2cap_conf_req *req = data;
        struct l2cap_conf_rfc rfc = { .mode = chan->mode };
        void *ptr = req->data;
+       u16 size;
 
        BT_DBG("chan %p", chan);
 
@@ -1913,6 +2021,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
                if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
                        break;
 
+               if (__l2cap_efs_supported(chan))
+                       set_bit(FLAG_EFS_ENABLE, &chan->flags);
+
                /* fall through */
        default:
                chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
@@ -1942,17 +2053,27 @@ done:
 
        case L2CAP_MODE_ERTM:
                rfc.mode            = L2CAP_MODE_ERTM;
-               rfc.txwin_size      = chan->tx_win;
                rfc.max_transmit    = chan->max_tx;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
-               rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-               if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-                       rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+               size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+               rfc.max_pdu_size = cpu_to_le16(size);
+
+               l2cap_txwin_setup(chan);
+
+               rfc.txwin_size = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_TX_WINDOW);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
                                                        (unsigned long) &rfc);
 
+               if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
+                       l2cap_add_opt_efs(&ptr, chan);
+
                if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -1961,6 +2082,10 @@ done:
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
+
+               if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+                                                               chan->tx_win);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -1969,13 +2094,19 @@ done:
                rfc.max_transmit    = 0;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
-               rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-               if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-                       rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+               size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+               rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
                                                        (unsigned long) &rfc);
 
+               if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
+                       l2cap_add_opt_efs(&ptr, chan);
+
                if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -2002,8 +2133,11 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
        int type, hint, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       struct l2cap_conf_efs efs;
+       u8 remote_efs = 0;
        u16 mtu = L2CAP_DEFAULT_MTU;
        u16 result = L2CAP_CONF_SUCCESS;
+       u16 size;
 
        BT_DBG("chan %p", chan);
 
@@ -2033,7 +2167,22 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                case L2CAP_CONF_FCS:
                        if (val == L2CAP_FCS_NONE)
                                set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       remote_efs = 1;
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *) val, olen);
+                       break;
+
+               case L2CAP_CONF_EWS:
+                       if (!enable_hs)
+                               return -ECONNREFUSED;
 
+                       set_bit(FLAG_EXT_CTRL, &chan->flags);
+                       set_bit(CONF_EWS_RECV, &chan->conf_state);
+                       chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
+                       chan->remote_tx_win = val;
                        break;
 
                default:
@@ -2058,6 +2207,13 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                        break;
                }
 
+               if (remote_efs) {
+                       if (__l2cap_efs_supported(chan))
+                               set_bit(FLAG_EFS_ENABLE, &chan->flags);
+                       else
+                               return -ECONNREFUSED;
+               }
+
                if (chan->mode != rfc.mode)
                        return -ECONNREFUSED;
 
@@ -2076,7 +2232,6 @@ done:
                                        sizeof(rfc), (unsigned long) &rfc);
        }
 
-
        if (result == L2CAP_CONF_SUCCESS) {
                /* Configure output options and let the other side know
                 * which ones we don't like. */
@@ -2089,6 +2244,26 @@ done:
                }
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
 
+               if (remote_efs) {
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype) {
+
+                               result = L2CAP_CONF_UNACCEPT;
+
+                               if (chan->num_conf_req >= 1)
+                                       return -ECONNREFUSED;
+
+                               l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                                       sizeof(efs),
+                                                       (unsigned long) &efs);
+                       } else {
+                               /* Send PENDING Conf Rsp */
+                               result = L2CAP_CONF_PENDING;
+                               set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+                       }
+               }
+
                switch (rfc.mode) {
                case L2CAP_MODE_BASIC:
                        chan->fcs = L2CAP_FCS_NONE;
@@ -2096,13 +2271,20 @@ done:
                        break;
 
                case L2CAP_MODE_ERTM:
-                       chan->remote_tx_win = rfc.txwin_size;
-                       chan->remote_max_tx = rfc.max_transmit;
+                       if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
+                               chan->remote_tx_win = rfc.txwin_size;
+                       else
+                               rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
 
-                       if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-                               rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+                       chan->remote_max_tx = rfc.max_transmit;
 
-                       chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+                       size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+                                               chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+                       rfc.max_pdu_size = cpu_to_le16(size);
+                       chan->remote_mps = size;
 
                        rfc.retrans_timeout =
                                le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
@@ -2114,13 +2296,29 @@ done:
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
 
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->remote_id = efs.id;
+                               chan->remote_stype = efs.stype;
+                               chan->remote_msdu = le16_to_cpu(efs.msdu);
+                               chan->remote_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                               chan->remote_acc_lat =
+                                               le32_to_cpu(efs.acc_lat);
+                               chan->remote_sdu_itime =
+                                       le32_to_cpu(efs.sdu_itime);
+                               l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       }
                        break;
 
                case L2CAP_MODE_STREAMING:
-                       if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-                               rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
-
-                       chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+                       size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+                                               chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+                       rfc.max_pdu_size = cpu_to_le16(size);
+                       chan->remote_mps = size;
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
@@ -2153,6 +2351,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        int type, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc;
+       struct l2cap_conf_efs efs;
 
        BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
 
@@ -2188,6 +2387,26 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
                        break;
+
+               case L2CAP_CONF_EWS:
+                       chan->tx_win = min_t(u16, val,
+                                               L2CAP_DEFAULT_EXT_WINDOW);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+                                                       chan->tx_win);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *)val, olen);
+
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype)
+                               return -ECONNREFUSED;
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       break;
                }
        }
 
@@ -2196,13 +2415,23 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
 
        chan->mode = rfc.mode;
 
-       if (*result == L2CAP_CONF_SUCCESS) {
+       if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
                switch (rfc.mode) {
                case L2CAP_MODE_ERTM:
                        chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
                        chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
+
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->local_msdu = le16_to_cpu(efs.msdu);
+                               chan->local_sdu_itime =
+                                               le32_to_cpu(efs.sdu_itime);
+                               chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
+                               chan->local_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                       }
                        break;
+
                case L2CAP_MODE_STREAMING:
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
                }
@@ -2330,7 +2559,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
-               conn->disc_reason = 0x05;
+               conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
        }
@@ -2602,6 +2831,21 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                chan->num_conf_req++;
        }
 
+       /* Got Conf Rsp PENDING from remote side and asume 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)) {
+
+               /* check compatibility */
+
+               clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+               set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
+                                       l2cap_build_conf_rsp(chan, rsp,
+                                       L2CAP_CONF_SUCCESS, 0x0000), rsp);
+       }
+
 unlock:
        bh_unlock_sock(sk);
        return 0;
@@ -2631,8 +2875,33 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        switch (result) {
        case L2CAP_CONF_SUCCESS:
                l2cap_conf_rfc_get(chan, rsp->data, len);
+               clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
                break;
 
+       case L2CAP_CONF_PENDING:
+               set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
+
+               if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+                       char buf[64];
+
+                       len = l2cap_parse_conf_rsp(chan, rsp->data, len,
+                                                               buf, &result);
+                       if (len < 0) {
+                               l2cap_send_disconn_req(conn, chan, ECONNRESET);
+                               goto done;
+                       }
+
+                       /* check compatibility */
+
+                       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+                       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+                       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
+                                               l2cap_build_conf_rsp(chan, buf,
+                                               L2CAP_CONF_SUCCESS, 0x0000), buf);
+               }
+               goto done;
+
        case L2CAP_CONF_UNACCEPT:
                if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
                        char req[64];
@@ -2782,15 +3051,25 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                                         | L2CAP_FEAT_FCS;
+               if (enable_hs)
+                       feat_mask |= L2CAP_FEAT_EXT_FLOW
+                                               | L2CAP_FEAT_EXT_WINDOW;
+
                put_unaligned_le32(feat_mask, rsp->data);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else if (type == L2CAP_IT_FIXED_CHAN) {
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+
+               if (enable_hs)
+                       l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
+               else
+                       l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
+
                rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
                rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
-               memcpy(buf + 4, l2cap_fixed_chan, 8);
+               memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
@@ -2857,6 +3136,165 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
        return 0;
 }
 
+static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                       void *data)
+{
+       struct l2cap_create_chan_req *req = data;
+       struct l2cap_create_chan_rsp rsp;
+       u16 psm, scid;
+
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
+       if (!enable_hs)
+               return -EINVAL;
+
+       psm = le16_to_cpu(req->psm);
+       scid = le16_to_cpu(req->scid);
+
+       BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
+
+       /* Placeholder: Always reject */
+       rsp.dcid = 0;
+       rsp.scid = cpu_to_le16(scid);
+       rsp.result = L2CAP_CR_NO_MEM;
+       rsp.status = L2CAP_CS_NO_INFO;
+
+       l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
+                      sizeof(rsp), &rsp);
+
+       return 0;
+}
+
+static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, void *data)
+{
+       BT_DBG("conn %p", conn);
+
+       return l2cap_connect_rsp(conn, cmd, data);
+}
+
+static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
+                                                       u16 icid, u16 result)
+{
+       struct l2cap_move_chan_rsp rsp;
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       rsp.icid = cpu_to_le16(icid);
+       rsp.result = cpu_to_le16(result);
+
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
+}
+
+static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
+                               struct l2cap_chan *chan, u16 icid, u16 result)
+{
+       struct l2cap_move_chan_cfm cfm;
+       u8 ident;
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       ident = l2cap_get_ident(conn);
+       if (chan)
+               chan->ident = ident;
+
+       cfm.icid = cpu_to_le16(icid);
+       cfm.result = cpu_to_le16(result);
+
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
+}
+
+static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
+                                                               u16 icid)
+{
+       struct l2cap_move_chan_cfm_rsp rsp;
+
+       BT_DBG("icid %d", icid);
+
+       rsp.icid = cpu_to_le16(icid);
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
+}
+
+static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_req *req = data;
+       u16 icid = 0;
+       u16 result = L2CAP_MR_NOT_ALLOWED;
+
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
+       icid = le16_to_cpu(req->icid);
+
+       BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
+
+       if (!enable_hs)
+               return -EINVAL;
+
+       /* Placeholder: Always refuse */
+       l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_rsp *rsp = data;
+       u16 icid, result;
+
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
+       icid = le16_to_cpu(rsp->icid);
+       result = le16_to_cpu(rsp->result);
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       /* Placeholder: Always unconfirmed */
+       l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_cfm *cfm = data;
+       u16 icid, result;
+
+       if (cmd_len != sizeof(*cfm))
+               return -EPROTO;
+
+       icid = le16_to_cpu(cfm->icid);
+       result = le16_to_cpu(cfm->result);
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_cfm_rsp *rsp = data;
+       u16 icid;
+
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
+       icid = le16_to_cpu(rsp->icid);
+
+       BT_DBG("icid %d", icid);
+
+       return 0;
+}
+
 static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
                                                        u16 to_multiplier)
 {
@@ -2969,6 +3407,30 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                err = l2cap_information_rsp(conn, cmd, data);
                break;
 
+       case L2CAP_CREATE_CHAN_REQ:
+               err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_CREATE_CHAN_RSP:
+               err = l2cap_create_channel_rsp(conn, cmd, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_REQ:
+               err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_RSP:
+               err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_CFM:
+               err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_CFM_RSP:
+               err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
+               break;
+
        default:
                BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
                err = -EINVAL;
@@ -3047,10 +3509,15 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 {
        u16 our_fcs, rcv_fcs;
-       int hdr_size = L2CAP_HDR_SIZE + 2;
+       int hdr_size;
+
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hdr_size = L2CAP_EXT_HDR_SIZE;
+       else
+               hdr_size = L2CAP_ENH_HDR_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               skb_trim(skb, skb->len - 2);
+               skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
                rcv_fcs = get_unaligned_le16(skb->data + skb->len);
                our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
 
@@ -3062,14 +3529,14 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 
 static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-       u16 control = 0;
+       u32 control = 0;
 
        chan->frames_sent = 0;
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                l2cap_send_sframe(chan, control);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
        }
@@ -3081,12 +3548,12 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 
        if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
                        chan->frames_sent == 0) {
-               control |= L2CAP_SUPER_RCV_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
                l2cap_send_sframe(chan, control);
        }
 }
 
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
+static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
 {
        struct sk_buff *next_skb;
        int tx_seq_offset, next_tx_seq_offset;
@@ -3100,18 +3567,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
                return 0;
        }
 
-       tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-       if (tx_seq_offset < 0)
-               tx_seq_offset += 64;
+       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
        do {
                if (bt_cb(next_skb)->tx_seq == tx_seq)
                        return -EINVAL;
 
-               next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
-                                               chan->buffer_seq) % 64;
-               if (next_tx_seq_offset < 0)
-                       next_tx_seq_offset += 64;
+               next_tx_seq_offset = __seq_offset(chan,
+                               bt_cb(next_skb)->tx_seq, chan->buffer_seq);
 
                if (next_tx_seq_offset > tx_seq_offset) {
                        __skb_queue_before(&chan->srej_q, next_skb, skb);
@@ -3147,24 +3610,24 @@ static void append_skb_frag(struct sk_buff *skb,
        skb->truesize += new_frag->truesize;
 }
 
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
 {
        int err = -EINVAL;
 
-       switch (control & L2CAP_CTRL_SAR) {
-       case L2CAP_SDU_UNSEGMENTED:
+       switch (__get_ctrl_sar(chan, control)) {
+       case L2CAP_SAR_UNSEGMENTED:
                if (chan->sdu)
                        break;
 
                err = chan->ops->recv(chan->data, skb);
                break;
 
-       case L2CAP_SDU_START:
+       case L2CAP_SAR_START:
                if (chan->sdu)
                        break;
 
                chan->sdu_len = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+               skb_pull(skb, L2CAP_SDULEN_SIZE);
 
                if (chan->sdu_len > chan->imtu) {
                        err = -EMSGSIZE;
@@ -3181,7 +3644,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
                err = 0;
                break;
 
-       case L2CAP_SDU_CONTINUE:
+       case L2CAP_SAR_CONTINUE:
                if (!chan->sdu)
                        break;
 
@@ -3195,7 +3658,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
                err = 0;
                break;
 
-       case L2CAP_SDU_END:
+       case L2CAP_SAR_END:
                if (!chan->sdu)
                        break;
 
@@ -3230,14 +3693,14 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-       u16 control;
+       u32 control;
 
        BT_DBG("chan %p, Enter local busy", chan);
 
        set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
-       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       control |= L2CAP_SUPER_RCV_NOT_READY;
+       control = __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
        l2cap_send_sframe(chan, control);
 
        set_bit(CONN_RNR_SENT, &chan->conn_state);
@@ -3247,13 +3710,14 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
 {
-       u16 control;
+       u32 control;
 
        if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
                goto done;
 
-       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+       control = __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_ctrl_poll(chan);
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
        l2cap_send_sframe(chan, control);
        chan->retry_count = 1;
 
@@ -3279,10 +3743,10 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
        }
 }
 
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct sk_buff *skb;
-       u16 control;
+       u32 control;
 
        while ((skb = skb_peek(&chan->srej_q)) &&
                        !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
@@ -3292,7 +3756,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
                        break;
 
                skb = skb_dequeue(&chan->srej_q);
-               control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+               control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
                err = l2cap_reassemble_sdu(chan, skb, control);
 
                if (err < 0) {
@@ -3300,16 +3764,15 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
                        break;
                }
 
-               chan->buffer_seq_srej =
-                       (chan->buffer_seq_srej + 1) % 64;
-               tx_seq = (tx_seq + 1) % 64;
+               chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
+               tx_seq = __next_seq(chan, tx_seq);
        }
 }
 
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *l, *tmp;
-       u16 control;
+       u32 control;
 
        list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
                if (l->tx_seq == tx_seq) {
@@ -3317,45 +3780,48 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
                        kfree(l);
                        return;
                }
-               control = L2CAP_SUPER_SELECT_REJECT;
-               control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+               control |= __set_reqseq(chan, l->tx_seq);
                l2cap_send_sframe(chan, control);
                list_del(&l->list);
                list_add_tail(&l->list, &chan->srej_l);
        }
 }
 
-static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *new;
-       u16 control;
+       u32 control;
 
        while (tx_seq != chan->expected_tx_seq) {
-               control = L2CAP_SUPER_SELECT_REJECT;
-               control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+               control |= __set_reqseq(chan, chan->expected_tx_seq);
                l2cap_send_sframe(chan, control);
 
                new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
                new->tx_seq = chan->expected_tx_seq;
-               chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+               chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+
                list_add_tail(&new->list, &chan->srej_l);
        }
-       chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 }
 
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-       u8 tx_seq = __get_txseq(rx_control);
-       u8 req_seq = __get_reqseq(rx_control);
-       u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
+       u16 tx_seq = __get_txseq(chan, rx_control);
+       u16 req_seq = __get_reqseq(chan, rx_control);
+       u8 sar = __get_ctrl_sar(chan, rx_control);
        int tx_seq_offset, expected_tx_seq_offset;
        int num_to_ack = (chan->tx_win/6) + 1;
        int err = 0;
 
-       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
+       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
                                                        tx_seq, rx_control);
 
-       if (L2CAP_CTRL_FINAL & rx_control &&
+       if (__is_ctrl_final(chan, rx_control) &&
                        test_bit(CONN_WAIT_F, &chan->conn_state)) {
                __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
@@ -3366,9 +3832,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        chan->expected_ack_seq = req_seq;
        l2cap_drop_acked_frames(chan);
 
-       tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-       if (tx_seq_offset < 0)
-               tx_seq_offset += 64;
+       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
        /* invalid tx_seq */
        if (tx_seq_offset >= chan->tx_win) {
@@ -3416,10 +3880,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
                        l2cap_send_srejframe(chan, tx_seq);
                }
        } else {
-               expected_tx_seq_offset =
-                       (chan->expected_tx_seq - chan->buffer_seq) % 64;
-               if (expected_tx_seq_offset < 0)
-                       expected_tx_seq_offset += 64;
+               expected_tx_seq_offset = __seq_offset(chan,
+                               chan->expected_tx_seq, chan->buffer_seq);
 
                /* duplicated tx_seq */
                if (tx_seq_offset < expected_tx_seq_offset)
@@ -3444,7 +3906,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        return 0;
 
 expected:
-       chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 
        if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                bt_cb(skb)->tx_seq = tx_seq;
@@ -3454,13 +3916,14 @@ expected:
        }
 
        err = l2cap_reassemble_sdu(chan, skb, rx_control);
-       chan->buffer_seq = (chan->buffer_seq + 1) % 64;
+       chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
+
        if (err < 0) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                return err;
        }
 
-       if (rx_control & L2CAP_CTRL_FINAL) {
+       if (__is_ctrl_final(chan, rx_control)) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        }
@@ -3478,15 +3941,15 @@ drop:
        return 0;
 }
 
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
-                                               rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
+                               __get_reqseq(chan, rx_control), rx_control);
 
-       chan->expected_ack_seq = __get_reqseq(rx_control);
+       chan->expected_ack_seq = __get_reqseq(chan, rx_control);
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_POLL) {
+       if (__is_ctrl_poll(chan, rx_control)) {
                set_bit(CONN_SEND_FBIT, &chan->conn_state);
                if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
@@ -3499,7 +3962,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
                        l2cap_send_i_or_rr_or_rnr(chan);
                }
 
-       } else if (rx_control & L2CAP_CTRL_FINAL) {
+       } else if (__is_ctrl_final(chan, rx_control)) {
                clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
@@ -3518,18 +3981,18 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
        }
 }
 
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_FINAL) {
+       if (__is_ctrl_final(chan, rx_control)) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        } else {
@@ -3539,15 +4002,15 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
                        set_bit(CONN_REJ_ACT, &chan->conn_state);
        }
 }
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-       if (rx_control & L2CAP_CTRL_POLL) {
+       if (__is_ctrl_poll(chan, rx_control)) {
                chan->expected_ack_seq = tx_seq;
                l2cap_drop_acked_frames(chan);
 
@@ -3560,7 +4023,7 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
                        chan->srej_save_reqseq = tx_seq;
                        set_bit(CONN_SREJ_ACT, &chan->conn_state);
                }
-       } else if (rx_control & L2CAP_CTRL_FINAL) {
+       } else if (__is_ctrl_final(chan, rx_control)) {
                if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
                                chan->srej_save_reqseq == tx_seq)
                        clear_bit(CONN_SREJ_ACT, &chan->conn_state);
@@ -3575,37 +4038,39 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
        }
 }
 
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_POLL)
+       if (__is_ctrl_poll(chan, rx_control))
                set_bit(CONN_SEND_FBIT, &chan->conn_state);
 
        if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                __clear_retrans_timer(chan);
-               if (rx_control & L2CAP_CTRL_POLL)
+               if (__is_ctrl_poll(chan, rx_control))
                        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
                return;
        }
 
-       if (rx_control & L2CAP_CTRL_POLL)
+       if (__is_ctrl_poll(chan, rx_control)) {
                l2cap_send_srejtail(chan);
-       else
-               l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
+       } else {
+               rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
+               l2cap_send_sframe(chan, rx_control);
+       }
 }
 
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-       BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
+       BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
 
-       if (L2CAP_CTRL_FINAL & rx_control &&
+       if (__is_ctrl_final(chan, rx_control) &&
                        test_bit(CONN_WAIT_F, &chan->conn_state)) {
                __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
@@ -3613,20 +4078,20 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
                clear_bit(CONN_WAIT_F, &chan->conn_state);
        }
 
-       switch (rx_control & L2CAP_CTRL_SUPERVISE) {
-       case L2CAP_SUPER_RCV_READY:
+       switch (__get_ctrl_super(chan, rx_control)) {
+       case L2CAP_SUPER_RR:
                l2cap_data_channel_rrframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_REJECT:
+       case L2CAP_SUPER_REJ:
                l2cap_data_channel_rejframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_SELECT_REJECT:
+       case L2CAP_SUPER_SREJ:
                l2cap_data_channel_srejframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_RCV_NOT_READY:
+       case L2CAP_SUPER_RNR:
                l2cap_data_channel_rnrframe(chan, rx_control);
                break;
        }
@@ -3638,12 +4103,12 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-       u16 control;
-       u8 req_seq;
+       u32 control;
+       u16 req_seq;
        int len, next_tx_seq_offset, req_seq_offset;
 
-       control = get_unaligned_le16(skb->data);
-       skb_pull(skb, 2);
+       control = __get_control(chan, skb->data);
+       skb_pull(skb, __ctrl_size(chan));
        len = skb->len;
 
        /*
@@ -3654,26 +4119,23 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
        if (l2cap_check_fcs(chan, skb))
                goto drop;
 
-       if (__is_sar_start(control) && __is_iframe(control))
-               len -= 2;
+       if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
+               len -= L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               len -= 2;
+               len -= L2CAP_FCS_SIZE;
 
        if (len > chan->mps) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                goto drop;
        }
 
-       req_seq = __get_reqseq(control);
-       req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
-       if (req_seq_offset < 0)
-               req_seq_offset += 64;
+       req_seq = __get_reqseq(chan, control);
 
-       next_tx_seq_offset =
-               (chan->next_tx_seq - chan->expected_ack_seq) % 64;
-       if (next_tx_seq_offset < 0)
-               next_tx_seq_offset += 64;
+       req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
+
+       next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
+                                               chan->expected_ack_seq);
 
        /* check for invalid req-seq */
        if (req_seq_offset > next_tx_seq_offset) {
@@ -3681,7 +4143,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
                goto drop;
        }
 
-       if (__is_iframe(control)) {
+       if (!__is_sframe(chan, control)) {
                if (len < 0) {
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                        goto drop;
@@ -3709,8 +4171,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 {
        struct l2cap_chan *chan;
        struct sock *sk = NULL;
-       u16 control;
-       u8 tx_seq;
+       u32 control;
+       u16 tx_seq;
        int len;
 
        chan = l2cap_get_chan_by_scid(conn, cid);
@@ -3751,23 +4213,23 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                goto done;
 
        case L2CAP_MODE_STREAMING:
-               control = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+               control = __get_control(chan, skb->data);
+               skb_pull(skb, __ctrl_size(chan));
                len = skb->len;
 
                if (l2cap_check_fcs(chan, skb))
                        goto drop;
 
-               if (__is_sar_start(control))
-                       len -= 2;
+               if (__is_sar_start(chan, control))
+                       len -= L2CAP_SDULEN_SIZE;
 
                if (chan->fcs == L2CAP_FCS_CRC16)
-                       len -= 2;
+                       len -= L2CAP_FCS_SIZE;
 
-               if (len > chan->mps || len < 0 || __is_sframe(control))
+               if (len > chan->mps || len < 0 || __is_sframe(chan, control))
                        goto drop;
 
-               tx_seq = __get_txseq(control);
+               tx_seq = __get_txseq(chan, control);
 
                if (chan->expected_tx_seq != tx_seq) {
                        /* Frame(s) missing - must discard partial SDU */
@@ -3779,7 +4241,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                        /* TODO: Notify userland of missing data */
                }
 
-               chan->expected_tx_seq = (tx_seq + 1) % 64;
+               chan->expected_tx_seq = __next_seq(chan, tx_seq);
 
                if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -3933,12 +4395,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
                        lm1 |= HCI_LM_ACCEPT;
-                       if (c->role_switch)
+                       if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm1 |= HCI_LM_MASTER;
                        exact++;
                } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm2 |= HCI_LM_ACCEPT;
-                       if (c->role_switch)
+                       if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm2 |= HCI_LM_MASTER;
                }
        }
@@ -3973,7 +4435,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon)
        BT_DBG("hcon %p", hcon);
 
        if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
-               return 0x13;
+               return HCI_ERROR_REMOTE_USER_TERM;
 
        return conn->disc_reason;
 }
@@ -4306,3 +4768,6 @@ void l2cap_exit(void)
 
 module_param(disable_ertm, bool, 0644);
 MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
+
+module_param(enable_hs, bool, 0644);
+MODULE_PARM_DESC(enable_hs, "Enable High Speed");
index 5c406d3136f74fc206380968a0a98c3c4b742474..e2e785c746306a6f4b79f10353b8f3fe7aa5d986 100644 (file)
@@ -334,7 +334,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                opts.mode     = chan->mode;
                opts.fcs      = chan->fcs;
                opts.max_tx   = chan->max_tx;
-               opts.txwin_size = (__u16)chan->tx_win;
+               opts.txwin_size = chan->tx_win;
 
                len = min_t(unsigned int, len, sizeof(opts));
                if (copy_to_user(optval, (char *) &opts, len))
@@ -359,10 +359,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
-               if (chan->role_switch)
+               if (test_bit(FLAG_ROLE_SWITCH, &chan->flags))
                        opt |= L2CAP_LM_MASTER;
 
-               if (chan->force_reliable)
+               if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        opt |= L2CAP_LM_RELIABLE;
 
                if (put_user(opt, (u32 __user *) optval))
@@ -449,7 +449,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                break;
 
        case BT_FLUSHABLE:
-               if (put_user(chan->flushable, (u32 __user *) optval))
+               if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
+                                               (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
@@ -461,7 +462,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                        break;
                }
 
-               pwr.force_active = chan->force_active;
+               pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
 
                len = min_t(unsigned int, len, sizeof(pwr));
                if (copy_to_user(optval, (char *) &pwr, len))
@@ -469,6 +470,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
                break;
 
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (put_user(chan->chan_policy, (u32 __user *) optval))
+                       err = -EFAULT;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -503,7 +514,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                opts.mode     = chan->mode;
                opts.fcs      = chan->fcs;
                opts.max_tx   = chan->max_tx;
-               opts.txwin_size = (__u16)chan->tx_win;
+               opts.txwin_size = chan->tx_win;
 
                len = min_t(unsigned int, sizeof(opts), optlen);
                if (copy_from_user((char *) &opts, optval, len)) {
@@ -511,7 +522,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
-               if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+               if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
                        err = -EINVAL;
                        break;
                }
@@ -535,7 +546,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                chan->omtu = opts.omtu;
                chan->fcs  = opts.fcs;
                chan->max_tx = opts.max_tx;
-               chan->tx_win = (__u8)opts.txwin_size;
+               chan->tx_win = opts.txwin_size;
                break;
 
        case L2CAP_LM:
@@ -551,8 +562,15 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                if (opt & L2CAP_LM_SECURE)
                        chan->sec_level = BT_SECURITY_HIGH;
 
-               chan->role_switch    = (opt & L2CAP_LM_MASTER);
-               chan->force_reliable = (opt & L2CAP_LM_RELIABLE);
+               if (opt & L2CAP_LM_MASTER)
+                       set_bit(FLAG_ROLE_SWITCH, &chan->flags);
+               else
+                       clear_bit(FLAG_ROLE_SWITCH, &chan->flags);
+
+               if (opt & L2CAP_LM_RELIABLE)
+                       set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
+               else
+                       clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
                break;
 
        default:
@@ -658,7 +676,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        }
                }
 
-               chan->flushable = opt;
+               if (opt)
+                       set_bit(FLAG_FLUSHABLE, &chan->flags);
+               else
+                       clear_bit(FLAG_FLUSHABLE, &chan->flags);
                break;
 
        case BT_POWER:
@@ -675,7 +696,36 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        err = -EFAULT;
                        break;
                }
-               chan->force_active = pwr.force_active;
+
+               if (pwr.force_active)
+                       set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+               else
+                       clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+               break;
+
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (chan->mode != L2CAP_MODE_ERTM &&
+                               chan->mode != L2CAP_MODE_STREAMING) {
+                       err = -EOPNOTSUPP;
+                       break;
+               }
+
+               chan->chan_policy = (u8) opt;
                break;
 
        default:
@@ -709,7 +759,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                return -ENOTCONN;
        }
 
-       err = l2cap_chan_send(chan, msg, len);
+       err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
 
        release_sock(sk);
        return err;
@@ -931,11 +981,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->fcs  = pchan->fcs;
                chan->max_tx = pchan->max_tx;
                chan->tx_win = pchan->tx_win;
+               chan->tx_win_max = pchan->tx_win_max;
                chan->sec_level = pchan->sec_level;
-               chan->role_switch = pchan->role_switch;
-               chan->force_reliable = pchan->force_reliable;
-               chan->flushable = pchan->flushable;
-               chan->force_active = pchan->force_active;
+               chan->flags = pchan->flags;
 
                security_sk_clone(parent, sk);
        } else {
@@ -964,12 +1012,10 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->max_tx = L2CAP_DEFAULT_MAX_TX;
                chan->fcs  = L2CAP_FCS_CRC16;
                chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+               chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
                chan->sec_level = BT_SECURITY_LOW;
-               chan->role_switch = 0;
-               chan->force_reliable = 0;
-               chan->flushable = BT_FLUSHABLE_OFF;
-               chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
-
+               chan->flags = 0;
+               set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
        }
 
        /* Default config options */
index 2c76342968660f97a1911783f26d60a7a96b715a..94739d3c4f59ccabb5ed378c6795150a85c60c79 100644 (file)
 #define MGMT_VERSION   0
 #define MGMT_REVISION  1
 
+#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
+
 struct pending_cmd {
        struct list_head list;
-       __u16 opcode;
+       u16 opcode;
        int index;
        void *param;
        struct sock *sk;
        void *user_data;
 };
 
-static LIST_HEAD(cmd_list);
-
 static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_status *ev;
+       int err;
 
        BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
 
@@ -66,10 +67,11 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
        ev->status = status;
        put_unaligned_le16(cmd, &ev->opcode);
 
-       if (sock_queue_rcv_skb(sk, skb) < 0)
+       err = sock_queue_rcv_skb(sk, skb);
+       if (err < 0)
                kfree_skb(skb);
 
-       return 0;
+       return err;
 }
 
 static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
@@ -78,6 +80,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_complete *ev;
+       int err;
 
        BT_DBG("sock %p", sk);
 
@@ -97,10 +100,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        if (rp)
                memcpy(ev->data, rp, rp_len);
 
-       if (sock_queue_rcv_skb(sk, skb) < 0)
+       err = sock_queue_rcv_skb(sk, skb);
+       if (err < 0)
                kfree_skb(skb);
 
-       return 0;
+       return err;;
 }
 
 static int read_version(struct sock *sk)
@@ -120,6 +124,7 @@ static int read_index_list(struct sock *sk)
 {
        struct mgmt_rp_read_index_list *rp;
        struct list_head *p;
+       struct hci_dev *d;
        size_t rp_len;
        u16 count;
        int i, err;
@@ -143,10 +148,9 @@ static int read_index_list(struct sock *sk)
        put_unaligned_le16(count, &rp->num_controllers);
 
        i = 0;
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
-               hci_del_off_timer(d);
+       list_for_each_entry(d, &hci_dev_list, list) {
+               if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
+                       cancel_delayed_work(&d->power_off);
 
                if (test_bit(HCI_SETUP, &d->flags))
                        continue;
@@ -176,7 +180,8 @@ static int read_controller_info(struct sock *sk, u16 index)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
 
-       hci_del_off_timer(hdev);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work_sync(&hdev->power_off);
 
        hci_dev_lock_bh(hdev);
 
@@ -221,7 +226,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd)
 }
 
 static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
-                                               u16 index, void *data, u16 len)
+                                                       struct hci_dev *hdev,
+                                                       void *data, u16 len)
 {
        struct pending_cmd *cmd;
 
@@ -230,7 +236,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
                return NULL;
 
        cmd->opcode = opcode;
-       cmd->index = index;
+       cmd->index = hdev->id;
 
        cmd->param = kmalloc(len, GFP_ATOMIC);
        if (!cmd->param) {
@@ -244,48 +250,36 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
        cmd->sk = sk;
        sock_hold(sk);
 
-       list_add(&cmd->list, &cmd_list);
+       list_add(&cmd->list, &hdev->mgmt_pending);
 
        return cmd;
 }
 
-static void mgmt_pending_foreach(u16 opcode, int index,
+static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
                                void (*cb)(struct pending_cmd *cmd, void *data),
                                void *data)
 {
        struct list_head *p, *n;
 
-       list_for_each_safe(p, n, &cmd_list) {
+       list_for_each_safe(p, n, &hdev->mgmt_pending) {
                struct pending_cmd *cmd;
 
                cmd = list_entry(p, struct pending_cmd, list);
 
-               if (cmd->opcode != opcode)
-                       continue;
-
-               if (index >= 0 && cmd->index != index)
+               if (opcode > 0 && cmd->opcode != opcode)
                        continue;
 
                cb(cmd, data);
        }
 }
 
-static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
+static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
 {
-       struct list_head *p;
-
-       list_for_each(p, &cmd_list) {
-               struct pending_cmd *cmd;
-
-               cmd = list_entry(p, struct pending_cmd, list);
-
-               if (cmd->opcode != opcode)
-                       continue;
-
-               if (index >= 0 && cmd->index != index)
-                       continue;
+       struct pending_cmd *cmd;
 
-               return cmd;
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+               if (cmd->opcode == opcode)
+                       return cmd;
        }
 
        return NULL;
@@ -323,12 +317,12 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -337,7 +331,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (cp->val)
                queue_work(hdev->workqueue, &hdev->power_on);
        else
-               queue_work(hdev->workqueue, &hdev->power_off);
+               queue_work(hdev->workqueue, &hdev->power_off.work);
 
        err = 0;
 
@@ -350,7 +344,7 @@ failed:
 static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                                                                        u16 len)
 {
-       struct mgmt_mode *cp;
+       struct mgmt_cp_set_discoverable *cp;
        struct hci_dev *hdev;
        struct pending_cmd *cmd;
        u8 scan;
@@ -374,8 +368,8 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
+                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
                goto failed;
        }
@@ -386,7 +380,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -396,11 +390,16 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
 
        if (cp->val)
                scan |= SCAN_INQUIRY;
+       else
+               cancel_delayed_work(&hdev->discov_off);
 
        err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
+       if (cp->val)
+               hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
+
 failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -435,8 +434,8 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
+                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
                goto failed;
        }
@@ -446,7 +445,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -468,8 +467,8 @@ failed:
        return err;
 }
 
-static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
-                                                       struct sock *skip_sk)
+static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
+                                       u16 data_len, struct sock *skip_sk)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
@@ -482,7 +481,10 @@ static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
 
        hdr = (void *) skb_put(skb, sizeof(*hdr));
        hdr->opcode = cpu_to_le16(event);
-       hdr->index = cpu_to_le16(index);
+       if (hdev)
+               hdr->index = cpu_to_le16(hdev->id);
+       else
+               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
        hdr->len = cpu_to_le16(data_len);
 
        if (data)
@@ -534,7 +536,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
 
        ev.val = cp->val;
 
-       err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
 
 failed:
        hci_dev_unlock_bh(hdev);
@@ -587,7 +589,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
        u16 eir_len = 0;
        u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
        int i, truncated = 0;
-       struct list_head *p;
+       struct bt_uuid *uuid;
        size_t name_len;
 
        name_len = strlen(hdev->dev_name);
@@ -612,8 +614,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
        memset(uuid16_list, 0, sizeof(uuid16_list));
 
        /* Group all UUID16 types */
-       list_for_each(p, &hdev->uuids) {
-               struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
+       list_for_each_entry(uuid, &hdev->uuids, list) {
                u16 uuid16;
 
                uuid16 = get_uuid16(uuid->uuid);
@@ -689,14 +690,11 @@ static int update_eir(struct hci_dev *hdev)
 
 static u8 get_service_classes(struct hci_dev *hdev)
 {
-       struct list_head *p;
+       struct bt_uuid *uuid;
        u8 val = 0;
 
-       list_for_each(p, &hdev->uuids) {
-               struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
-
+       list_for_each_entry(uuid, &hdev->uuids, list)
                val |= uuid->svc_hint;
-       }
 
        return val;
 }
@@ -895,6 +893,9 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        if (err == 0)
                err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
                                                                        0);
+       else
+               cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
+
 
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -902,30 +903,32 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        return err;
 }
 
-static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
+                                                               u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_load_keys *cp;
+       struct mgmt_cp_load_link_keys *cp;
        u16 key_count, expected_len;
        int i;
 
        cp = (void *) data;
 
        if (len < sizeof(*cp))
-               return -EINVAL;
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
 
        key_count = get_unaligned_le16(&cp->key_count);
 
-       expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
+       expected_len = sizeof(*cp) + key_count *
+                                       sizeof(struct mgmt_link_key_info);
        if (expected_len != len) {
-               BT_ERR("load_keys: expected %u bytes, got %u bytes",
+               BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
                                                        len, expected_len);
-               return -EINVAL;
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
        }
 
        hdev = hci_dev_get(index);
        if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
 
        BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
                                                                key_count);
@@ -942,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
                clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
 
        for (i = 0; i < key_count; i++) {
-               struct mgmt_key_info *key = &cp->keys[i];
+               struct mgmt_link_key_info *key = &cp->keys[i];
 
                hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
                                                                key->pin_len);
@@ -954,27 +957,28 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        return 0;
 }
 
-static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
+                                                               u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_remove_key *cp;
+       struct mgmt_cp_remove_keys *cp;
        struct hci_conn *conn;
        int err;
 
        cp = (void *) data;
 
        if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
 
        hdev = hci_dev_get(index);
        if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
 
        hci_dev_lock_bh(hdev);
 
        err = hci_remove_link_key(hdev, &cp->bdaddr);
        if (err < 0) {
-               err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
+               err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
                goto unlock;
        }
 
@@ -1026,7 +1030,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
+       if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
                goto failed;
        }
@@ -1040,7 +1044,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1060,10 +1064,23 @@ failed:
        return err;
 }
 
+static u8 link_to_mgmt(u8 link_type)
+{
+       switch (link_type) {
+       case LE_LINK:
+               return MGMT_ADDR_LE;
+       case ACL_LINK:
+               return MGMT_ADDR_BREDR;
+       default:
+               return MGMT_ADDR_INVALID;
+       }
+}
+
 static int get_connections(struct sock *sk, u16 index)
 {
        struct mgmt_rp_get_connections *rp;
        struct hci_dev *hdev;
+       struct hci_conn *c;
        struct list_head *p;
        size_t rp_len;
        u16 count;
@@ -1082,7 +1099,7 @@ static int get_connections(struct sock *sk, u16 index)
                count++;
        }
 
-       rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
+       rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
        rp = kmalloc(rp_len, GFP_ATOMIC);
        if (!rp) {
                err = -ENOMEM;
@@ -1092,12 +1109,17 @@ static int get_connections(struct sock *sk, u16 index)
        put_unaligned_le16(count, &rp->conn_count);
 
        i = 0;
-       list_for_each(p, &hdev->conn_hash.list) {
-               struct hci_conn *c = list_entry(p, struct hci_conn, list);
-
-               bacpy(&rp->conn[i++], &c->dst);
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
+               bacpy(&rp->addr[i].bdaddr, &c->dst);
+               rp->addr[i].type = link_to_mgmt(c->type);
+               if (rp->addr[i].type == MGMT_ADDR_INVALID)
+                       continue;
+               i++;
        }
 
+       /* Recalculate length in case of filtered SCO connections, etc */
+       rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
+
        err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
 
 unlock:
@@ -1113,7 +1135,7 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index,
        struct pending_cmd *cmd;
        int err;
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
+       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
                                                                sizeof(*cp));
        if (!cmd)
                return -ENOMEM;
@@ -1174,7 +1196,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1265,19 +1287,12 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
 static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
-       struct list_head *p;
-
-       list_for_each(p, &cmd_list) {
-               struct pending_cmd *cmd;
-
-               cmd = list_entry(p, struct pending_cmd, list);
+       struct pending_cmd *cmd;
 
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
                if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
                        continue;
 
-               if (cmd->index != hdev->id)
-                       continue;
-
                if (cmd->user_data != conn)
                        continue;
 
@@ -1310,16 +1325,19 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
 static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
        struct pending_cmd *cmd;
+       struct hci_dev *hdev = conn->hdev;
 
        BT_DBG("status %u", status);
 
+       hci_dev_lock_bh(hdev);
+
        cmd = find_pairing(conn);
-       if (!cmd) {
+       if (!cmd)
                BT_DBG("Unable to find a pending command");
-               return;
-       }
+       else
+               pairing_complete(cmd, status);
 
-       pairing_complete(cmd, status);
+       hci_dev_unlock_bh(hdev);
 }
 
 static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1370,7 +1388,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                hci_conn_put(conn);
@@ -1432,7 +1450,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
+       cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1469,7 +1487,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1515,12 +1533,12 @@ static int read_local_oob_data(struct sock *sk, u16 index)
                goto unlock;
        }
 
-       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
+       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
@@ -1607,8 +1625,6 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
 
 static int start_discovery(struct sock *sk, u16 index)
 {
-       u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       struct hci_cp_inquiry cp;
        struct pending_cmd *cmd;
        struct hci_dev *hdev;
        int err;
@@ -1621,18 +1637,18 @@ static int start_discovery(struct sock *sk, u16 index)
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
+       if (!test_bit(HCI_UP, &hdev->flags)) {
+               err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
+               goto failed;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       memset(&cp, 0, sizeof(cp));
-       memcpy(&cp.lap, lap, 3);
-       cp.length  = 0x08;
-       cp.num_rsp = 0x00;
-
-       err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+       err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -1657,13 +1673,13 @@ static int stop_discovery(struct sock *sk, u16 index)
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+       err = hci_cancel_inquiry(hdev);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -1678,7 +1694,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct pending_cmd *cmd;
        struct mgmt_cp_block_device *cp = (void *) data;
        int err;
 
@@ -1695,23 +1710,13 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
-       if (!cmd) {
-               err = -ENOMEM;
-               goto failed;
-       }
-
        err = hci_blacklist_add(hdev, &cp->bdaddr);
-
        if (err < 0)
                err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
        else
                err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        NULL, 0);
 
-       mgmt_pending_remove(cmd);
-
-failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
@@ -1722,7 +1727,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct pending_cmd *cmd;
        struct mgmt_cp_unblock_device *cp = (void *) data;
        int err;
 
@@ -1739,12 +1743,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
-       if (!cmd) {
-               err = -ENOMEM;
-               goto failed;
-       }
-
        err = hci_blacklist_del(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1753,9 +1751,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                NULL, 0);
 
-       mgmt_pending_remove(cmd);
-
-failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
@@ -1883,11 +1878,11 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        case MGMT_OP_SET_SERVICE_CACHE:
                err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
                break;
-       case MGMT_OP_LOAD_KEYS:
-               err = load_keys(sk, index, buf + sizeof(*hdr), len);
+       case MGMT_OP_LOAD_LINK_KEYS:
+               err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
                break;
-       case MGMT_OP_REMOVE_KEY:
-               err = remove_key(sk, index, buf + sizeof(*hdr), len);
+       case MGMT_OP_REMOVE_KEYS:
+               err = remove_keys(sk, index, buf + sizeof(*hdr), len);
                break;
        case MGMT_OP_DISCONNECT:
                err = disconnect(sk, index, buf + sizeof(*hdr), len);
@@ -1958,14 +1953,26 @@ done:
        return err;
 }
 
-int mgmt_index_added(u16 index)
+static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
 {
-       return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
+       u8 *status = data;
+
+       cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
+       mgmt_pending_remove(cmd);
 }
 
-int mgmt_index_removed(u16 index)
+int mgmt_index_added(struct hci_dev *hdev)
 {
-       return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
+       return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
+}
+
+int mgmt_index_removed(struct hci_dev *hdev)
+{
+       u8 status = ENODEV;
+
+       mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+
+       return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
 }
 
 struct cmd_lookup {
@@ -1993,17 +2000,22 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_free(cmd);
 }
 
-int mgmt_powered(u16 index, u8 powered)
+int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { powered, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
+
+       if (!powered) {
+               u8 status = ENETDOWN;
+               mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+       }
 
        ev.val = powered;
 
-       ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
+       ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
 
        if (match.sk)
                sock_put(match.sk);
@@ -2011,17 +2023,17 @@ int mgmt_powered(u16 index, u8 powered)
        return ret;
 }
 
-int mgmt_discoverable(u16 index, u8 discoverable)
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { discoverable, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
 
        ev.val = discoverable;
 
-       ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
+       ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
                                                                match.sk);
 
        if (match.sk)
@@ -2030,17 +2042,17 @@ int mgmt_discoverable(u16 index, u8 discoverable)
        return ret;
 }
 
-int mgmt_connectable(u16 index, u8 connectable)
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { connectable, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
 
        ev.val = connectable;
 
-       ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
+       ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
 
        if (match.sk)
                sock_put(match.sk);
@@ -2048,9 +2060,23 @@ int mgmt_connectable(u16 index, u8 connectable)
        return ret;
 }
 
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
+{
+       if (scan & SCAN_PAGE)
+               mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
+                                               cmd_status_rsp, &status);
+
+       if (scan & SCAN_INQUIRY)
+               mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
+                                               cmd_status_rsp, &status);
+
+       return 0;
+}
+
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent)
 {
-       struct mgmt_ev_new_key ev;
+       struct mgmt_ev_new_link_key ev;
 
        memset(&ev, 0, sizeof(ev));
 
@@ -2060,17 +2086,17 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
        memcpy(ev.key.val, key->val, 16);
        ev.key.pin_len = key->pin_len;
 
-       return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
 {
-       struct mgmt_ev_connected ev;
+       struct mgmt_addr_info ev;
 
        bacpy(&ev.bdaddr, bdaddr);
-       ev.link_type = link_type;
+       ev.type = link_to_mgmt(link_type);
 
-       return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
 }
 
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
@@ -2089,17 +2115,18 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_remove(cmd);
 }
 
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
-       struct mgmt_ev_disconnected ev;
+       struct mgmt_addr_info ev;
        struct sock *sk = NULL;
        int err;
 
-       mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
+       mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
 
        bacpy(&ev.bdaddr, bdaddr);
+       ev.type = link_to_mgmt(type);
 
-       err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
 
        if (sk)
                sock_put(sk);
@@ -2107,57 +2134,60 @@ int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
        return err;
 }
 
-int mgmt_disconnect_failed(u16 index)
+int mgmt_disconnect_failed(struct hci_dev *hdev)
 {
        struct pending_cmd *cmd;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
+       cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
+       err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
 
        mgmt_pending_remove(cmd);
 
        return err;
 }
 
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                                               u8 status)
 {
        struct mgmt_ev_connect_failed ev;
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(type);
        ev.status = status;
 
-       return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
 {
        struct mgmt_ev_pin_code_request ev;
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.secure = secure;
 
-       return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
+       return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
                                                                        NULL);
 }
 
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
+       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
                                                                sizeof(rp));
 
        mgmt_pending_remove(cmd);
@@ -2165,20 +2195,21 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
        return err;
 }
 
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
+       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
                                                                sizeof(rp));
 
        mgmt_pending_remove(cmd);
@@ -2186,97 +2217,93 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
        return err;
 }
 
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint)
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint)
 {
        struct mgmt_ev_user_confirm_request ev;
 
-       BT_DBG("hci%u", index);
+       BT_DBG("%s", hdev->name);
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.confirm_hint = confirm_hint;
        put_unaligned_le32(value, &ev.value);
 
-       return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
+       return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
                                                                        NULL);
 }
 
-static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
-                                                               u8 opcode)
+static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                       u8 status, u8 opcode)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_user_confirm_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(opcode, index);
+       cmd = mgmt_pending_find(opcode, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
-       err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
+       err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
        return err;
 }
 
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
-       return confirm_reply_complete(index, bdaddr, status,
+       return confirm_reply_complete(hdev, bdaddr, status,
                                                MGMT_OP_USER_CONFIRM_REPLY);
 }
 
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status)
 {
-       return confirm_reply_complete(index, bdaddr, status,
+       return confirm_reply_complete(hdev, bdaddr, status,
                                        MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
 {
        struct mgmt_ev_auth_failed ev;
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.status = status;
 
-       return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
 {
        struct pending_cmd *cmd;
-       struct hci_dev *hdev;
        struct mgmt_cp_set_local_name ev;
        int err;
 
        memset(&ev, 0, sizeof(ev));
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 
-       cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
+       cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
        if (!cmd)
                goto send_event;
 
        if (status) {
-               err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
+               err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
+                                                                       EIO);
                goto failed;
        }
 
-       hdev = hci_dev_get(index);
-       if (hdev) {
-               hci_dev_lock_bh(hdev);
-               update_eir(hdev);
-               hci_dev_unlock_bh(hdev);
-               hci_dev_put(hdev);
-       }
+       update_eir(hdev);
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
                                                                sizeof(ev));
        if (err < 0)
                goto failed;
 
 send_event:
-       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
+       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
                                                        cmd ? cmd->sk : NULL);
 
 failed:
@@ -2285,29 +2312,30 @@ failed:
        return err;
 }
 
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
-                                                               u8 status)
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status)
 {
        struct pending_cmd *cmd;
        int err;
 
-       BT_DBG("hci%u status %u", index, status);
+       BT_DBG("%s status %u", hdev->name, status);
 
-       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
+       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
        if (!cmd)
                return -ENOENT;
 
        if (status) {
-               err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                                       EIO);
+               err = cmd_status(cmd->sk, hdev->id,
+                                       MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
        } else {
                struct mgmt_rp_read_local_oob_data rp;
 
                memcpy(rp.hash, hash, sizeof(rp.hash));
                memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
 
-               err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                       &rp, sizeof(rp));
+               err = cmd_complete(cmd->sk, hdev->id,
+                                               MGMT_OP_READ_LOCAL_OOB_DATA,
+                                               &rp, sizeof(rp));
        }
 
        mgmt_pending_remove(cmd);
@@ -2315,14 +2343,15 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
        return err;
 }
 
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir)
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                       u8 *dev_class, s8 rssi, u8 *eir)
 {
        struct mgmt_ev_device_found ev;
 
        memset(&ev, 0, sizeof(ev));
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(type);
        ev.rssi = rssi;
 
        if (eir)
@@ -2331,10 +2360,10 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
        if (dev_class)
                memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
 
-       return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
 {
        struct mgmt_ev_remote_name ev;
 
@@ -2343,37 +2372,64 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
        bacpy(&ev.bdaddr, bdaddr);
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 
-       return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_discovering(u16 index, u8 discovering)
+int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
 {
-       return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
+       struct pending_cmd *cmd;
+       int err;
+
+       cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       if (!cmd)
+               return -ENOENT;
+
+       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
+       mgmt_pending_remove(cmd);
+
+       return err;
+}
+
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
+{
+       struct pending_cmd *cmd;
+
+       if (discovering)
+               cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       else
+               cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
+
+       if (cmd != NULL) {
+               cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
+               mgmt_pending_remove(cmd);
+       }
+
+       return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
                                                sizeof(discovering), NULL);
 }
 
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_blocked ev;
 
-       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
+       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
 
        bacpy(&ev.bdaddr, bdaddr);
 
-       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
-                                               cmd ? cmd->sk : NULL);
+       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
+                                                       cmd ? cmd->sk : NULL);
 }
 
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_unblocked ev;
 
-       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
+       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
 
        bacpy(&ev.bdaddr, bdaddr);
 
-       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
-                                               cmd ? cmd->sk : NULL);
+       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
+                                                       cmd ? cmd->sk : NULL);
 }
index 4e32e18211f9187d8a98a27772a9ba97f5cf7112..8743f369ed3fac82dc80095eb2df8bf8bf6da1b8 100644 (file)
@@ -65,7 +65,8 @@ static DEFINE_MUTEX(rfcomm_mutex);
 
 static LIST_HEAD(session_list);
 
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+                                                       u32 priority);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
 static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
 static int rfcomm_queue_disc(struct rfcomm_dlc *d);
@@ -377,13 +378,11 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
 static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_dlc *d;
-       struct list_head *p;
 
-       list_for_each(p, &s->dlcs) {
-               d = list_entry(p, struct rfcomm_dlc, list);
+       list_for_each_entry(d, &s->dlcs, list)
                if (d->dlci == dlci)
                        return d;
-       }
+
        return NULL;
 }
 
@@ -749,19 +748,34 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
 }
 
 /* ---- RFCOMM frame sending ---- */
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+                                                       u32 priority)
 {
        struct socket *sock = s->sock;
+       struct sock *sk = sock->sk;
        struct kvec iv = { data, len };
        struct msghdr msg;
 
-       BT_DBG("session %p len %d", s, len);
+       BT_DBG("session %p len %d priority %u", s, len, priority);
+
+       if (sk->sk_priority != priority) {
+               lock_sock(sk);
+               sk->sk_priority = priority;
+               release_sock(sk);
+       }
 
        memset(&msg, 0, sizeof(msg));
 
        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
+static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
+{
+       BT_DBG("%p cmd %u", s, cmd->ctrl);
+
+       return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX);
+}
+
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_cmd cmd;
@@ -773,7 +787,7 @@ static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
@@ -787,7 +801,7 @@ static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
@@ -801,7 +815,7 @@ static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_queue_disc(struct rfcomm_dlc *d)
@@ -815,6 +829,8 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
        if (!skb)
                return -ENOMEM;
 
+       skb->priority = HCI_PRIO_MAX;
+
        cmd = (void *) __skb_put(skb, sizeof(*cmd));
        cmd->addr = d->addr;
        cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
@@ -837,7 +853,7 @@ static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
@@ -862,7 +878,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
@@ -904,7 +920,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
@@ -942,7 +958,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
@@ -969,7 +985,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
@@ -996,7 +1012,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
@@ -1018,7 +1034,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
@@ -1040,7 +1056,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
@@ -1091,7 +1107,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
@@ -1769,7 +1785,8 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
                return skb_queue_len(&d->tx_queue);
 
        while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-               err = rfcomm_send_frame(d->session, skb->data, skb->len);
+               err = rfcomm_send_frame(d->session, skb->data, skb->len,
+                                                       skb->priority);
                if (err < 0) {
                        skb_queue_head(&d->tx_queue, skb);
                        break;
@@ -2120,15 +2137,13 @@ static struct hci_cb rfcomm_cb = {
 static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
 {
        struct rfcomm_session *s;
-       struct list_head *pp, *p;
 
        rfcomm_lock();
 
-       list_for_each(p, &session_list) {
-               s = list_entry(p, struct rfcomm_session, list);
-               list_for_each(pp, &s->dlcs) {
+       list_for_each_entry(s, &session_list, list) {
+               struct rfcomm_dlc *d;
+               list_for_each_entry(d, &s->dlcs, list) {
                        struct sock *sk = s->sock->sk;
-                       struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
 
                        seq_printf(f, "%s %s %ld %d %d %d %d\n",
                                                batostr(&bt_sk(sk)->src),
index 5417f6127323ec0db7cb51d75eb1e643fb8ec339..aea2bdd1510f2b4f083a4581105228b927cde858 100644 (file)
@@ -600,6 +600,8 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        break;
                }
 
+               skb->priority = sk->sk_priority;
+
                err = rfcomm_dlc_send(d, skb);
                if (err < 0) {
                        kfree_skb(skb);
index c258796313e08274c6005e8142ca3304046c5a70..fa8f4de53b997213b05a528434bf5ef14374651d 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/capability.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
+#include <linux/workqueue.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -65,7 +66,7 @@ struct rfcomm_dev {
        struct rfcomm_dlc       *dlc;
        struct tty_struct       *tty;
        wait_queue_head_t       wait;
-       struct tasklet_struct   wakeup_task;
+       struct work_struct      wakeup_task;
 
        struct device           *tty_dev;
 
@@ -81,7 +82,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
-static void rfcomm_tty_wakeup(unsigned long arg);
+static void rfcomm_tty_wakeup(struct work_struct *work);
 
 /* ---- Device functions ---- */
 static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
@@ -133,13 +134,10 @@ static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
-       struct list_head  *p;
 
-       list_for_each(p, &rfcomm_dev_list) {
-               dev = list_entry(p, struct rfcomm_dev, list);
+       list_for_each_entry(dev, &rfcomm_dev_list, list)
                if (dev->id == id)
                        return dev;
-       }
 
        return NULL;
 }
@@ -197,7 +195,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
 
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
-       struct rfcomm_dev *dev;
+       struct rfcomm_dev *dev, *entry;
        struct list_head *head = &rfcomm_dev_list, *p;
        int err = 0;
 
@@ -212,8 +210,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        if (req->dev_id < 0) {
                dev->id = 0;
 
-               list_for_each(p, &rfcomm_dev_list) {
-                       if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
+               list_for_each_entry(entry, &rfcomm_dev_list, list) {
+                       if (entry->id != dev->id)
                                break;
 
                        dev->id++;
@@ -222,9 +220,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        } else {
                dev->id = req->dev_id;
 
-               list_for_each(p, &rfcomm_dev_list) {
-                       struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
-
+               list_for_each_entry(entry, &rfcomm_dev_list, list) {
                        if (entry->id == dev->id) {
                                err = -EADDRINUSE;
                                goto out;
@@ -257,7 +253,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        atomic_set(&dev->opened, 0);
 
        init_waitqueue_head(&dev->wait);
-       tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
+       INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
 
        skb_queue_head_init(&dev->pending);
 
@@ -351,7 +347,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
        struct rfcomm_dev *dev = (void *) skb->sk;
        atomic_sub(skb->truesize, &dev->wmem_alloc);
        if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-               tasklet_schedule(&dev->wakeup_task);
+               queue_work(system_nrt_wq, &dev->wakeup_task);
        rfcomm_dev_put(dev);
 }
 
@@ -455,9 +451,9 @@ static int rfcomm_release_dev(void __user *arg)
 
 static int rfcomm_get_dev_list(void __user *arg)
 {
+       struct rfcomm_dev *dev;
        struct rfcomm_dev_list_req *dl;
        struct rfcomm_dev_info *di;
-       struct list_head *p;
        int n = 0, size, err;
        u16 dev_num;
 
@@ -479,8 +475,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        read_lock_bh(&rfcomm_dev_lock);
 
-       list_for_each(p, &rfcomm_dev_list) {
-               struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
+       list_for_each_entry(dev, &rfcomm_dev_list, list) {
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
                        continue;
                (di + n)->id      = dev->id;
@@ -635,9 +630,10 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
 }
 
 /* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(unsigned long arg)
+static void rfcomm_tty_wakeup(struct work_struct *work)
 {
-       struct rfcomm_dev *dev = (void *) arg;
+       struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
+                                                               wakeup_task);
        struct tty_struct *tty = dev->tty;
        if (!tty)
                return;
@@ -762,7 +758,7 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
                rfcomm_dlc_close(dev->dlc, 0);
 
                clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-               tasklet_kill(&dev->wakeup_task);
+               cancel_work_sync(&dev->wakeup_task);
 
                rfcomm_dlc_lock(dev->dlc);
                tty->driver_data = NULL;
@@ -1155,9 +1151,11 @@ static const struct tty_operations rfcomm_ops = {
 
 int __init rfcomm_init_ttys(void)
 {
+       int error;
+
        rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
        if (!rfcomm_tty_driver)
-               return -1;
+               return -ENOMEM;
 
        rfcomm_tty_driver->owner        = THIS_MODULE;
        rfcomm_tty_driver->driver_name  = "rfcomm";
@@ -1172,10 +1170,11 @@ int __init rfcomm_init_ttys(void)
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
 
-       if (tty_register_driver(rfcomm_tty_driver)) {
+       error = tty_register_driver(rfcomm_tty_driver);
+       if (error) {
                BT_ERR("Can't register RFCOMM TTY driver");
                put_tty_driver(rfcomm_tty_driver);
-               return -1;
+               return error;
        }
 
        BT_INFO("RFCOMM TTY layer initialized");
index 759b63572641012b4c89fa5f48fcf6c68eee6918..94e94ca353848768e5bca28c3364a7b8554acdf3 100644 (file)
@@ -181,7 +181,8 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
        if (!skb)
                return;
 
-       hci_send_acl(conn->hcon, skb, 0);
+       skb->priority = HCI_PRIO_MAX;
+       hci_send_acl(conn->hchan, skb, 0);
 
        mod_timer(&conn->security_timer, jiffies +
                                        msecs_to_jiffies(SMP_TIMEOUT));
index feb77ea7b58ed2308938c4a9bedd8be82394c464..a3754ac262c3158509e2ab985583d56b06e8d62b 100644 (file)
@@ -186,7 +186,8 @@ static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        strcpy(info->bus_info, "N/A");
 }
 
-static u32 br_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t br_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        struct net_bridge *br = netdev_priv(dev);
 
@@ -341,10 +342,10 @@ void br_dev_setup(struct net_device *dev)
        dev->priv_flags = IFF_EBRIDGE;
 
        dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
-                       NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
+                       NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | NETIF_F_LLTX |
                        NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX;
        dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
-                          NETIF_F_GSO_MASK | NETIF_F_NO_CSUM |
+                          NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
                           NETIF_F_HW_VLAN_TX;
 
        br->dev = dev;
index c8e7861b88b02983e0d5ff202de4e6165bb022b8..973813e344283f4ea694ce1c9fdfb7c8397cd74d 100644 (file)
@@ -556,7 +556,7 @@ skip:
        return skb->len;
 }
 
-/* Create new static fdb entry */
+/* Update (create or replace) forwarding database entry */
 static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
                         __u16 state, __u16 flags)
 {
@@ -575,16 +575,21 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
        } else {
                if (flags & NLM_F_EXCL)
                        return -EEXIST;
+       }
+
+       if (fdb_to_nud(fdb) != state) {
+               if (state & NUD_PERMANENT)
+                       fdb->is_local = fdb->is_static = 1;
+               else if (state & NUD_NOARP) {
+                       fdb->is_local = 0;
+                       fdb->is_static = 1;
+               } else
+                       fdb->is_local = fdb->is_static = 0;
 
-               if (flags & NLM_F_REPLACE)
-                       fdb->updated = fdb->used = jiffies;
-               fdb->is_local = fdb->is_static = 0;
+               fdb->updated = fdb->used = jiffies;
+               fdb_notify(fdb, RTM_NEWNEIGH);
        }
 
-       if (state & NUD_PERMANENT)
-               fdb->is_local = fdb->is_static = 1;
-       else if (state & NUD_NOARP)
-               fdb->is_static = 1;
        return 0;
 }
 
@@ -627,6 +632,11 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                return -EINVAL;
        }
 
+       if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
+               pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
+               return -EINVAL;
+       }
+
        p = br_port_get_rtnl(dev);
        if (p == NULL) {
                pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
@@ -634,9 +644,15 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                return -EINVAL;
        }
 
-       spin_lock_bh(&p->br->hash_lock);
-       err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
-       spin_unlock_bh(&p->br->hash_lock);
+       if (ndm->ndm_flags & NTF_USE) {
+               rcu_read_lock();
+               br_fdb_update(p->br, p, addr);
+               rcu_read_unlock();
+       } else {
+               spin_lock_bh(&p->br->hash_lock);
+               err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
+               spin_unlock_bh(&p->br->hash_lock);
+       }
 
        return err;
 }
index f603e5b0b9309cf24df5af863d40431ad6ee201c..0a942fbccc9a64592d486199608e6527ebc8de8f 100644 (file)
@@ -296,10 +296,11 @@ int br_min_mtu(const struct net_bridge *br)
 /*
  * Recomputes features using slave's features
  */
-u32 br_features_recompute(struct net_bridge *br, u32 features)
+netdev_features_t br_features_recompute(struct net_bridge *br,
+       netdev_features_t features)
 {
        struct net_bridge_port *p;
-       u32 mask;
+       netdev_features_t mask;
 
        if (list_empty(&br->port_list))
                return features;
index d7d6fb05411f28715615375982cb51fcbd452dd2..4027029aa5e49a42dad2a719fea1f12897a2d947 100644 (file)
@@ -387,7 +387,8 @@ extern int br_add_if(struct net_bridge *br,
 extern int br_del_if(struct net_bridge *br,
              struct net_device *dev);
 extern int br_min_mtu(const struct net_bridge *br);
-extern u32 br_features_recompute(struct net_bridge *br, u32 features);
+extern netdev_features_t br_features_recompute(struct net_bridge *br,
+       netdev_features_t features);
 
 /* br_input.c */
 extern int br_handle_frame_finish(struct sk_buff *skb);
index 6ba50a1e404c4bac04cc7d56718865d5a1749c2f..f7895999614837e525aedd6fe6fc91588fa1f901 100644 (file)
 #include <linux/if_pppox.h>
 #include <linux/ppp_defs.h>
 #include <linux/net_tstamp.h>
+#include <linux/jump_label.h>
 
 #include "net-sysfs.h"
 
@@ -1320,8 +1321,6 @@ EXPORT_SYMBOL(dev_close);
  */
 void dev_disable_lro(struct net_device *dev)
 {
-       u32 flags;
-
        /*
         * If we're trying to disable lro on a vlan device
         * use the underlying physical device instead
@@ -1329,15 +1328,9 @@ void dev_disable_lro(struct net_device *dev)
        if (is_vlan_dev(dev))
                dev = vlan_dev_real_dev(dev);
 
-       if (dev->ethtool_ops && dev->ethtool_ops->get_flags)
-               flags = dev->ethtool_ops->get_flags(dev);
-       else
-               flags = ethtool_op_get_flags(dev);
-
-       if (!(flags & ETH_FLAG_LRO))
-               return;
+       dev->wanted_features &= ~NETIF_F_LRO;
+       netdev_update_features(dev);
 
-       __ethtool_set_flags(dev, flags & ~ETH_FLAG_LRO);
        if (unlikely(dev->features & NETIF_F_LRO))
                netdev_WARN(dev, "failed to disable LRO!\n");
 }
@@ -1449,34 +1442,32 @@ int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
 }
 EXPORT_SYMBOL(call_netdevice_notifiers);
 
-/* When > 0 there are consumers of rx skb time stamps */
-static atomic_t netstamp_needed = ATOMIC_INIT(0);
+static struct jump_label_key netstamp_needed __read_mostly;
 
 void net_enable_timestamp(void)
 {
-       atomic_inc(&netstamp_needed);
+       jump_label_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
 
 void net_disable_timestamp(void)
 {
-       atomic_dec(&netstamp_needed);
+       jump_label_dec(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
 static inline void net_timestamp_set(struct sk_buff *skb)
 {
-       if (atomic_read(&netstamp_needed))
+       skb->tstamp.tv64 = 0;
+       if (static_branch(&netstamp_needed))
                __net_timestamp(skb);
-       else
-               skb->tstamp.tv64 = 0;
 }
 
-static inline void net_timestamp_check(struct sk_buff *skb)
-{
-       if (!skb->tstamp.tv64 && atomic_read(&netstamp_needed))
-               __net_timestamp(skb);
-}
+#define net_timestamp_check(COND, SKB)                 \
+       if (static_branch(&netstamp_needed)) {          \
+               if ((COND) && !(SKB)->tstamp.tv64)      \
+                       __net_timestamp(SKB);           \
+       }                                               \
 
 static int net_hwtstamp_validate(struct ifreq *ifr)
 {
@@ -1923,7 +1914,8 @@ EXPORT_SYMBOL(skb_checksum_help);
  *     It may return NULL if the skb requires no segmentation.  This is
  *     only possible when GSO is used for verifying header integrity.
  */
-struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *skb_gso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
        struct packet_type *ptype;
@@ -1953,9 +1945,9 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, u32 features)
                if (dev && dev->ethtool_ops && dev->ethtool_ops->get_drvinfo)
                        dev->ethtool_ops->get_drvinfo(dev, &info);
 
-               WARN(1, "%s: caps=(0x%lx, 0x%lx) len=%d data_len=%d ip_summed=%d\n",
-                    info.driver, dev ? dev->features : 0L,
-                    skb->sk ? skb->sk->sk_route_caps : 0L,
+               WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d ip_summed=%d\n",
+                    info.driver, dev ? &dev->features : NULL,
+                    skb->sk ? &skb->sk->sk_route_caps : NULL,
                     skb->len, skb->data_len, skb->ip_summed);
 
                if (skb_header_cloned(skb) &&
@@ -2064,7 +2056,7 @@ static void dev_gso_skb_destructor(struct sk_buff *skb)
  *     This function segments the given skb and stores the list of segments
  *     in skb->next.
  */
-static int dev_gso_segment(struct sk_buff *skb, int features)
+static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
 {
        struct sk_buff *segs;
 
@@ -2103,7 +2095,7 @@ static inline void skb_orphan_try(struct sk_buff *skb)
        }
 }
 
-static bool can_checksum_protocol(unsigned long features, __be16 protocol)
+static bool can_checksum_protocol(netdev_features_t features, __be16 protocol)
 {
        return ((features & NETIF_F_GEN_CSUM) ||
                ((features & NETIF_F_V4_CSUM) &&
@@ -2114,7 +2106,8 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
                 protocol == htons(ETH_P_FCOE)));
 }
 
-static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features)
+static netdev_features_t harmonize_features(struct sk_buff *skb,
+       __be16 protocol, netdev_features_t features)
 {
        if (!can_checksum_protocol(features, protocol)) {
                features &= ~NETIF_F_ALL_CSUM;
@@ -2126,10 +2119,10 @@ static u32 harmonize_features(struct sk_buff *skb, __be16 protocol, u32 features
        return features;
 }
 
-u32 netif_skb_features(struct sk_buff *skb)
+netdev_features_t netif_skb_features(struct sk_buff *skb)
 {
        __be16 protocol = skb->protocol;
-       u32 features = skb->dev->features;
+       netdev_features_t features = skb->dev->features;
 
        if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
@@ -2175,7 +2168,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
        unsigned int skb_len;
 
        if (likely(!skb->next)) {
-               u32 features;
+               netdev_features_t features;
 
                /*
                 * If device doesn't need skb->dst, release it right now while
@@ -2718,6 +2711,8 @@ EXPORT_SYMBOL(__skb_get_rxhash);
 struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly;
 EXPORT_SYMBOL(rps_sock_flow_table);
 
+struct jump_label_key rps_needed __read_mostly;
+
 static struct rps_dev_flow *
 set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
            struct rps_dev_flow *rflow, u16 next_cpu)
@@ -2997,12 +2992,11 @@ int netif_rx(struct sk_buff *skb)
        if (netpoll_rx(skb))
                return NET_RX_DROP;
 
-       if (netdev_tstamp_prequeue)
-               net_timestamp_check(skb);
+       net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        trace_netif_rx(skb);
 #ifdef CONFIG_RPS
-       {
+       if (static_branch(&rps_needed)) {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
                int cpu;
 
@@ -3017,14 +3011,13 @@ int netif_rx(struct sk_buff *skb)
 
                rcu_read_unlock();
                preempt_enable();
-       }
-#else
+       } else
+#endif
        {
                unsigned int qtail;
                ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
                put_cpu();
        }
-#endif
        return ret;
 }
 EXPORT_SYMBOL(netif_rx);
@@ -3230,8 +3223,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
        int ret = NET_RX_DROP;
        __be16 type;
 
-       if (!netdev_tstamp_prequeue)
-               net_timestamp_check(skb);
+       net_timestamp_check(!netdev_tstamp_prequeue, skb);
 
        trace_netif_receive_skb(skb);
 
@@ -3362,14 +3354,13 @@ out:
  */
 int netif_receive_skb(struct sk_buff *skb)
 {
-       if (netdev_tstamp_prequeue)
-               net_timestamp_check(skb);
+       net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        if (skb_defer_rx_timestamp(skb))
                return NET_RX_SUCCESS;
 
 #ifdef CONFIG_RPS
-       {
+       if (static_branch(&rps_needed)) {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
                int cpu, ret;
 
@@ -3380,16 +3371,12 @@ int netif_receive_skb(struct sk_buff *skb)
                if (cpu >= 0) {
                        ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
                        rcu_read_unlock();
-               } else {
-                       rcu_read_unlock();
-                       ret = __netif_receive_skb(skb);
+                       return ret;
                }
-
-               return ret;
+               rcu_read_unlock();
        }
-#else
-       return __netif_receive_skb(skb);
 #endif
+       return __netif_receive_skb(skb);
 }
 EXPORT_SYMBOL(netif_receive_skb);
 
@@ -5362,7 +5349,8 @@ static void rollback_registered(struct net_device *dev)
        list_del(&single);
 }
 
-static u32 netdev_fix_features(struct net_device *dev, u32 features)
+static netdev_features_t netdev_fix_features(struct net_device *dev,
+       netdev_features_t features)
 {
        /* Fix illegal checksum combinations */
        if ((features & NETIF_F_HW_CSUM) &&
@@ -5371,12 +5359,6 @@ static u32 netdev_fix_features(struct net_device *dev, u32 features)
                features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
        }
 
-       if ((features & NETIF_F_NO_CSUM) &&
-           (features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
-               netdev_warn(dev, "mixed no checksumming and other settings.\n");
-               features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
-       }
-
        /* Fix illegal SG+CSUM combinations. */
        if ((features & NETIF_F_SG) &&
            !(features & NETIF_F_ALL_CSUM)) {
@@ -5424,7 +5406,7 @@ static u32 netdev_fix_features(struct net_device *dev, u32 features)
 
 int __netdev_update_features(struct net_device *dev)
 {
-       u32 features;
+       netdev_features_t features;
        int err = 0;
 
        ASSERT_RTNL();
@@ -5440,16 +5422,16 @@ int __netdev_update_features(struct net_device *dev)
        if (dev->features == features)
                return 0;
 
-       netdev_dbg(dev, "Features changed: 0x%08x -> 0x%08x\n",
-               dev->features, features);
+       netdev_dbg(dev, "Features changed: %pNF -> %pNF\n",
+               &dev->features, &features);
 
        if (dev->netdev_ops->ndo_set_features)
                err = dev->netdev_ops->ndo_set_features(dev, features);
 
        if (unlikely(err < 0)) {
                netdev_err(dev,
-                       "set_features() failed (%d); wanted 0x%08x, left 0x%08x\n",
-                       err, features, dev->features);
+                       "set_features() failed (%d); wanted %pNF, left %pNF\n",
+                       err, &features, &dev->features);
                return -1;
        }
 
@@ -5633,11 +5615,12 @@ int register_netdevice(struct net_device *dev)
        dev->wanted_features = dev->features & dev->hw_features;
 
        /* Turn on no cache copy if HW is doing checksum */
-       dev->hw_features |= NETIF_F_NOCACHE_COPY;
-       if ((dev->features & NETIF_F_ALL_CSUM) &&
-           !(dev->features & NETIF_F_NO_CSUM)) {
-               dev->wanted_features |= NETIF_F_NOCACHE_COPY;
-               dev->features |= NETIF_F_NOCACHE_COPY;
+       if (!(dev->flags & IFF_LOOPBACK)) {
+               dev->hw_features |= NETIF_F_NOCACHE_COPY;
+               if (dev->features & NETIF_F_ALL_CSUM) {
+                       dev->wanted_features |= NETIF_F_NOCACHE_COPY;
+                       dev->features |= NETIF_F_NOCACHE_COPY;
+               }
        }
 
        /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
@@ -6373,7 +6356,8 @@ static int dev_cpu_callback(struct notifier_block *nfb,
  *     @one to the master device with current feature set @all.  Will not
  *     enable anything that is off in @mask. Returns the new feature set.
  */
-u32 netdev_increment_features(u32 all, u32 one, u32 mask)
+netdev_features_t netdev_increment_features(netdev_features_t all,
+       netdev_features_t one, netdev_features_t mask)
 {
        if (mask & NETIF_F_GEN_CSUM)
                mask |= NETIF_F_ALL_CSUM;
@@ -6382,10 +6366,6 @@ u32 netdev_increment_features(u32 all, u32 one, u32 mask)
        all |= one & (NETIF_F_ONE_FOR_ALL|NETIF_F_ALL_CSUM) & mask;
        all &= one | ~NETIF_F_ALL_FOR_ALL;
 
-       /* If device needs checksumming, downgrade to it. */
-       if (all & (NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM))
-               all &= ~NETIF_F_NO_CSUM;
-
        /* If one device supports hw checksumming, set for all. */
        if (all & NETIF_F_GEN_CSUM)
                all &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_GEN_CSUM);
index f444817071245006200ba882a2f085ee43ae3773..31b0b7f5383e19ea70daf121658a2463b12f9cb0 100644 (file)
@@ -36,235 +36,44 @@ u32 ethtool_op_get_link(struct net_device *dev)
 }
 EXPORT_SYMBOL(ethtool_op_get_link);
 
-u32 ethtool_op_get_tx_csum(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_ALL_CSUM) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_tx_csum);
-
-int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_IP_CSUM;
-       else
-               dev->features &= ~NETIF_F_IP_CSUM;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_csum);
-
-int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_HW_CSUM;
-       else
-               dev->features &= ~NETIF_F_HW_CSUM;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
-
-int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-       else
-               dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
-
-u32 ethtool_op_get_sg(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_SG) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_sg);
-
-int ethtool_op_set_sg(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_SG;
-       else
-               dev->features &= ~NETIF_F_SG;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_sg);
-
-u32 ethtool_op_get_tso(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_TSO) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_tso);
-
-int ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_TSO;
-       else
-               dev->features &= ~NETIF_F_TSO;
-
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_tso);
-
-u32 ethtool_op_get_ufo(struct net_device *dev)
-{
-       return (dev->features & NETIF_F_UFO) != 0;
-}
-EXPORT_SYMBOL(ethtool_op_get_ufo);
-
-int ethtool_op_set_ufo(struct net_device *dev, u32 data)
-{
-       if (data)
-               dev->features |= NETIF_F_UFO;
-       else
-               dev->features &= ~NETIF_F_UFO;
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_ufo);
-
-/* the following list of flags are the same as their associated
- * NETIF_F_xxx values in include/linux/netdevice.h
- */
-static const u32 flags_dup_features =
-       (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |
-        ETH_FLAG_RXHASH);
-
-u32 ethtool_op_get_flags(struct net_device *dev)
-{
-       /* in the future, this function will probably contain additional
-        * handling for flags which are not so easily handled
-        * by a simple masking operation
-        */
-
-       return dev->features & flags_dup_features;
-}
-EXPORT_SYMBOL(ethtool_op_get_flags);
-
-/* Check if device can enable (or disable) particular feature coded in "data"
- * argument. Flags "supported" describe features that can be toggled by device.
- * If feature can not be toggled, it state (enabled or disabled) must match
- * hardcoded device features state, otherwise flags are marked as invalid.
- */
-bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported)
-{
-       u32 features = dev->features & flags_dup_features;
-       /* "data" can contain only flags_dup_features bits,
-        * see __ethtool_set_flags */
-
-       return (features & ~supported) != (data & ~supported);
-}
-EXPORT_SYMBOL(ethtool_invalid_flags);
-
-int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
-{
-       if (ethtool_invalid_flags(dev, data, supported))
-               return -EINVAL;
-
-       dev->features = ((dev->features & ~flags_dup_features) |
-                        (data & flags_dup_features));
-       return 0;
-}
-EXPORT_SYMBOL(ethtool_op_set_flags);
-
 /* Handlers for each ethtool command */
 
-#define ETHTOOL_DEV_FEATURE_WORDS      1
-
-static void ethtool_get_features_compat(struct net_device *dev,
-       struct ethtool_get_features_block *features)
-{
-       if (!dev->ethtool_ops)
-               return;
-
-       /* getting RX checksum */
-       if (dev->ethtool_ops->get_rx_csum)
-               if (dev->ethtool_ops->get_rx_csum(dev))
-                       features[0].active |= NETIF_F_RXCSUM;
-
-       /* mark legacy-changeable features */
-       if (dev->ethtool_ops->set_sg)
-               features[0].available |= NETIF_F_SG;
-       if (dev->ethtool_ops->set_tx_csum)
-               features[0].available |= NETIF_F_ALL_CSUM;
-       if (dev->ethtool_ops->set_tso)
-               features[0].available |= NETIF_F_ALL_TSO;
-       if (dev->ethtool_ops->set_rx_csum)
-               features[0].available |= NETIF_F_RXCSUM;
-       if (dev->ethtool_ops->set_flags)
-               features[0].available |= flags_dup_features;
-}
-
-static int ethtool_set_feature_compat(struct net_device *dev,
-       int (*legacy_set)(struct net_device *, u32),
-       struct ethtool_set_features_block *features, u32 mask)
-{
-       u32 do_set;
-
-       if (!legacy_set)
-               return 0;
-
-       if (!(features[0].valid & mask))
-               return 0;
-
-       features[0].valid &= ~mask;
-
-       do_set = !!(features[0].requested & mask);
-
-       if (legacy_set(dev, do_set) < 0)
-               netdev_info(dev,
-                       "Legacy feature change (%s) failed for 0x%08x\n",
-                       do_set ? "set" : "clear", mask);
-
-       return 1;
-}
-
-static int ethtool_set_flags_compat(struct net_device *dev,
-       int (*legacy_set)(struct net_device *, u32),
-       struct ethtool_set_features_block *features, u32 mask)
-{
-       u32 value;
-
-       if (!legacy_set)
-               return 0;
-
-       if (!(features[0].valid & mask))
-               return 0;
-
-       value = dev->features & ~features[0].valid;
-       value |= features[0].requested;
-
-       features[0].valid &= ~mask;
-
-       if (legacy_set(dev, value & mask) < 0)
-               netdev_info(dev, "Legacy flags change failed\n");
-
-       return 1;
-}
-
-static int ethtool_set_features_compat(struct net_device *dev,
-       struct ethtool_set_features_block *features)
-{
-       int compat;
-
-       if (!dev->ethtool_ops)
-               return 0;
-
-       compat  = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg,
-               features, NETIF_F_SG);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum,
-               features, NETIF_F_ALL_CSUM);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso,
-               features, NETIF_F_ALL_TSO);
-       compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
-               features, NETIF_F_RXCSUM);
-       compat |= ethtool_set_flags_compat(dev, dev->ethtool_ops->set_flags,
-               features, flags_dup_features);
-
-       return compat;
-}
+#define ETHTOOL_DEV_FEATURE_WORDS      ((NETDEV_FEATURE_COUNT + 31) / 32)
+
+static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
+       [NETIF_F_SG_BIT] =               "tx-scatter-gather",
+       [NETIF_F_IP_CSUM_BIT] =          "tx-checksum-ipv4",
+       [NETIF_F_HW_CSUM_BIT] =          "tx-checksum-ip-generic",
+       [NETIF_F_IPV6_CSUM_BIT] =        "tx-checksum-ipv6",
+       [NETIF_F_HIGHDMA_BIT] =          "highdma",
+       [NETIF_F_FRAGLIST_BIT] =         "tx-scatter-gather-fraglist",
+       [NETIF_F_HW_VLAN_TX_BIT] =       "tx-vlan-hw-insert",
+
+       [NETIF_F_HW_VLAN_RX_BIT] =       "rx-vlan-hw-parse",
+       [NETIF_F_HW_VLAN_FILTER_BIT] =   "rx-vlan-filter",
+       [NETIF_F_VLAN_CHALLENGED_BIT] =  "vlan-challenged",
+       [NETIF_F_GSO_BIT] =              "tx-generic-segmentation",
+       [NETIF_F_LLTX_BIT] =             "tx-lockless",
+       [NETIF_F_NETNS_LOCAL_BIT] =      "netns-local",
+       [NETIF_F_GRO_BIT] =              "rx-gro",
+       [NETIF_F_LRO_BIT] =              "rx-lro",
+
+       [NETIF_F_TSO_BIT] =              "tx-tcp-segmentation",
+       [NETIF_F_UFO_BIT] =              "tx-udp-fragmentation",
+       [NETIF_F_GSO_ROBUST_BIT] =       "tx-gso-robust",
+       [NETIF_F_TSO_ECN_BIT] =          "tx-tcp-ecn-segmentation",
+       [NETIF_F_TSO6_BIT] =             "tx-tcp6-segmentation",
+       [NETIF_F_FSO_BIT] =              "tx-fcoe-segmentation",
+
+       [NETIF_F_FCOE_CRC_BIT] =         "tx-checksum-fcoe-crc",
+       [NETIF_F_SCTP_CSUM_BIT] =        "tx-checksum-sctp",
+       [NETIF_F_FCOE_MTU_BIT] =         "fcoe-mtu",
+       [NETIF_F_NTUPLE_BIT] =           "rx-ntuple-filter",
+       [NETIF_F_RXHASH_BIT] =           "rx-hashing",
+       [NETIF_F_RXCSUM_BIT] =           "rx-checksum",
+       [NETIF_F_NOCACHE_COPY_BIT] =     "tx-nocache-copy",
+       [NETIF_F_LOOPBACK_BIT] =         "loopback",
+};
 
 static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
 {
@@ -272,18 +81,21 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
                .cmd = ETHTOOL_GFEATURES,
                .size = ETHTOOL_DEV_FEATURE_WORDS,
        };
-       struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS] = {
-               {
-                       .available = dev->hw_features,
-                       .requested = dev->wanted_features,
-                       .active = dev->features,
-                       .never_changed = NETIF_F_NEVER_CHANGE,
-               },
-       };
+       struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
        u32 __user *sizeaddr;
        u32 copy_size;
+       int i;
 
-       ethtool_get_features_compat(dev, features);
+       /* in case feature bits run out again */
+       BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
+
+       for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
+               features[i].available = (u32)(dev->hw_features >> (32 * i));
+               features[i].requested = (u32)(dev->wanted_features >> (32 * i));
+               features[i].active = (u32)(dev->features >> (32 * i));
+               features[i].never_changed =
+                       (u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
+       }
 
        sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
        if (get_user(copy_size, sizeaddr))
@@ -305,7 +117,8 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_sfeatures cmd;
        struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
-       int ret = 0;
+       netdev_features_t wanted = 0, valid = 0;
+       int i, ret = 0;
 
        if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
                return -EFAULT;
@@ -317,65 +130,29 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
        if (copy_from_user(features, useraddr, sizeof(features)))
                return -EFAULT;
 
-       if (features[0].valid & ~NETIF_F_ETHTOOL_BITS)
-               return -EINVAL;
+       for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
+               valid |= (netdev_features_t)features[i].valid << (32 * i);
+               wanted |= (netdev_features_t)features[i].requested << (32 * i);
+       }
 
-       if (ethtool_set_features_compat(dev, features))
-               ret |= ETHTOOL_F_COMPAT;
+       if (valid & ~NETIF_F_ETHTOOL_BITS)
+               return -EINVAL;
 
-       if (features[0].valid & ~dev->hw_features) {
-               features[0].valid &= dev->hw_features;
+       if (valid & ~dev->hw_features) {
+               valid &= dev->hw_features;
                ret |= ETHTOOL_F_UNSUPPORTED;
        }
 
-       dev->wanted_features &= ~features[0].valid;
-       dev->wanted_features |= features[0].valid & features[0].requested;
+       dev->wanted_features &= ~valid;
+       dev->wanted_features |= wanted & valid;
        __netdev_update_features(dev);
 
-       if ((dev->wanted_features ^ dev->features) & features[0].valid)
+       if ((dev->wanted_features ^ dev->features) & valid)
                ret |= ETHTOOL_F_WISH;
 
        return ret;
 }
 
-static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GSTRING_LEN] = {
-       /* NETIF_F_SG */              "tx-scatter-gather",
-       /* NETIF_F_IP_CSUM */         "tx-checksum-ipv4",
-       /* NETIF_F_NO_CSUM */         "tx-checksum-unneeded",
-       /* NETIF_F_HW_CSUM */         "tx-checksum-ip-generic",
-       /* NETIF_F_IPV6_CSUM */       "tx-checksum-ipv6",
-       /* NETIF_F_HIGHDMA */         "highdma",
-       /* NETIF_F_FRAGLIST */        "tx-scatter-gather-fraglist",
-       /* NETIF_F_HW_VLAN_TX */      "tx-vlan-hw-insert",
-
-       /* NETIF_F_HW_VLAN_RX */      "rx-vlan-hw-parse",
-       /* NETIF_F_HW_VLAN_FILTER */  "rx-vlan-filter",
-       /* NETIF_F_VLAN_CHALLENGED */ "vlan-challenged",
-       /* NETIF_F_GSO */             "tx-generic-segmentation",
-       /* NETIF_F_LLTX */            "tx-lockless",
-       /* NETIF_F_NETNS_LOCAL */     "netns-local",
-       /* NETIF_F_GRO */             "rx-gro",
-       /* NETIF_F_LRO */             "rx-lro",
-
-       /* NETIF_F_TSO */             "tx-tcp-segmentation",
-       /* NETIF_F_UFO */             "tx-udp-fragmentation",
-       /* NETIF_F_GSO_ROBUST */      "tx-gso-robust",
-       /* NETIF_F_TSO_ECN */         "tx-tcp-ecn-segmentation",
-       /* NETIF_F_TSO6 */            "tx-tcp6-segmentation",
-       /* NETIF_F_FSO */             "tx-fcoe-segmentation",
-       "",
-       "",
-
-       /* NETIF_F_FCOE_CRC */        "tx-checksum-fcoe-crc",
-       /* NETIF_F_SCTP_CSUM */       "tx-checksum-sctp",
-       /* NETIF_F_FCOE_MTU */        "fcoe-mtu",
-       /* NETIF_F_NTUPLE */          "rx-ntuple-filter",
-       /* NETIF_F_RXHASH */          "rx-hashing",
-       /* NETIF_F_RXCSUM */          "rx-checksum",
-       /* NETIF_F_NOCACHE_COPY */    "tx-nocache-copy",
-       /* NETIF_F_LOOPBACK */        "loopback",
-};
-
 static int __ethtool_get_sset_count(struct net_device *dev, int sset)
 {
        const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -402,7 +179,7 @@ static void __ethtool_get_strings(struct net_device *dev,
                ops->get_strings(dev, stringset, data);
 }
 
-static u32 ethtool_get_feature_mask(u32 eth_cmd)
+static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
 {
        /* feature masks of legacy discrete ethtool ops */
 
@@ -433,136 +210,82 @@ static u32 ethtool_get_feature_mask(u32 eth_cmd)
        }
 }
 
-static void *__ethtool_get_one_feature_actor(struct net_device *dev, u32 ethcmd)
-{
-       const struct ethtool_ops *ops = dev->ethtool_ops;
-
-       if (!ops)
-               return NULL;
-
-       switch (ethcmd) {
-       case ETHTOOL_GTXCSUM:
-               return ops->get_tx_csum;
-       case ETHTOOL_GRXCSUM:
-               return ops->get_rx_csum;
-       case ETHTOOL_SSG:
-               return ops->get_sg;
-       case ETHTOOL_STSO:
-               return ops->get_tso;
-       case ETHTOOL_SUFO:
-               return ops->get_ufo;
-       default:
-               return NULL;
-       }
-}
-
-static u32 __ethtool_get_rx_csum_oldbug(struct net_device *dev)
-{
-       return !!(dev->features & NETIF_F_ALL_CSUM);
-}
-
 static int ethtool_get_one_feature(struct net_device *dev,
        char __user *useraddr, u32 ethcmd)
 {
-       u32 mask = ethtool_get_feature_mask(ethcmd);
+       netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
        struct ethtool_value edata = {
                .cmd = ethcmd,
                .data = !!(dev->features & mask),
        };
 
-       /* compatibility with discrete get_ ops */
-       if (!(dev->hw_features & mask)) {
-               u32 (*actor)(struct net_device *);
-
-               actor = __ethtool_get_one_feature_actor(dev, ethcmd);
-
-               /* bug compatibility with old get_rx_csum */
-               if (ethcmd == ETHTOOL_GRXCSUM && !actor)
-                       actor = __ethtool_get_rx_csum_oldbug;
-
-               if (actor)
-                       edata.data = actor(dev);
-       }
-
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
                return -EFAULT;
        return 0;
 }
 
-static int __ethtool_set_tx_csum(struct net_device *dev, u32 data);
-static int __ethtool_set_rx_csum(struct net_device *dev, u32 data);
-static int __ethtool_set_sg(struct net_device *dev, u32 data);
-static int __ethtool_set_tso(struct net_device *dev, u32 data);
-static int __ethtool_set_ufo(struct net_device *dev, u32 data);
-
 static int ethtool_set_one_feature(struct net_device *dev,
        void __user *useraddr, u32 ethcmd)
 {
        struct ethtool_value edata;
-       u32 mask;
+       netdev_features_t mask;
 
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
                return -EFAULT;
 
        mask = ethtool_get_feature_mask(ethcmd);
        mask &= dev->hw_features;
-       if (mask) {
-               if (edata.data)
-                       dev->wanted_features |= mask;
-               else
-                       dev->wanted_features &= ~mask;
+       if (!mask)
+               return -EOPNOTSUPP;
 
-               __netdev_update_features(dev);
-               return 0;
-       }
+       if (edata.data)
+               dev->wanted_features |= mask;
+       else
+               dev->wanted_features &= ~mask;
 
-       /* Driver is not converted to ndo_fix_features or does not
-        * support changing this offload. In the latter case it won't
-        * have corresponding ethtool_ops field set.
-        *
-        * Following part is to be removed after all drivers advertise
-        * their changeable features in netdev->hw_features and stop
-        * using discrete offload setting ops.
-        */
+       __netdev_update_features(dev);
 
-       switch (ethcmd) {
-       case ETHTOOL_STXCSUM:
-               return __ethtool_set_tx_csum(dev, edata.data);
-       case ETHTOOL_SRXCSUM:
-               return __ethtool_set_rx_csum(dev, edata.data);
-       case ETHTOOL_SSG:
-               return __ethtool_set_sg(dev, edata.data);
-       case ETHTOOL_STSO:
-               return __ethtool_set_tso(dev, edata.data);
-       case ETHTOOL_SUFO:
-               return __ethtool_set_ufo(dev, edata.data);
-       default:
-               return -EOPNOTSUPP;
-       }
+       return 0;
+}
+
+#define ETH_ALL_FLAGS    (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
+                         ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
+#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \
+                         NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH)
+
+static u32 __ethtool_get_flags(struct net_device *dev)
+{
+       u32 flags = 0;
+
+       if (dev->features & NETIF_F_LRO)        flags |= ETH_FLAG_LRO;
+       if (dev->features & NETIF_F_HW_VLAN_RX) flags |= ETH_FLAG_RXVLAN;
+       if (dev->features & NETIF_F_HW_VLAN_TX) flags |= ETH_FLAG_TXVLAN;
+       if (dev->features & NETIF_F_NTUPLE)     flags |= ETH_FLAG_NTUPLE;
+       if (dev->features & NETIF_F_RXHASH)     flags |= ETH_FLAG_RXHASH;
+
+       return flags;
 }
 
-int __ethtool_set_flags(struct net_device *dev, u32 data)
+static int __ethtool_set_flags(struct net_device *dev, u32 data)
 {
-       u32 changed;
+       netdev_features_t features = 0, changed;
 
-       if (data & ~flags_dup_features)
+       if (data & ~ETH_ALL_FLAGS)
                return -EINVAL;
 
-       /* legacy set_flags() op */
-       if (dev->ethtool_ops->set_flags) {
-               if (unlikely(dev->hw_features & flags_dup_features))
-                       netdev_warn(dev,
-                               "driver BUG: mixed hw_features and set_flags()\n");
-               return dev->ethtool_ops->set_flags(dev, data);
-       }
+       if (data & ETH_FLAG_LRO)        features |= NETIF_F_LRO;
+       if (data & ETH_FLAG_RXVLAN)     features |= NETIF_F_HW_VLAN_RX;
+       if (data & ETH_FLAG_TXVLAN)     features |= NETIF_F_HW_VLAN_TX;
+       if (data & ETH_FLAG_NTUPLE)     features |= NETIF_F_NTUPLE;
+       if (data & ETH_FLAG_RXHASH)     features |= NETIF_F_RXHASH;
 
        /* allow changing only bits set in hw_features */
-       changed = (data ^ dev->features) & flags_dup_features;
+       changed = (features ^ dev->features) & ETH_ALL_FEATURES;
        if (changed & ~dev->hw_features)
                return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
 
        dev->wanted_features =
-               (dev->wanted_features & ~changed) | (data & dev->hw_features);
+               (dev->wanted_features & ~changed) | (features & changed);
 
        __netdev_update_features(dev);
 
@@ -1231,81 +954,6 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
        return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
 }
 
-static int __ethtool_set_sg(struct net_device *dev, u32 data)
-{
-       int err;
-
-       if (!dev->ethtool_ops->set_sg)
-               return -EOPNOTSUPP;
-
-       if (data && !(dev->features & NETIF_F_ALL_CSUM))
-               return -EINVAL;
-
-       if (!data && dev->ethtool_ops->set_tso) {
-               err = dev->ethtool_ops->set_tso(dev, 0);
-               if (err)
-                       return err;
-       }
-
-       if (!data && dev->ethtool_ops->set_ufo) {
-               err = dev->ethtool_ops->set_ufo(dev, 0);
-               if (err)
-                       return err;
-       }
-       return dev->ethtool_ops->set_sg(dev, data);
-}
-
-static int __ethtool_set_tx_csum(struct net_device *dev, u32 data)
-{
-       int err;
-
-       if (!dev->ethtool_ops->set_tx_csum)
-               return -EOPNOTSUPP;
-
-       if (!data && dev->ethtool_ops->set_sg) {
-               err = __ethtool_set_sg(dev, 0);
-               if (err)
-                       return err;
-       }
-
-       return dev->ethtool_ops->set_tx_csum(dev, data);
-}
-
-static int __ethtool_set_rx_csum(struct net_device *dev, u32 data)
-{
-       if (!dev->ethtool_ops->set_rx_csum)
-               return -EOPNOTSUPP;
-
-       if (!data)
-               dev->features &= ~NETIF_F_GRO;
-
-       return dev->ethtool_ops->set_rx_csum(dev, data);
-}
-
-static int __ethtool_set_tso(struct net_device *dev, u32 data)
-{
-       if (!dev->ethtool_ops->set_tso)
-               return -EOPNOTSUPP;
-
-       if (data && !(dev->features & NETIF_F_SG))
-               return -EINVAL;
-
-       return dev->ethtool_ops->set_tso(dev, data);
-}
-
-static int __ethtool_set_ufo(struct net_device *dev, u32 data)
-{
-       if (!dev->ethtool_ops->set_ufo)
-               return -EOPNOTSUPP;
-       if (data && !(dev->features & NETIF_F_SG))
-               return -EINVAL;
-       if (data && !((dev->features & NETIF_F_GEN_CSUM) ||
-               (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
-                       == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)))
-               return -EINVAL;
-       return dev->ethtool_ops->set_ufo(dev, data);
-}
-
 static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 {
        struct ethtool_test test;
@@ -1771,9 +1419,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
                break;
        case ETHTOOL_GFLAGS:
                rc = ethtool_get_value(dev, useraddr, ethcmd,
-                                      (dev->ethtool_ops->get_flags ?
-                                       dev->ethtool_ops->get_flags :
-                                       ethtool_op_get_flags));
+                                       __ethtool_get_flags);
                break;
        case ETHTOOL_SFLAGS:
                rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);
index 039d51e6c284e7ab655319d399b9d40060357dcf..2684794458ca00ff1476e178115fed5a6f56e2b0 100644 (file)
@@ -238,6 +238,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
                                   it to safe state.
                                 */
                                skb_queue_purge(&n->arp_queue);
+                               n->arp_queue_len_bytes = 0;
                                n->output = neigh_blackhole;
                                if (n->nud_state & NUD_VALID)
                                        n->nud_state = NUD_NOARP;
@@ -702,6 +703,7 @@ void neigh_destroy(struct neighbour *neigh)
                printk(KERN_WARNING "Impossible event.\n");
 
        skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
 
        dev_put(neigh->dev);
        neigh_parms_put(neigh->parms);
@@ -842,6 +844,7 @@ static void neigh_invalidate(struct neighbour *neigh)
                write_lock(&neigh->lock);
        }
        skb_queue_purge(&neigh->arp_queue);
+       neigh->arp_queue_len_bytes = 0;
 }
 
 static void neigh_probe(struct neighbour *neigh)
@@ -980,15 +983,20 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
 
        if (neigh->nud_state == NUD_INCOMPLETE) {
                if (skb) {
-                       if (skb_queue_len(&neigh->arp_queue) >=
-                           neigh->parms->queue_len) {
+                       while (neigh->arp_queue_len_bytes + skb->truesize >
+                              neigh->parms->queue_len_bytes) {
                                struct sk_buff *buff;
+
                                buff = __skb_dequeue(&neigh->arp_queue);
+                               if (!buff)
+                                       break;
+                               neigh->arp_queue_len_bytes -= buff->truesize;
                                kfree_skb(buff);
                                NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
                        }
                        skb_dst_force(skb);
                        __skb_queue_tail(&neigh->arp_queue, skb);
+                       neigh->arp_queue_len_bytes += skb->truesize;
                }
                rc = 1;
        }
@@ -1175,6 +1183,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
                        write_lock_bh(&neigh->lock);
                }
                skb_queue_purge(&neigh->arp_queue);
+               neigh->arp_queue_len_bytes = 0;
        }
 out:
        if (update_isrouter) {
@@ -1747,7 +1756,11 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
                NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
 
        NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
-       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
+       NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
+       /* approximative value for deprecated QUEUE_LEN (in packets) */
+       NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
+                   DIV_ROUND_UP(parms->queue_len_bytes,
+                                SKB_TRUESIZE(ETH_FRAME_LEN)));
        NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
        NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
        NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
@@ -1974,7 +1987,11 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 
                        switch (i) {
                        case NDTPA_QUEUE_LEN:
-                               p->queue_len = nla_get_u32(tbp[i]);
+                               p->queue_len_bytes = nla_get_u32(tbp[i]) *
+                                                    SKB_TRUESIZE(ETH_FRAME_LEN);
+                               break;
+                       case NDTPA_QUEUE_LENBYTES:
+                               p->queue_len_bytes = nla_get_u32(tbp[i]);
                                break;
                        case NDTPA_PROXY_QLEN:
                                p->proxy_qlen = nla_get_u32(tbp[i]);
@@ -2635,117 +2652,158 @@ EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
 
-#define NEIGH_VARS_MAX 19
+static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
+                          size_t *lenp, loff_t *ppos)
+{
+       int size, ret;
+       ctl_table tmp = *ctl;
+
+       tmp.data = &size;
+       size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN));
+       ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+       if (write && !ret)
+               *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
+       return ret;
+}
+
+enum {
+       NEIGH_VAR_MCAST_PROBE,
+       NEIGH_VAR_UCAST_PROBE,
+       NEIGH_VAR_APP_PROBE,
+       NEIGH_VAR_RETRANS_TIME,
+       NEIGH_VAR_BASE_REACHABLE_TIME,
+       NEIGH_VAR_DELAY_PROBE_TIME,
+       NEIGH_VAR_GC_STALETIME,
+       NEIGH_VAR_QUEUE_LEN,
+       NEIGH_VAR_QUEUE_LEN_BYTES,
+       NEIGH_VAR_PROXY_QLEN,
+       NEIGH_VAR_ANYCAST_DELAY,
+       NEIGH_VAR_PROXY_DELAY,
+       NEIGH_VAR_LOCKTIME,
+       NEIGH_VAR_RETRANS_TIME_MS,
+       NEIGH_VAR_BASE_REACHABLE_TIME_MS,
+       NEIGH_VAR_GC_INTERVAL,
+       NEIGH_VAR_GC_THRESH1,
+       NEIGH_VAR_GC_THRESH2,
+       NEIGH_VAR_GC_THRESH3,
+       NEIGH_VAR_MAX
+};
 
 static struct neigh_sysctl_table {
        struct ctl_table_header *sysctl_header;
-       struct ctl_table neigh_vars[NEIGH_VARS_MAX];
+       struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
        char *dev_name;
 } neigh_sysctl_template __read_mostly = {
        .neigh_vars = {
-               {
+               [NEIGH_VAR_MCAST_PROBE] = {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_UCAST_PROBE] = {
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_APP_PROBE] = {
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_RETRANS_TIME] = {
                        .procname       = "retrans_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_BASE_REACHABLE_TIME] = {
                        .procname       = "base_reachable_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_DELAY_PROBE_TIME] = {
                        .procname       = "delay_first_probe_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_STALETIME] = {
                        .procname       = "gc_stale_time",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_QUEUE_LEN] = {
                        .procname       = "unres_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
+                       .proc_handler   = proc_unres_qlen,
+               },
+               [NEIGH_VAR_QUEUE_LEN_BYTES] = {
+                       .procname       = "unres_qlen_bytes",
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_PROXY_QLEN] = {
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_ANYCAST_DELAY] = {
                        .procname       = "anycast_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_PROXY_DELAY] = {
                        .procname       = "proxy_delay",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_LOCKTIME] = {
                        .procname       = "locktime",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_userhz_jiffies,
                },
-               {
+               [NEIGH_VAR_RETRANS_TIME_MS] = {
                        .procname       = "retrans_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
                },
-               {
+               [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
                        .procname       = "base_reachable_time_ms",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_ms_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_INTERVAL] = {
                        .procname       = "gc_interval",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec_jiffies,
                },
-               {
+               [NEIGH_VAR_GC_THRESH1] = {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
-               {
+               [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
@@ -2778,47 +2836,49 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        if (!t)
                goto err;
 
-       t->neigh_vars[0].data  = &p->mcast_probes;
-       t->neigh_vars[1].data  = &p->ucast_probes;
-       t->neigh_vars[2].data  = &p->app_probes;
-       t->neigh_vars[3].data  = &p->retrans_time;
-       t->neigh_vars[4].data  = &p->base_reachable_time;
-       t->neigh_vars[5].data  = &p->delay_probe_time;
-       t->neigh_vars[6].data  = &p->gc_staletime;
-       t->neigh_vars[7].data  = &p->queue_len;
-       t->neigh_vars[8].data  = &p->proxy_qlen;
-       t->neigh_vars[9].data  = &p->anycast_delay;
-       t->neigh_vars[10].data = &p->proxy_delay;
-       t->neigh_vars[11].data = &p->locktime;
-       t->neigh_vars[12].data  = &p->retrans_time;
-       t->neigh_vars[13].data  = &p->base_reachable_time;
+       t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data  = &p->mcast_probes;
+       t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data  = &p->ucast_probes;
+       t->neigh_vars[NEIGH_VAR_APP_PROBE].data  = &p->app_probes;
+       t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data  = &p->retrans_time;
+       t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data  = &p->base_reachable_time;
+       t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data  = &p->delay_probe_time;
+       t->neigh_vars[NEIGH_VAR_GC_STALETIME].data  = &p->gc_staletime;
+       t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data  = &p->queue_len_bytes;
+       t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data  = &p->queue_len_bytes;
+       t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data  = &p->proxy_qlen;
+       t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data  = &p->anycast_delay;
+       t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
+       t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
+       t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data  = &p->retrans_time;
+       t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data  = &p->base_reachable_time;
 
        if (dev) {
                dev_name_source = dev->name;
                /* Terminate the table early */
-               memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
+               memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
+                      sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
        } else {
                dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
-               t->neigh_vars[14].data = (int *)(p + 1);
-               t->neigh_vars[15].data = (int *)(p + 1) + 1;
-               t->neigh_vars[16].data = (int *)(p + 1) + 2;
-               t->neigh_vars[17].data = (int *)(p + 1) + 3;
+               t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
+               t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
+               t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
+               t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
        }
 
 
        if (handler) {
                /* RetransTime */
-               t->neigh_vars[3].proc_handler = handler;
-               t->neigh_vars[3].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
                /* ReachableTime */
-               t->neigh_vars[4].proc_handler = handler;
-               t->neigh_vars[4].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
                /* RetransTime (in milliseconds)*/
-               t->neigh_vars[12].proc_handler = handler;
-               t->neigh_vars[12].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
                /* ReachableTime (in milliseconds) */
-               t->neigh_vars[13].proc_handler = handler;
-               t->neigh_vars[13].extra1 = dev;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
        }
 
        t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
index c71c434a4c053e440dc816682d944c521e05c50f..db6c2f83633f346552a56bf24db80e55d4184159 100644 (file)
@@ -606,9 +606,12 @@ static ssize_t store_rps_map(struct netdev_rx_queue *queue,
        rcu_assign_pointer(queue->rps_map, map);
        spin_unlock(&rps_map_lock);
 
-       if (old_map)
+       if (map)
+               jump_label_inc(&rps_needed);
+       if (old_map) {
                kfree_rcu(old_map, rcu);
-
+               jump_label_dec(&rps_needed);
+       }
        free_cpumask_var(mask);
        return len;
 }
@@ -780,7 +783,7 @@ net_rx_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
 #endif
 }
 
-#ifdef CONFIG_XPS
+#ifdef CONFIG_SYSFS
 /*
  * netdev_queue sysfs structures and functions.
  */
@@ -826,6 +829,23 @@ static const struct sysfs_ops netdev_queue_sysfs_ops = {
        .store = netdev_queue_attr_store,
 };
 
+static ssize_t show_trans_timeout(struct netdev_queue *queue,
+                                 struct netdev_queue_attribute *attribute,
+                                 char *buf)
+{
+       unsigned long trans_timeout;
+
+       spin_lock_irq(&queue->_xmit_lock);
+       trans_timeout = queue->trans_timeout;
+       spin_unlock_irq(&queue->_xmit_lock);
+
+       return sprintf(buf, "%lu", trans_timeout);
+}
+
+static struct netdev_queue_attribute queue_trans_timeout =
+       __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL);
+
+#ifdef CONFIG_XPS
 static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue)
 {
        struct net_device *dev = queue->dev;
@@ -901,7 +921,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
        struct xps_map *map, *new_map;
        struct xps_dev_maps *dev_maps, *new_dev_maps;
        int nonempty = 0;
-       int numa_node = -2;
+       int numa_node_id = -2;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -944,10 +964,10 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
                need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu);
 #ifdef CONFIG_NUMA
                if (need_set) {
-                       if (numa_node == -2)
-                               numa_node = cpu_to_node(cpu);
-                       else if (numa_node != cpu_to_node(cpu))
-                               numa_node = -1;
+                       if (numa_node_id == -2)
+                               numa_node_id = cpu_to_node(cpu);
+                       else if (numa_node_id != cpu_to_node(cpu))
+                               numa_node_id = -1;
                }
 #endif
                if (need_set && pos >= map_len) {
@@ -997,7 +1017,7 @@ static ssize_t store_xps_map(struct netdev_queue *queue,
        if (dev_maps)
                kfree_rcu(dev_maps, rcu);
 
-       netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node :
+       netdev_queue_numa_node_write(queue, (numa_node_id >= 0) ? numa_node_id :
                                            NUMA_NO_NODE);
 
        mutex_unlock(&xps_map_mutex);
@@ -1020,12 +1040,17 @@ error:
 
 static struct netdev_queue_attribute xps_cpus_attribute =
     __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map);
+#endif /* CONFIG_XPS */
 
 static struct attribute *netdev_queue_default_attrs[] = {
+       &queue_trans_timeout.attr,
+#ifdef CONFIG_XPS
        &xps_cpus_attribute.attr,
+#endif
        NULL
 };
 
+#ifdef CONFIG_XPS
 static void netdev_queue_release(struct kobject *kobj)
 {
        struct netdev_queue *queue = to_netdev_queue(kobj);
@@ -1076,10 +1101,13 @@ static void netdev_queue_release(struct kobject *kobj)
        memset(kobj, 0, sizeof(*kobj));
        dev_put(queue->dev);
 }
+#endif /* CONFIG_XPS */
 
 static struct kobj_type netdev_queue_ktype = {
        .sysfs_ops = &netdev_queue_sysfs_ops,
+#ifdef CONFIG_XPS
        .release = netdev_queue_release,
+#endif
        .default_attrs = netdev_queue_default_attrs,
 };
 
@@ -1102,12 +1130,12 @@ static int netdev_queue_add_kobject(struct net_device *net, int index)
 
        return error;
 }
-#endif /* CONFIG_XPS */
+#endif /* CONFIG_SYSFS */
 
 int
 netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
 {
-#ifdef CONFIG_XPS
+#ifdef CONFIG_SYSFS
        int i;
        int error = 0;
 
@@ -1125,14 +1153,14 @@ netdev_queue_update_kobjects(struct net_device *net, int old_num, int new_num)
        return error;
 #else
        return 0;
-#endif
+#endif /* CONFIG_SYSFS */
 }
 
 static int register_queue_kobjects(struct net_device *net)
 {
        int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0;
 
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        net->queues_kset = kset_create_and_add("queues",
            NULL, &net->dev.kobj);
        if (!net->queues_kset)
@@ -1173,7 +1201,7 @@ static void remove_queue_kobjects(struct net_device *net)
 
        net_rx_queue_update_kobjects(net, real_rx, 0);
        netdev_queue_update_kobjects(net, real_tx, 0);
-#if defined(CONFIG_RPS) || defined(CONFIG_XPS)
+#ifdef CONFIG_SYSFS
        kset_unregister(net->queues_kset);
 #endif
 }
index cf64c1ffa4cd95c3368de492916f0b95ded7ce64..1a7d8e2c9768a767a3a2608e64eabbea20fd48f3 100644 (file)
@@ -422,6 +422,7 @@ static void arp_reply(struct sk_buff *skb)
        struct sk_buff *send_skb;
        struct netpoll *np, *tmp;
        unsigned long flags;
+       int hlen, tlen;
        int hits = 0;
 
        if (list_empty(&npinfo->rx_np))
@@ -479,8 +480,9 @@ static void arp_reply(struct sk_buff *skb)
                if (tip != np->local_ip)
                        continue;
 
-               send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
-                                   LL_RESERVED_SPACE(np->dev));
+               hlen = LL_RESERVED_SPACE(np->dev);
+               tlen = np->dev->needed_tailroom;
+               send_skb = find_skb(np, size + hlen + tlen, hlen);
                if (!send_skb)
                        continue;
 
index 18a3cebb753d39d57b2962f991f32fb048d76c29..7dc05ecf040a374a5c5a1d26af49f73856968bf7 100644 (file)
@@ -244,6 +244,55 @@ nodata:
 }
 EXPORT_SYMBOL(__alloc_skb);
 
+/**
+ * build_skb - build a network buffer
+ * @data: data buffer provided by caller
+ *
+ * Allocate a new &sk_buff. Caller provides space holding head and
+ * skb_shared_info. @data must have been allocated by kmalloc()
+ * The return is the new skb buffer.
+ * On a failure the return is %NULL, and @data is not freed.
+ * Notes :
+ *  Before IO, driver allocates only data buffer where NIC put incoming frame
+ *  Driver should add room at head (NET_SKB_PAD) and
+ *  MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
+ *  After IO, driver calls build_skb(), to allocate sk_buff and populate it
+ *  before giving packet to stack.
+ *  RX rings only contains data buffers, not full skbs.
+ */
+struct sk_buff *build_skb(void *data)
+{
+       struct skb_shared_info *shinfo;
+       struct sk_buff *skb;
+       unsigned int size;
+
+       skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
+       if (!skb)
+               return NULL;
+
+       size = ksize(data) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       memset(skb, 0, offsetof(struct sk_buff, tail));
+       skb->truesize = SKB_TRUESIZE(size);
+       atomic_set(&skb->users, 1);
+       skb->head = data;
+       skb->data = data;
+       skb_reset_tail_pointer(skb);
+       skb->end = skb->tail + size;
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+       skb->mac_header = ~0U;
+#endif
+
+       /* make sure we initialize shinfo sequentially */
+       shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
+       atomic_set(&shinfo->dataref, 1);
+       kmemcheck_annotate_variable(shinfo->destructor_arg);
+
+       return skb;
+}
+EXPORT_SYMBOL(build_skb);
+
 /**
  *     __netdev_alloc_skb - allocate an skbuff for rx on a specific device
  *     @dev: network device to receive on
@@ -2621,7 +2670,7 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
  *     a pointer to the first in a list of new skbs for the segments.
  *     In case of error it returns ERR_PTR(err).
  */
-struct sk_buff *skb_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 {
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
@@ -3169,6 +3218,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
 }
 EXPORT_SYMBOL_GPL(skb_tstamp_tx);
 
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+       struct sock *sk = skb->sk;
+       struct sock_exterr_skb *serr;
+       int err;
+
+       skb->wifi_acked_valid = 1;
+       skb->wifi_acked = acked;
+
+       serr = SKB_EXT_ERR(skb);
+       memset(serr, 0, sizeof(*serr));
+       serr->ee.ee_errno = ENOMSG;
+       serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+
+       err = sock_queue_err_skb(sk, skb);
+       if (err)
+               kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_wifi_ack);
+
 
 /**
  * skb_partial_csum_set - set up and verify partial csum values for packet
index 4ed7b1d12f5ecde5b8c2119c0d4cfaaa765ff470..9a8b3fac14014be42177d93f75d5393929edd16c 100644 (file)
@@ -740,6 +740,11 @@ set_rcvbuf:
        case SO_RXQ_OVFL:
                sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool);
                break;
+
+       case SO_WIFI_STATUS:
+               sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
+               break;
+
        default:
                ret = -ENOPROTOOPT;
                break;
@@ -961,6 +966,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
                break;
 
+       case SO_WIFI_STATUS:
+               v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
@@ -1204,7 +1213,14 @@ void sk_release_kernel(struct sock *sk)
 }
 EXPORT_SYMBOL(sk_release_kernel);
 
-struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
+/**
+ *     sk_clone_lock - clone a socket, and lock its clone
+ *     @sk: the socket to clone
+ *     @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ *
+ *     Caller must unlock socket even in error path (bh_unlock_sock(newsk))
+ */
+struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
 {
        struct sock *newsk;
 
@@ -1297,7 +1313,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 out:
        return newsk;
 }
-EXPORT_SYMBOL_GPL(sk_clone);
+EXPORT_SYMBOL_GPL(sk_clone_lock);
 
 void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
index 77a65f031488b3f222e13d1f071a2d3f44218c70..d05559d4d9cd4bbf5d97bd1ce1f058ef016a8e3a 100644 (file)
@@ -68,8 +68,13 @@ static int rps_sock_flow_sysctl(ctl_table *table, int write,
 
                if (sock_table != orig_sock_table) {
                        rcu_assign_pointer(rps_sock_flow_table, sock_table);
-                       synchronize_rcu();
-                       vfree(orig_sock_table);
+                       if (sock_table)
+                               jump_label_inc(&rps_needed);
+                       if (orig_sock_table) {
+                               jump_label_dec(&rps_needed);
+                               synchronize_rcu();
+                               vfree(orig_sock_table);
+                       }
                }
        }
 
index d7041a0963af9588142133187c28e7c3a9abc215..563b7c74e49de1e443fe2b2a662388635fac0aed 100644 (file)
@@ -100,7 +100,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
         *   (* Generate a new socket and switch to that socket *)
         *   Set S := new socket for this port pair
         */
-       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
+       struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
 
        if (newsk != NULL) {
                struct dccp_request_sock *dreq = dccp_rsk(req);
index 7f0eb087dc116390ebb67aca72295f95d24dcde3..3532ac64c82db980f59a626cda4529a861c1075a 100644 (file)
@@ -107,7 +107,7 @@ struct neigh_table dn_neigh_table = {
                .gc_staletime = 60 * HZ,
                .reachable_time =               30 * HZ,
                .delay_probe_time =     5 * HZ,
-               .queue_len =            3,
+               .queue_len_bytes =      64*1024,
                .ucast_probes = 0,
                .app_probes =           0,
                .mcast_probes = 0,
index 1c1f26c5d672034973187409c94688e59bf03e55..7e717cb35ad15c7437dba106107cf4cebb653a52 100644 (file)
@@ -322,6 +322,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                /* Real hardware Econet.  We're not worthy etc. */
 #ifdef CONFIG_ECONET_NATIVE
                unsigned short proto = 0;
+               int hlen, tlen;
                int res;
 
                if (len + 15 > dev->mtu) {
@@ -331,12 +332,14 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                dev_hold(dev);
 
-               skb = sock_alloc_send_skb(sk, len + LL_ALLOCATED_SPACE(dev),
+               hlen = LL_RESERVED_SPACE(dev);
+               tlen = dev->needed_tailroom;
+               skb = sock_alloc_send_skb(sk, len + hlen + tlen,
                                          msg->msg_flags & MSG_DONTWAIT, &err);
                if (skb == NULL)
                        goto out_unlock;
 
-               skb_reserve(skb, LL_RESERVED_SPACE(dev));
+               skb_reserve(skb, hlen);
                skb_reset_network_header(skb);
 
                eb = (struct ec_cb *)&skb->cb;
index 19d6aefe97d4b9de337d8df3848a4b988bb5a5bd..e4ecc1eef98c3b2aca2b583de283bc7bc7b2f44c 100644 (file)
@@ -50,8 +50,6 @@
  * SUCH DAMAGE.
  */
 
-#define DEBUG
-
 #include <linux/bitops.h>
 #include <linux/if_arp.h>
 #include <linux/module.h>
@@ -113,6 +111,20 @@ struct lowpan_dev_record {
        struct list_head list;
 };
 
+struct lowpan_fragment {
+       struct sk_buff          *skb;           /* skb to be assembled */
+       spinlock_t              lock;           /* concurency lock */
+       u16                     length;         /* length to be assemled */
+       u32                     bytes_rcv;      /* bytes received */
+       u16                     tag;            /* current fragment tag */
+       struct timer_list       timer;          /* assembling timer */
+       struct list_head        list;           /* fragments list */
+};
+
+static unsigned short fragment_tag;
+static LIST_HEAD(lowpan_fragments);
+spinlock_t flist_lock;
+
 static inline struct
 lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
 {
@@ -234,6 +246,50 @@ lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr,
        return 0;
 }
 
+static void
+lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+
+       pr_debug("(%s): UDP header compression\n", __func__);
+
+       if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) ==
+                               LOWPAN_NHC_UDP_4BIT_PORT) &&
+           ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) ==
+                               LOWPAN_NHC_UDP_4BIT_PORT)) {
+               pr_debug("(%s): both ports compression to 4 bits\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
+               **(hc06_ptr + 1) = /* subtraction is faster */
+                  (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) +
+                      ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4));
+               *hc06_ptr += 2;
+       } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("(%s): remove 8 bits of dest\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
+               memcpy(*hc06_ptr + 1, &uh->source, 2);
+               **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT);
+               *hc06_ptr += 4;
+       } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("(%s): remove 8 bits of source\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
+               memcpy(*hc06_ptr + 1, &uh->dest, 2);
+               **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT);
+               *hc06_ptr += 4;
+       } else {
+               pr_debug("(%s): can't compress header\n", __func__);
+               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
+               memcpy(*hc06_ptr + 1, &uh->source, 2);
+               memcpy(*hc06_ptr + 3, &uh->dest, 2);
+               *hc06_ptr += 5;
+       }
+
+       /* checksum is always inline */
+       memcpy(*hc06_ptr, &uh->check, 2);
+       *hc06_ptr += 2;
+}
+
 static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
 {
        u8 ret;
@@ -244,6 +300,73 @@ static u8 lowpan_fetch_skb_u8(struct sk_buff *skb)
        return ret;
 }
 
+static u16 lowpan_fetch_skb_u16(struct sk_buff *skb)
+{
+       u16 ret;
+
+       BUG_ON(!pskb_may_pull(skb, 2));
+
+       ret = skb->data[0] | (skb->data[1] << 8);
+       skb_pull(skb, 2);
+       return ret;
+}
+
+static int
+lowpan_uncompress_udp_header(struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+       u8 tmp;
+
+       tmp = lowpan_fetch_skb_u8(skb);
+
+       if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+               pr_debug("(%s): UDP header uncompression\n", __func__);
+               switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
+               case LOWPAN_NHC_UDP_CS_P_00:
+                       memcpy(&uh->source, &skb->data[0], 2);
+                       memcpy(&uh->dest, &skb->data[2], 2);
+                       skb_pull(skb, 4);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_01:
+                       memcpy(&uh->source, &skb->data[0], 2);
+                       uh->dest =
+                          skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT;
+                       skb_pull(skb, 3);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_10:
+                       uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT;
+                       memcpy(&uh->dest, &skb->data[1], 2);
+                       skb_pull(skb, 3);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_11:
+                       uh->source =
+                          LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4);
+                       uh->dest =
+                          LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f);
+                       skb_pull(skb, 1);
+                       break;
+               default:
+                       pr_debug("(%s) ERROR: unknown UDP format\n", __func__);
+                       goto err;
+                       break;
+               }
+
+               pr_debug("(%s): uncompressed UDP ports: src = %d, dst = %d\n",
+                                       __func__, uh->source, uh->dest);
+
+               /* copy checksum */
+               memcpy(&uh->check, &skb->data[0], 2);
+               skb_pull(skb, 2);
+       } else {
+               pr_debug("(%s): ERROR: unsupported NH format\n", __func__);
+               goto err;
+       }
+
+       return 0;
+err:
+       return -EINVAL;
+}
+
 static int lowpan_header_create(struct sk_buff *skb,
                           struct net_device *dev,
                           unsigned short type, const void *_daddr,
@@ -342,8 +465,6 @@ static int lowpan_header_create(struct sk_buff *skb,
        if (hdr->nexthdr == UIP_PROTO_UDP)
                iphc0 |= LOWPAN_IPHC_NH_C;
 
-/* TODO: next header compression */
-
        if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
                *hc06_ptr = hdr->nexthdr;
                hc06_ptr += 1;
@@ -431,8 +552,9 @@ static int lowpan_header_create(struct sk_buff *skb,
                }
        }
 
-       /* TODO: UDP header compression */
-       /* TODO: Next Header compression */
+       /* UDP header compression */
+       if (hdr->nexthdr == UIP_PROTO_UDP)
+               lowpan_compress_udp_header(&hc06_ptr, skb);
 
        head[0] = iphc0;
        head[1] = iphc1;
@@ -467,6 +589,7 @@ static int lowpan_header_create(struct sk_buff *skb,
                memcpy(&(sa.hwaddr), saddr, 8);
 
                mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+
                return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
                                type, (void *)&da, (void *)&sa, skb->len);
        }
@@ -511,6 +634,21 @@ static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
        return stat;
 }
 
+static void lowpan_fragment_timer_expired(unsigned long entry_addr)
+{
+       struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
+
+       pr_debug("%s: timer expired for frame with tag %d\n", __func__,
+                                                               entry->tag);
+
+       spin_lock(&flist_lock);
+       list_del(&entry->list);
+       spin_unlock(&flist_lock);
+
+       dev_kfree_skb(entry->skb);
+       kfree(entry);
+}
+
 static int
 lowpan_process_data(struct sk_buff *skb)
 {
@@ -525,6 +663,107 @@ lowpan_process_data(struct sk_buff *skb)
        if (skb->len < 2)
                goto drop;
        iphc0 = lowpan_fetch_skb_u8(skb);
+
+       /* fragments assembling */
+       switch (iphc0 & LOWPAN_DISPATCH_MASK) {
+       case LOWPAN_DISPATCH_FRAG1:
+       case LOWPAN_DISPATCH_FRAGN:
+       {
+               struct lowpan_fragment *frame;
+               u8 len, offset;
+               u16 tag;
+               bool found = false;
+
+               len = lowpan_fetch_skb_u8(skb); /* frame length */
+               tag = lowpan_fetch_skb_u16(skb);
+
+               /*
+                * check if frame assembling with the same tag is
+                * already in progress
+                */
+               spin_lock(&flist_lock);
+
+               list_for_each_entry(frame, &lowpan_fragments, list)
+                       if (frame->tag == tag) {
+                               found = true;
+                               break;
+                       }
+
+               /* alloc new frame structure */
+               if (!found) {
+                       frame = kzalloc(sizeof(struct lowpan_fragment),
+                                                               GFP_ATOMIC);
+                       if (!frame)
+                               goto unlock_and_drop;
+
+                       INIT_LIST_HEAD(&frame->list);
+
+                       frame->length = (iphc0 & 7) | (len << 3);
+                       frame->tag = tag;
+
+                       /* allocate buffer for frame assembling */
+                       frame->skb = alloc_skb(frame->length +
+                                       sizeof(struct ipv6hdr), GFP_ATOMIC);
+
+                       if (!frame->skb) {
+                               kfree(frame);
+                               goto unlock_and_drop;
+                       }
+
+                       frame->skb->priority = skb->priority;
+                       frame->skb->dev = skb->dev;
+
+                       /* reserve headroom for uncompressed ipv6 header */
+                       skb_reserve(frame->skb, sizeof(struct ipv6hdr));
+                       skb_put(frame->skb, frame->length);
+
+                       init_timer(&frame->timer);
+                       /* time out is the same as for ipv6 - 60 sec */
+                       frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
+                       frame->timer.data = (unsigned long)frame;
+                       frame->timer.function = lowpan_fragment_timer_expired;
+
+                       add_timer(&frame->timer);
+
+                       list_add_tail(&frame->list, &lowpan_fragments);
+               }
+
+               if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1)
+                       goto unlock_and_drop;
+
+               offset = lowpan_fetch_skb_u8(skb); /* fetch offset */
+
+               /* if payload fits buffer, copy it */
+               if (likely((offset * 8 + skb->len) <= frame->length))
+                       skb_copy_to_linear_data_offset(frame->skb, offset * 8,
+                                                       skb->data, skb->len);
+               else
+                       goto unlock_and_drop;
+
+               frame->bytes_rcv += skb->len;
+
+               /* frame assembling complete */
+               if ((frame->bytes_rcv == frame->length) &&
+                    frame->timer.expires > jiffies) {
+                       /* if timer haven't expired - first of all delete it */
+                       del_timer(&frame->timer);
+                       list_del(&frame->list);
+                       spin_unlock(&flist_lock);
+
+                       dev_kfree_skb(skb);
+                       skb = frame->skb;
+                       kfree(frame);
+                       iphc0 = lowpan_fetch_skb_u8(skb);
+                       break;
+               }
+               spin_unlock(&flist_lock);
+
+               return kfree_skb(skb), 0;
+       }
+       default:
+               break;
+       }
+
        iphc1 = lowpan_fetch_skb_u8(skb);
 
        _saddr = mac_cb(skb)->sa.hwaddr;
@@ -659,7 +898,10 @@ lowpan_process_data(struct sk_buff *skb)
                        goto drop;
        }
 
-       /* TODO: UDP header parse */
+       /* UDP data uncompression */
+       if (iphc0 & LOWPAN_IPHC_NH_C)
+               if (lowpan_uncompress_udp_header(skb))
+                       goto drop;
 
        /* Not fragmented package */
        hdr.payload_len = htons(skb->len);
@@ -674,6 +916,9 @@ lowpan_process_data(struct sk_buff *skb)
        lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
                                                        sizeof(hdr));
        return lowpan_skb_deliver(skb, &hdr);
+
+unlock_and_drop:
+       spin_unlock(&flist_lock);
 drop:
        kfree_skb(skb);
        return -EINVAL;
@@ -692,18 +937,115 @@ static int lowpan_set_address(struct net_device *dev, void *p)
        return 0;
 }
 
+static int lowpan_get_mac_header_length(struct sk_buff *skb)
+{
+       /*
+        * Currently long addressing mode is supported only, so the overall
+        * header size is 21:
+        * FC SeqNum DPAN DA  SA  Sec
+        * 2  +  1  +  2 + 8 + 8 + 0  = 21
+        */
+       return 21;
+}
+
+static int
+lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
+                       int mlen, int plen, int offset)
+{
+       struct sk_buff *frag;
+       int hlen, ret;
+
+       /* if payload length is zero, therefore it's a first fragment */
+       hlen = (plen == 0 ? LOWPAN_FRAG1_HEAD_SIZE :  LOWPAN_FRAGN_HEAD_SIZE);
+
+       lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
+
+       frag = dev_alloc_skb(hlen + mlen + plen + IEEE802154_MFR_SIZE);
+       if (!frag)
+               return -ENOMEM;
+
+       frag->priority = skb->priority;
+       frag->dev = skb->dev;
+
+       /* copy header, MFR and payload */
+       memcpy(skb_put(frag, mlen), skb->data, mlen);
+       memcpy(skb_put(frag, hlen), head, hlen);
+
+       if (plen)
+               skb_copy_from_linear_data_offset(skb, offset + mlen,
+                                       skb_put(frag, plen), plen);
+
+       lowpan_raw_dump_table(__func__, " raw fragment dump", frag->data,
+                                                               frag->len);
+
+       ret = dev_queue_xmit(frag);
+
+       return ret;
+}
+
+static int
+lowpan_skb_fragmentation(struct sk_buff *skb)
+{
+       int  err, header_length, payload_length, tag, offset = 0;
+       u8 head[5];
+
+       header_length = lowpan_get_mac_header_length(skb);
+       payload_length = skb->len - header_length;
+       tag = fragment_tag++;
+
+       /* first fragment header */
+       head[0] = LOWPAN_DISPATCH_FRAG1 | (payload_length & 0x7);
+       head[1] = (payload_length >> 3) & 0xff;
+       head[2] = tag & 0xff;
+       head[3] = tag >> 8;
+
+       err = lowpan_fragment_xmit(skb, head, header_length, 0, 0);
+
+       /* next fragment header */
+       head[0] &= ~LOWPAN_DISPATCH_FRAG1;
+       head[0] |= LOWPAN_DISPATCH_FRAGN;
+
+       while ((payload_length - offset > 0) && (err >= 0)) {
+               int len = LOWPAN_FRAG_SIZE;
+
+               head[4] = offset / 8;
+
+               if (payload_length - offset < len)
+                       len = payload_length - offset;
+
+               err = lowpan_fragment_xmit(skb, head, header_length,
+                                                       len, offset);
+               offset += len;
+       }
+
+       return err;
+}
+
 static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       int err = 0;
+       int err = -1;
 
        pr_debug("(%s): package xmit\n", __func__);
 
        skb->dev = lowpan_dev_info(dev)->real_dev;
        if (skb->dev == NULL) {
                pr_debug("(%s) ERROR: no real wpan device found\n", __func__);
-               dev_kfree_skb(skb);
-       } else
+               goto error;
+       }
+
+       if (skb->len <= IEEE802154_MTU) {
                err = dev_queue_xmit(skb);
+               goto out;
+       }
+
+       pr_debug("(%s): frame is too big, fragmentation is needed\n",
+                                                               __func__);
+       err = lowpan_skb_fragmentation(skb);
+error:
+       dev_kfree_skb(skb);
+out:
+       if (err < 0)
+               pr_debug("(%s): ERROR: xmit failed\n", __func__);
 
        return (err < 0 ? NETDEV_TX_BUSY : NETDEV_TX_OK);
 }
@@ -730,13 +1072,12 @@ static void lowpan_setup(struct net_device *dev)
        dev->addr_len           = IEEE802154_ADDR_LEN;
        memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
        dev->type               = ARPHRD_IEEE802154;
-       dev->features           = NETIF_F_NO_CSUM;
        /* Frame Control + Sequence Number + Address fields + Security Header */
        dev->hard_header_len    = 2 + 1 + 20 + 14;
        dev->needed_tailroom    = 2; /* FCS */
        dev->mtu                = 1281;
        dev->tx_queue_len       = 0;
-       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
        dev->watchdog_timeo     = 0;
 
        dev->netdev_ops         = &lowpan_netdev_ops;
@@ -765,8 +1106,15 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                goto drop;
 
        /* check that it's our buffer */
-       if ((skb->data[0] & 0xe0) == 0x60)
+       switch (skb->data[0] & 0xe0) {
+       case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+       case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
+       case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
                lowpan_process_data(skb);
+               break;
+       default:
+               break;
+       }
 
        return NET_RX_SUCCESS;
 
index 5d8cf80b930dc316e874f67b1b78d690fb89bb03..aeff3f3104821ab3bdead00ed070d5d3fbb5164d 100644 (file)
 #define LOWPAN_DISPATCH_FRAG1  0xc0 /* 11000xxx */
 #define LOWPAN_DISPATCH_FRAGN  0xe0 /* 11100xxx */
 
+#define LOWPAN_DISPATCH_MASK   0xf8 /* 11111000 */
+
+#define LOWPAN_FRAG_TIMEOUT    (HZ * 60)       /* time-out 60 sec */
+
+#define LOWPAN_FRAG1_HEAD_SIZE 0x4
+#define LOWPAN_FRAGN_HEAD_SIZE 0x5
+
+/*
+ * According IEEE802.15.4 standard:
+ *   - MTU is 127 octets
+ *   - maximum MHR size is 37 octets
+ *   - MFR size is 2 octets
+ *
+ * so minimal payload size that we may guarantee is:
+ *   MTU - MHR - MFR = 88 octets
+ */
+#define LOWPAN_FRAG_SIZE       88
+
 /*
  * Values of fields within the IPHC encoding first byte
  * (C stands for compressed and I for inline)
 #define LOWPAN_NHC_UDP_CHECKSUMC       0x04
 #define LOWPAN_NHC_UDP_CHECKSUMI       0x00
 
+#define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
+#define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
+#define LOWPAN_NHC_UDP_8BIT_PORT       0xF000
+#define LOWPAN_NHC_UDP_8BIT_MASK       0xFF00
+
 /* values for port compression, _with checksum_ ie bit 5 set to 0 */
 #define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
 #define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
index faecf648123f7bc9bf5ae7a3913c737a89ea4841..1b09eaabaac1239475e1abab843af353bcccdd4f 100644 (file)
@@ -209,6 +209,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
        unsigned mtu;
        struct sk_buff *skb;
        struct dgram_sock *ro = dgram_sk(sk);
+       int hlen, tlen;
        int err;
 
        if (msg->msg_flags & MSG_OOB) {
@@ -229,13 +230,15 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
        mtu = dev->mtu;
        pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
 
-       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = sock_alloc_send_skb(sk, hlen + tlen + size,
                        msg->msg_flags & MSG_DONTWAIT,
                        &err);
        if (!skb)
                goto out_dev;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
 
index 10970ca85748a2a0835b2a9ac17bf26c66c1e9e2..f96bae8fd330213aec8d58b35531e72486e77a54 100644 (file)
@@ -108,6 +108,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        struct net_device *dev;
        unsigned mtu;
        struct sk_buff *skb;
+       int hlen, tlen;
        int err;
 
        if (msg->msg_flags & MSG_OOB) {
@@ -137,12 +138,14 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                goto out_dev;
        }
 
-       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size,
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = sock_alloc_send_skb(sk, hlen + tlen + size,
                        msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb)
                goto out_dev;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
index 1b5096a9875aae06db3fa9857800881dcc305d31..15dc4c4828deff376dc95d27b34364a266dd13b2 100644 (file)
@@ -1250,7 +1250,8 @@ out:
        return err;
 }
 
-static struct sk_buff *inet_gso_segment(struct sk_buff *skb, u32 features)
+static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct iphdr *iph;
@@ -1572,9 +1573,9 @@ static __net_init int ipv4_mib_init_net(struct net *net)
                          sizeof(struct icmp_mib),
                          __alignof__(struct icmp_mib)) < 0)
                goto err_icmp_mib;
-       if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
-                         sizeof(struct icmpmsg_mib),
-                         __alignof__(struct icmpmsg_mib)) < 0)
+       net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib),
+                                             GFP_KERNEL);
+       if (!net->mib.icmpmsg_statistics)
                goto err_icmpmsg_mib;
 
        tcp_mib_init(net);
@@ -1598,7 +1599,7 @@ err_tcp_mib:
 
 static __net_exit void ipv4_mib_exit_net(struct net *net)
 {
-       snmp_mib_free((void __percpu **)net->mib.icmpmsg_statistics);
+       kfree(net->mib.icmpmsg_statistics);
        snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
        snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
        snmp_mib_free((void __percpu **)net->mib.udp_statistics);
index 96a164aa1367b9c4f48f58c860b4e785261dbd9c..5c29ac5b0c3aab6138a357718792d1a21e25cb98 100644 (file)
@@ -177,7 +177,7 @@ struct neigh_table arp_tbl = {
                .gc_staletime           = 60 * HZ,
                .reachable_time         = 30 * HZ,
                .delay_probe_time       = 5 * HZ,
-               .queue_len              = 3,
+               .queue_len_bytes        = 64*1024,
                .ucast_probes           = 3,
                .mcast_probes           = 3,
                .anycast_delay          = 1 * HZ,
@@ -592,16 +592,18 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
        struct sk_buff *skb;
        struct arphdr *arp;
        unsigned char *arp_ptr;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
 
        /*
         *      Allocate a buffer
         */
 
-       skb = alloc_skb(arp_hdr_len(dev) + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+       skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC);
        if (skb == NULL)
                return NULL;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
        arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
        skb->dev = dev;
index c7472eff2d514b475579d1a3e5a89269d04fce0e..fbc53767bf3508370f8a84204bac3c8094e0f566 100644 (file)
@@ -304,9 +304,11 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        struct igmpv3_report *pig;
        struct net *net = dev_net(dev);
        struct flowi4 fl4;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
 
        while (1) {
-               skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev),
+               skb = alloc_skb(size + hlen + tlen,
                                GFP_ATOMIC | __GFP_NOWARN);
                if (skb)
                        break;
@@ -327,7 +329,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        skb_dst_set(skb, &rt->dst);
        skb->dev = dev;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
        pip = ip_hdr(skb);
@@ -647,6 +649,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        __be32  group = pmc ? pmc->multiaddr : 0;
        struct flowi4 fl4;
        __be32  dst;
+       int hlen, tlen;
 
        if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
                return igmpv3_send_report(in_dev, pmc);
@@ -661,7 +664,9 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        if (IS_ERR(rt))
                return -1;
 
-       skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = alloc_skb(IGMP_SIZE + hlen + tlen, GFP_ATOMIC);
        if (skb == NULL) {
                ip_rt_put(rt);
                return -1;
@@ -669,7 +674,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
 
        skb_dst_set(skb, &rt->dst);
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
index c14d88ad348d3365a11685a59c453d54c4db5332..a598768c616c1f3e3cefa0763f8cf80dcb3effb2 100644 (file)
@@ -588,10 +588,19 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
 }
 EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_prune);
 
-struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
-                           const gfp_t priority)
+/**
+ *     inet_csk_clone_lock - clone an inet socket, and lock its clone
+ *     @sk: the socket to clone
+ *     @req: request_sock
+ *     @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ *
+ *     Caller must unlock socket even in error path (bh_unlock_sock(newsk))
+ */
+struct sock *inet_csk_clone_lock(const struct sock *sk,
+                                const struct request_sock *req,
+                                const gfp_t priority)
 {
-       struct sock *newsk = sk_clone(sk, priority);
+       struct sock *newsk = sk_clone_lock(sk, priority);
 
        if (newsk != NULL) {
                struct inet_connection_sock *newicsk = inet_csk(newsk);
@@ -615,7 +624,7 @@ struct sock *inet_csk_clone(struct sock *sk, const struct request_sock *req,
        }
        return newsk;
 }
-EXPORT_SYMBOL_GPL(inet_csk_clone);
+EXPORT_SYMBOL_GPL(inet_csk_clone_lock);
 
 /*
  * At this point, there should be no process reference to this
index d55110e9312023bdba81a9643b727ada7be06fee..2b32296b7958fc8ac03b64e30f4ed8bfa3c77f0a 100644 (file)
@@ -171,7 +171,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ipgre_get_stats(struct net_device *dev)
 {
@@ -835,6 +835,8 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
        if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
            (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
                struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+               if (max_headroom > dev->needed_headroom)
+                       dev->needed_headroom = max_headroom;
                if (!new_skb) {
                        ip_rt_put(rt);
                        dev->stats.tx_dropped++;
index 09ff51bf16a4c400d84f67caa7137de3678649d3..80d5fa45021042ecf17958f87b252d3047ead364 100644 (file)
 /*
  *     SOL_IP control messages.
  */
+#define PKTINFO_SKB_CB(__skb) ((struct in_pktinfo *)((__skb)->cb))
 
 static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 {
-       struct in_pktinfo info;
-       struct rtable *rt = skb_rtable(skb);
+       struct in_pktinfo info = *PKTINFO_SKB_CB(skb);
 
        info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
-       if (rt) {
-               info.ipi_ifindex = rt->rt_iif;
-               info.ipi_spec_dst.s_addr = rt->rt_spec_dst;
-       } else {
-               info.ipi_ifindex = 0;
-               info.ipi_spec_dst.s_addr = 0;
-       }
 
        put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);
 }
@@ -992,20 +985,28 @@ e_inval:
 }
 
 /**
- * ip_queue_rcv_skb - Queue an skb into sock receive queue
+ * ipv4_pktinfo_prepare - transfert some info from rtable to skb
  * @sk: socket
  * @skb: buffer
  *
- * Queues an skb into socket receive queue. If IP_CMSG_PKTINFO option
- * is not set, we drop skb dst entry now, while dst cache line is hot.
+ * To support IP_CMSG_PKTINFO option, we store rt_iif and rt_spec_dst
+ * in skb->cb[] before dst drop.
+ * This way, receiver doesnt make cache line misses to read rtable.
  */
-int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+void ipv4_pktinfo_prepare(struct sk_buff *skb)
 {
-       if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
-               skb_dst_drop(skb);
-       return sock_queue_rcv_skb(sk, skb);
+       struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb);
+       const struct rtable *rt = skb_rtable(skb);
+
+       if (rt) {
+               pktinfo->ipi_ifindex = rt->rt_iif;
+               pktinfo->ipi_spec_dst.s_addr = rt->rt_spec_dst;
+       } else {
+               pktinfo->ipi_ifindex = 0;
+               pktinfo->ipi_spec_dst.s_addr = 0;
+       }
+       skb_dst_drop(skb);
 }
-EXPORT_SYMBOL(ip_queue_rcv_skb);
 
 int ip_setsockopt(struct sock *sk, int level,
                int optname, char __user *optval, unsigned int optlen)
index 0da2afc97f32ffae2773098391aba0dcbd004903..915eb5265b2e808ed9f3124d031581ab9fe5bb3b 100644 (file)
@@ -763,13 +763,15 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
        struct sk_buff *skb;
        struct bootp_pkt *b;
        struct iphdr *h;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
 
        /* Allocate packet */
-       skb = alloc_skb(sizeof(struct bootp_pkt) + LL_ALLOCATED_SPACE(dev) + 15,
+       skb = alloc_skb(sizeof(struct bootp_pkt) + hlen + tlen + 15,
                        GFP_KERNEL);
        if (!skb)
                return;
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt));
        memset(b, 0, sizeof(struct bootp_pkt));
 
@@ -822,8 +824,13 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
        if (dev_hard_header(skb, dev, ntohs(skb->protocol),
-                           dev->broadcast, dev->dev_addr, skb->len) < 0 ||
-           dev_queue_xmit(skb) < 0)
+                           dev->broadcast, dev->dev_addr, skb->len) < 0) {
+               kfree_skb(skb);
+               printk("E");
+               return;
+       }
+
+       if (dev_queue_xmit(skb) < 0)
                printk("E");
 }
 
index 065effd8349a81689828927c84142a778aebb650..94906908a416dc278b2fb204a3112e0bd7f894dd 100644 (file)
@@ -148,7 +148,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ipip_get_stats(struct net_device *dev)
 {
index 466ea8bb7a4d916e41c838389c7dcaf2b7f01b4a..961eed4f510a26e78d71dcf41fa265a414249dd0 100644 (file)
@@ -288,7 +288,7 @@ static void icmpmsg_put(struct seq_file *seq)
 
        count = 0;
        for (i = 0; i < ICMPMSG_MIB_MAX; i++) {
-               val = snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics, i);
+               val = atomic_long_read(&net->mib.icmpmsg_statistics->mibs[i]);
                if (val) {
                        type[count] = i;
                        vals[count++] = val;
@@ -307,6 +307,7 @@ static void icmp_put(struct seq_file *seq)
 {
        int i;
        struct net *net = seq->private;
+       atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs;
 
        seq_puts(seq, "\nIcmp: InMsgs InErrors");
        for (i=0; icmpmibmap[i].name != NULL; i++)
@@ -319,15 +320,13 @@ static void icmp_put(struct seq_file *seq)
                snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_INERRORS));
        for (i=0; icmpmibmap[i].name != NULL; i++)
                seq_printf(seq, " %lu",
-                       snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
-                               icmpmibmap[i].index));
+                          atomic_long_read(ptr + icmpmibmap[i].index));
        seq_printf(seq, " %lu %lu",
                snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTMSGS),
                snmp_fold_field((void __percpu **) net->mib.icmp_statistics, ICMP_MIB_OUTERRORS));
        for (i=0; icmpmibmap[i].name != NULL; i++)
                seq_printf(seq, " %lu",
-                       snmp_fold_field((void __percpu **) net->mib.icmpmsg_statistics,
-                               icmpmibmap[i].index | 0x100));
+                          atomic_long_read(ptr + (icmpmibmap[i].index | 0x100)));
 }
 
 /*
index 007e2eb769d33ede3afdb4e4fc69c3e9de6db1b4..3ccda5ae8a27b24855c86cf0f3e858c648fc5295 100644 (file)
@@ -292,7 +292,8 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
        /* Charge it to the socket. */
 
-       if (ip_queue_rcv_skb(sk, skb) < 0) {
+       ipv4_pktinfo_prepare(skb);
+       if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -327,6 +328,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
        unsigned int iphlen;
        int err;
        struct rtable *rt = *rtp;
+       int hlen, tlen;
 
        if (length > rt->dst.dev->mtu) {
                ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
@@ -336,12 +338,14 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
        if (flags&MSG_PROBE)
                goto out;
 
+       hlen = LL_RESERVED_SPACE(rt->dst.dev);
+       tlen = rt->dst.dev->needed_tailroom;
        skb = sock_alloc_send_skb(sk,
-                                 length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
+                                 length + hlen + tlen + 15,
                                  flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto error;
-       skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
+       skb_reserve(skb, hlen);
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
index 34f5db1e1c8b85110192c881e17c7fd11c01d633..50c359645665a89e3f0b3b3174a53248a116969e 100644 (file)
@@ -2653,7 +2653,8 @@ int compat_tcp_getsockopt(struct sock *sk, int level, int optname,
 EXPORT_SYMBOL(compat_tcp_getsockopt);
 #endif
 
-struct sk_buff *tcp_tso_segment(struct sk_buff *skb, u32 features)
+struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct tcphdr *th;
index 66363b689ad652586e35ecc49362fee864cf7685..0a7e3398c4616b06189bf6584f749b80dbcf8b57 100644 (file)
@@ -425,7 +425,7 @@ static inline void TCP_ECN_openreq_child(struct tcp_sock *tp,
  */
 struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, struct sk_buff *skb)
 {
-       struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
+       struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC);
 
        if (newsk != NULL) {
                const struct inet_request_sock *ireq = inet_rsk(req);
index ab0966df1e2a8aec9e4ecb40e77332cbebbde466..b867ea23ece92224af4e89777d2f7f6774a383b1 100644 (file)
@@ -1357,7 +1357,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);
 
-       rc = ip_queue_rcv_skb(sk, skb);
+       rc = sock_queue_rcv_skb(sk, skb);
        if (rc < 0) {
                int is_udplite = IS_UDPLITE(sk);
 
@@ -1473,6 +1473,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 
        rc = 0;
 
+       ipv4_pktinfo_prepare(skb);
        bh_lock_sock(sk);
        if (!sock_owned_by_user(sk))
                rc = __udp_queue_rcv_skb(sk, skb);
@@ -2246,7 +2247,8 @@ int udp4_ufo_send_check(struct sk_buff *skb)
        return 0;
 }
 
-struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, u32 features)
+struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        unsigned int mss;
index d27c797f9f05e76b82317d1a73818e0a7557bdf3..ee3319487c4f6b32170f92b68cae95dbed9abd74 100644 (file)
@@ -347,7 +347,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                         */
                        v4addr = LOOPBACK4_IPV6;
                        if (!(addr_type & IPV6_ADDR_MULTICAST)) {
-                               if (!inet->transparent &&
+                               if (!(inet->freebind || inet->transparent) &&
                                    !ipv6_chk_addr(net, &addr->sin6_addr,
                                                   dev, 0)) {
                                        err = -EADDRNOTAVAIL;
@@ -769,7 +769,8 @@ out:
        return err;
 }
 
-static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, u32 features)
+static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct ipv6hdr *ipv6h;
@@ -985,9 +986,9 @@ static int __net_init ipv6_init_mibs(struct net *net)
                          sizeof(struct icmpv6_mib),
                          __alignof__(struct icmpv6_mib)) < 0)
                goto err_icmp_mib;
-       if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics,
-                         sizeof(struct icmpv6msg_mib),
-                         __alignof__(struct icmpv6msg_mib)) < 0)
+       net->mib.icmpv6msg_statistics = kzalloc(sizeof(struct icmpv6msg_mib),
+                                               GFP_KERNEL);
+       if (!net->mib.icmpv6msg_statistics)
                goto err_icmpmsg_mib;
        return 0;
 
@@ -1008,7 +1009,7 @@ static void ipv6_cleanup_mibs(struct net *net)
        snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6);
        snmp_mib_free((void __percpu **)net->mib.ipv6_statistics);
        snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics);
-       snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics);
+       kfree(net->mib.icmpv6msg_statistics);
 }
 
 static int __net_init inet6_net_init(struct net *net)
index e2480691c220a16f93f602ce19266ffb2e7f017f..83037af4fa7b50ddaf680f8d2fa4c339422d863f 100644 (file)
@@ -654,7 +654,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
 
                        if (addr_type != IPV6_ADDR_ANY) {
                                int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;
-                               if (!inet_sk(sk)->transparent &&
+                               if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) &&
                                    !ipv6_chk_addr(net, &src_info->ipi6_addr,
                                                   strict ? dev : NULL, 0))
                                        err = -EINVAL;
index 93718f3db79b3bcacd7bef609978175c68211db3..424f063fb2295cee871e591efe3f43d3f08f3469 100644 (file)
@@ -425,7 +425,8 @@ out:
 
 static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
                                     int addrlen, int plen,
-                                    int offset)
+                                    int offset, int allow_create,
+                                    int replace_required)
 {
        struct fib6_node *fn, *in, *ln;
        struct fib6_node *pn = NULL;
@@ -447,8 +448,18 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
                 *      Prefix match
                 */
                if (plen < fn->fn_bit ||
-                   !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit))
+                   !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) {
+                       if (!allow_create) {
+                               if (replace_required) {
+                                       pr_warn("IPv6: Can't replace route, "
+                                               "no match found\n");
+                                       return ERR_PTR(-ENOENT);
+                               }
+                               pr_warn("IPv6: NLM_F_CREATE should be set "
+                                       "when creating new route\n");
+                       }
                        goto insert_above;
+               }
 
                /*
                 *      Exact match ?
@@ -477,6 +488,23 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr,
                fn = dir ? fn->right: fn->left;
        } while (fn);
 
+       if (!allow_create) {
+               /* We should not create new node because
+                * NLM_F_REPLACE was specified without NLM_F_CREATE
+                * I assume it is safe to require NLM_F_CREATE when
+                * REPLACE flag is used! Later we may want to remove the
+                * check for replace_required, because according
+                * to netlink specification, NLM_F_CREATE
+                * MUST be specified if new route is created.
+                * That would keep IPv6 consistent with IPv4
+                */
+               if (replace_required) {
+                       pr_warn("IPv6: Can't replace route, no match found\n");
+                       return ERR_PTR(-ENOENT);
+               }
+               pr_warn("IPv6: NLM_F_CREATE should be set "
+                       "when creating new route\n");
+       }
        /*
         *      We walked to the bottom of tree.
         *      Create new leaf node without children.
@@ -614,6 +642,11 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 {
        struct rt6_info *iter = NULL;
        struct rt6_info **ins;
+       int replace = (NULL != info->nlh &&
+           (info->nlh->nlmsg_flags&NLM_F_REPLACE));
+       int add = (NULL == info->nlh ||
+           (info->nlh->nlmsg_flags&NLM_F_CREATE));
+       int found = 0;
 
        ins = &fn->leaf;
 
@@ -626,6 +659,13 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                        /*
                         *      Same priority level
                         */
+                       if (NULL != info->nlh &&
+                           (info->nlh->nlmsg_flags&NLM_F_EXCL))
+                               return -EEXIST;
+                       if (replace) {
+                               found++;
+                               break;
+                       }
 
                        if (iter->rt6i_dev == rt->rt6i_dev &&
                            iter->rt6i_idev == rt->rt6i_idev &&
@@ -655,17 +695,40 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
        /*
         *      insert node
         */
+       if (!replace) {
+               if (!add)
+                       pr_warn("IPv6: NLM_F_CREATE should be set when creating new route\n");
+
+add:
+               rt->dst.rt6_next = iter;
+               *ins = rt;
+               rt->rt6i_node = fn;
+               atomic_inc(&rt->rt6i_ref);
+               inet6_rt_notify(RTM_NEWROUTE, rt, info);
+               info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
+
+               if ((fn->fn_flags & RTN_RTINFO) == 0) {
+                       info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
+                       fn->fn_flags |= RTN_RTINFO;
+               }
 
-       rt->dst.rt6_next = iter;
-       *ins = rt;
-       rt->rt6i_node = fn;
-       atomic_inc(&rt->rt6i_ref);
-       inet6_rt_notify(RTM_NEWROUTE, rt, info);
-       info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
-
-       if ((fn->fn_flags & RTN_RTINFO) == 0) {
-               info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
-               fn->fn_flags |= RTN_RTINFO;
+       } else {
+               if (!found) {
+                       if (add)
+                               goto add;
+                       pr_warn("IPv6: NLM_F_REPLACE set, but no existing node found!\n");
+                       return -ENOENT;
+               }
+               *ins = rt;
+               rt->rt6i_node = fn;
+               rt->dst.rt6_next = iter->dst.rt6_next;
+               atomic_inc(&rt->rt6i_ref);
+               inet6_rt_notify(RTM_NEWROUTE, rt, info);
+               rt6_release(iter);
+               if ((fn->fn_flags & RTN_RTINFO) == 0) {
+                       info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
+                       fn->fn_flags |= RTN_RTINFO;
+               }
        }
 
        return 0;
@@ -696,9 +759,25 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
 {
        struct fib6_node *fn, *pn = NULL;
        int err = -ENOMEM;
+       int allow_create = 1;
+       int replace_required = 0;
+       if (NULL != info->nlh) {
+               if (!(info->nlh->nlmsg_flags&NLM_F_CREATE))
+                       allow_create = 0;
+               if ((info->nlh->nlmsg_flags&NLM_F_REPLACE))
+                       replace_required = 1;
+       }
+       if (!allow_create && !replace_required)
+               pr_warn("IPv6: RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n");
 
        fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
-                       rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst));
+                   rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst),
+                   allow_create, replace_required);
+
+       if (IS_ERR(fn)) {
+               err = PTR_ERR(fn);
+               fn = NULL;
+       }
 
        if (fn == NULL)
                goto out;
@@ -736,7 +815,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
 
                        sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
                                        sizeof(struct in6_addr), rt->rt6i_src.plen,
-                                       offsetof(struct rt6_info, rt6i_src));
+                                       offsetof(struct rt6_info, rt6i_src),
+                                       allow_create, replace_required);
 
                        if (sn == NULL) {
                                /* If it is failed, discard just allocated
@@ -753,8 +833,13 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
                } else {
                        sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
                                        sizeof(struct in6_addr), rt->rt6i_src.plen,
-                                       offsetof(struct rt6_info, rt6i_src));
+                                       offsetof(struct rt6_info, rt6i_src),
+                                       allow_create, replace_required);
 
+                       if (IS_ERR(sn)) {
+                               err = PTR_ERR(sn);
+                               sn = NULL;
+                       }
                        if (sn == NULL)
                                goto st_failure;
                }
index 84d0bd5cac939814edaed4379f09464a958d61bf..68ef97f353b65b8d7c2abafb12f272dcc79db32b 100644 (file)
@@ -631,6 +631,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        struct ipv6hdr *tmp_hdr;
        struct frag_hdr *fh;
        unsigned int mtu, hlen, left, len;
+       int hroom, troom;
        __be32 frag_id = 0;
        int ptr, offset = 0, err=0;
        u8 *prevhdr, nexthdr = 0;
@@ -797,6 +798,8 @@ slow_path:
         */
 
        *prevhdr = NEXTHDR_FRAGMENT;
+       hroom = LL_RESERVED_SPACE(rt->dst.dev);
+       troom = rt->dst.dev->needed_tailroom;
 
        /*
         *      Keep copying data until we run out.
@@ -815,7 +818,8 @@ slow_path:
                 *      Allocate buffer.
                 */
 
-               if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_ALLOCATED_SPACE(rt->dst.dev), GFP_ATOMIC)) == NULL) {
+               if ((frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) +
+                                     hroom + troom, GFP_ATOMIC)) == NULL) {
                        NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
                        IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                                      IPSTATS_MIB_FRAGFAILS);
@@ -828,7 +832,7 @@ slow_path:
                 */
 
                ip6_copy_metadata(frag, skb);
-               skb_reserve(frag, LL_RESERVED_SPACE(rt->dst.dev));
+               skb_reserve(frag, hroom);
                skb_put(frag, len + hlen + sizeof(struct frag_hdr));
                skb_reset_network_header(frag);
                fh = (struct frag_hdr *)(skb_network_header(frag) + hlen);
index 4e2e9ff67ef29701d4add34b20a63559aa950b4f..83f0e31c5fbd65663c859dff90e5a00b81bd8a4b 100644 (file)
@@ -93,7 +93,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ip6_get_stats(struct net_device *dev)
 {
index ee7839f4d6e3450c222f2b2677d3b9cf0709d21e..7b94bebb73b198e8abdedd1de88bed78b3104e10 100644 (file)
@@ -1343,13 +1343,15 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
        struct mld2_report *pmr;
        struct in6_addr addr_buf;
        const struct in6_addr *saddr;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
        int err;
        u8 ra[8] = { IPPROTO_ICMPV6, 0,
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
                     IPV6_TLV_PADN, 0 };
 
        /* we assume size > sizeof(ra) here */
-       size += LL_ALLOCATED_SPACE(dev);
+       size += hlen + tlen;
        /* limit our allocations to order-0 page */
        size = min_t(int, size, SKB_MAX_ORDER(0, 0));
        skb = sock_alloc_send_skb(sk, size, 1, &err);
@@ -1357,7 +1359,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
        if (!skb)
                return NULL;
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
@@ -1723,6 +1725,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        struct mld_msg *hdr;
        const struct in6_addr *snd_addr, *saddr;
        struct in6_addr addr_buf;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
        int err, len, payload_len, full_len;
        u8 ra[8] = { IPPROTO_ICMPV6, 0,
                     IPV6_TLV_ROUTERALERT, 2, 0, 0,
@@ -1744,7 +1748,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                      IPSTATS_MIB_OUT, full_len);
        rcu_read_unlock();
 
-       skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + full_len, 1, &err);
+       skb = sock_alloc_send_skb(sk, hlen + tlen + full_len, 1, &err);
 
        if (skb == NULL) {
                rcu_read_lock();
@@ -1754,7 +1758,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                return;
        }
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
 
        if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
index 44e5b7f2a6c1badcbf4dbb5ed2a844ae2daa199c..d699ddcad4cedcfba34ff222ff244c0acf943e62 100644 (file)
@@ -141,7 +141,7 @@ struct neigh_table nd_tbl = {
                .gc_staletime           = 60 * HZ,
                .reachable_time         = ND_REACHABLE_TIME,
                .delay_probe_time       = 5 * HZ,
-               .queue_len              = 3,
+               .queue_len_bytes        = 64*1024,
                .ucast_probes           = 3,
                .mcast_probes           = 3,
                .anycast_delay          = 1 * HZ,
@@ -446,6 +446,8 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
        struct sock *sk = net->ipv6.ndisc_sk;
        struct sk_buff *skb;
        struct icmp6hdr *hdr;
+       int hlen = LL_RESERVED_SPACE(dev);
+       int tlen = dev->needed_tailroom;
        int len;
        int err;
        u8 *opt;
@@ -459,7 +461,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
 
        skb = sock_alloc_send_skb(sk,
                                  (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                  len + LL_ALLOCATED_SPACE(dev)),
+                                  len + hlen + tlen),
                                  1, &err);
        if (!skb) {
                ND_PRINTK0(KERN_ERR
@@ -468,7 +470,7 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
                return NULL;
        }
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len);
 
        skb->transport_header = skb->tail;
@@ -1533,6 +1535,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        struct inet6_dev *idev;
        struct flowi6 fl6;
        u8 *opt;
+       int hlen, tlen;
        int rd_len;
        int err;
        u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
@@ -1590,9 +1593,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        rd_len &= ~0x7;
        len += rd_len;
 
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
        buff = sock_alloc_send_skb(sk,
                                   (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                   len + LL_ALLOCATED_SPACE(dev)),
+                                   len + hlen + tlen),
                                   1, &err);
        if (buff == NULL) {
                ND_PRINTK0(KERN_ERR
@@ -1601,7 +1606,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                goto release;
        }
 
-       skb_reserve(buff, LL_RESERVED_SPACE(dev));
+       skb_reserve(buff, hlen);
        ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
                   IPPROTO_ICMPV6, len);
 
index 1008ce94bc339e5a97405723170ea63d4fed6ba6..fdeb6d03da812d136874fccc870b90c69efee7b1 100644 (file)
@@ -142,11 +142,7 @@ static const struct snmp_mib snmp6_udplite6_list[] = {
        SNMP_MIB_SENTINEL
 };
 
-/* can be called either with percpu mib (pcpumib != NULL),
- * or shared one (smib != NULL)
- */
-static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpumib,
-                                    atomic_long_t *smib)
+static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, atomic_long_t *smib)
 {
        char name[32];
        int i;
@@ -163,14 +159,14 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **pcpum
                snprintf(name, sizeof(name), "Icmp6%s%s",
                        i & 0x100 ? "Out" : "In", p);
                seq_printf(seq, "%-32s\t%lu\n", name,
-                       pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i));
+                          atomic_long_read(smib + i));
        }
 
        /* print by number (nonzero only) - ICMPMsgStat format */
        for (i = 0; i < ICMP6MSG_MIB_MAX; i++) {
                unsigned long val;
 
-               val = pcpumib ? snmp_fold_field(pcpumib, i) : atomic_long_read(smib + i);
+               val = atomic_long_read(smib + i);
                if (!val)
                        continue;
                snprintf(name, sizeof(name), "Icmp6%sType%u",
@@ -215,8 +211,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v)
                            snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp));
        snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics,
                            NULL, snmp6_icmp6_list);
-       snmp6_seq_show_icmpv6msg(seq,
-                           (void __percpu **)net->mib.icmpv6msg_statistics, NULL);
+       snmp6_seq_show_icmpv6msg(seq, net->mib.icmpv6msg_statistics->mibs);
        snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6,
                            NULL, snmp6_udp6_list);
        snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6,
@@ -246,7 +241,7 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v)
                            snmp6_ipstats_list);
        snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs,
                            snmp6_icmp6_list);
-       snmp6_seq_show_icmpv6msg(seq, NULL, idev->stats.icmpv6msgdev->mibs);
+       snmp6_seq_show_icmpv6msg(seq, idev->stats.icmpv6msgdev->mibs);
        return 0;
 }
 
index 331af3b882ac211ca65cb59042f14c381fe2d244..a1aa869a9ce7ef9130b1f434432e0aba776eb867 100644 (file)
@@ -383,7 +383,8 @@ static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
        }
 
        /* Charge it to the socket. */
-       if (ip_queue_rcv_skb(sk, skb) < 0) {
+       skb_dst_drop(skb);
+       if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -610,6 +611,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        struct sk_buff *skb;
        int err;
        struct rt6_info *rt = (struct rt6_info *)*dstp;
+       int hlen = LL_RESERVED_SPACE(rt->dst.dev);
+       int tlen = rt->dst.dev->needed_tailroom;
 
        if (length > rt->dst.dev->mtu) {
                ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
@@ -619,11 +622,11 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
                goto out;
 
        skb = sock_alloc_send_skb(sk,
-                                 length + LL_ALLOCATED_SPACE(rt->dst.dev) + 15,
+                                 length + hlen + tlen + 15,
                                  flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto error;
-       skb_reserve(skb, LL_RESERVED_SPACE(rt->dst.dev));
+       skb_reserve(skb, hlen);
 
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
index 8473016bba4a8cd6ae4dfc420c7827524fc3a84b..05c89be04c9f0ac9a6e3768503448c822a5205bf 100644 (file)
@@ -1230,9 +1230,18 @@ int ip6_route_add(struct fib6_config *cfg)
        if (cfg->fc_metric == 0)
                cfg->fc_metric = IP6_RT_PRIO_USER;
 
-       table = fib6_new_table(net, cfg->fc_table);
+       err = -ENOBUFS;
+       if (NULL != cfg->fc_nlinfo.nlh &&
+           !(cfg->fc_nlinfo.nlh->nlmsg_flags&NLM_F_CREATE)) {
+               table = fib6_get_table(net, cfg->fc_table);
+               if (table == NULL) {
+                       printk(KERN_WARNING "IPv6: NLM_F_CREATE should be specified when creating new route\n");
+                       table = fib6_new_table(net, cfg->fc_table);
+               }
+       } else {
+               table = fib6_new_table(net, cfg->fc_table);
+       }
        if (table == NULL) {
-               err = -ENOBUFS;
                goto out;
        }
 
index a7a18602a046e1ffe5f0f00883844459802f4a25..cec09382282d30e0bd0f606c7caae125ea59f1dc 100644 (file)
@@ -91,7 +91,7 @@ struct pcpu_tstats {
        unsigned long   rx_bytes;
        unsigned long   tx_packets;
        unsigned long   tx_bytes;
-};
+} __attribute__((aligned(4*sizeof(unsigned long))));
 
 static struct net_device_stats *ipip6_get_stats(struct net_device *dev)
 {
index 846f4757eb8d46394a604595be0698d485ae1ab0..ccfb0451b1c310ba04520468dac7efdb8dc5fc4e 100644 (file)
@@ -538,7 +538,9 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                        goto drop;
        }
 
-       if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
+       skb_dst_drop(skb);
+       rc = sock_queue_rcv_skb(sk, skb);
+       if (rc < 0) {
                /* Note that an ENOMEM error is charged twice */
                if (rc == -ENOMEM)
                        UDP6_INC_STATS_BH(sock_net(sk),
@@ -1298,7 +1300,8 @@ static int udp6_ufo_send_check(struct sk_buff *skb)
        return 0;
 }
 
-static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, u32 features)
+static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
+       netdev_features_t features)
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        unsigned int mss;
index 93b2434226592e335568195ccaeaa20e06788d19..476b106c0b1cbcb7e69631e49832c23cb6007816 100644 (file)
@@ -177,7 +177,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
index b3f65520e7a716312adc51d48d8fa9d8e2993c3d..39d72ccaffb3d92b977dfa89e8bc366f39d65830 100644 (file)
@@ -78,7 +78,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
@@ -372,13 +373,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
               pubsta->addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       /*
-        * The aggregation code is not prepared to handle
-        * anything but STA/AP due to the BSSID handling.
-        * IBSS could work in the code but isn't supported
-        * by drivers or the standard.
-        */
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+           sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
            sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
            sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
index d06c65fa5526a88739a647b809067f37fd64fc24..1063a7e57d62a9d2cf68e965e71152c9f1eb3033 100644 (file)
@@ -411,7 +411,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                                BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
                                BIT(NL80211_STA_FLAG_WME) |
                                BIT(NL80211_STA_FLAG_MFP) |
-                               BIT(NL80211_STA_FLAG_AUTHENTICATED);
+                               BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                               BIT(NL80211_STA_FLAG_TDLS_PEER);
        if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
        if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
@@ -422,6 +423,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
        if (test_sta_flag(sta, WLAN_STA_AUTH))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
 }
 
 
@@ -488,6 +491,31 @@ static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
                (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
 }
 
+static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
+                                   u8 *resp, size_t resp_len)
+{
+       struct sk_buff *new, *old;
+
+       if (!resp || !resp_len)
+               return -EINVAL;
+
+       old = sdata->u.ap.probe_resp;
+
+       new = dev_alloc_skb(resp_len);
+       if (!new)
+               return -ENOMEM;
+
+       memcpy(skb_put(new, resp_len), resp, resp_len);
+
+       rcu_assign_pointer(sdata->u.ap.probe_resp, new);
+       synchronize_rcu();
+
+       if (old)
+               dev_kfree_skb(old);
+
+       return 0;
+}
+
 /*
  * This handles both adding a beacon and setting new beacon info
  */
@@ -498,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
        int new_head_len, new_tail_len;
        int size;
        int err = -EINVAL;
+       u32 changed = 0;
 
        old = rtnl_dereference(sdata->u.ap.beacon);
 
@@ -581,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        kfree(old);
 
+       err = ieee80211_set_probe_resp(sdata, params->probe_resp,
+                                      params->probe_resp_len);
+       if (!err)
+               changed |= BSS_CHANGED_AP_PROBE_RESP;
+
        ieee80211_config_ap_ssid(sdata, params);
+       changed |= BSS_CHANGED_BEACON_ENABLED |
+                  BSS_CHANGED_BEACON |
+                  BSS_CHANGED_SSID;
 
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
-                                               BSS_CHANGED_BEACON |
-                                               BSS_CHANGED_SSID);
+       ieee80211_bss_info_change_notify(sdata, changed);
        return 0;
 }
 
@@ -594,6 +629,8 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
+       struct ieee80211_sub_if_data *vlan;
+       int ret;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -601,7 +638,24 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
        if (old)
                return -EALREADY;
 
-       return ieee80211_config_beacon(sdata, params);
+       ret = ieee80211_config_beacon(sdata, params);
+       if (ret)
+               return ret;
+
+       /*
+        * Apply control port protocol, this allows us to
+        * not encrypt dynamic WEP control frames.
+        */
+       sdata->control_port_protocol = params->crypto.control_port_ethertype;
+       sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+               vlan->control_port_protocol =
+                       params->crypto.control_port_ethertype;
+               vlan->control_port_no_encrypt =
+                       params->crypto.control_port_no_encrypt;
+       }
+
+       return 0;
 }
 
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -847,7 +901,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 
        sta_apply_parameters(local, sta, params);
 
-       rate_control_rate_init(sta);
+       /*
+        * for TDLS, rate control should be initialized only when supported
+        * rates are known.
+        */
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               rate_control_rate_init(sta);
 
        layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
                sdata->vif.type == NL80211_IFTYPE_AP;
@@ -931,6 +990,9 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 
        sta_apply_parameters(local, sta, params);
 
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
+               rate_control_rate_init(sta);
+
        rcu_read_unlock();
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
@@ -1394,7 +1456,7 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
            (old_oper_type != local->_oper_channel_type))
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
-       if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) &&
+       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
            old_vif_oper_type != sdata->vif.bss_conf.channel_type)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
 
@@ -1917,7 +1979,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                             enum nl80211_channel_type channel_type,
                             bool channel_type_valid, unsigned int wait,
                             const u8 *buf, size_t len, bool no_cck,
-                            u64 *cookie)
+                            bool dont_wait_for_ack, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1925,10 +1987,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
-       u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-                   IEEE80211_TX_CTL_REQ_TX_STATUS;
+       u32 flags;
        bool is_offchan = false;
 
+       if (dont_wait_for_ack)
+               flags = IEEE80211_TX_CTL_NO_ACK;
+       else
+               flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                       IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        /* Check that we are on the requested channel for transmission */
        if (chan != local->tmp_channel &&
            chan != local->oper_channel)
@@ -2488,6 +2555,82 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
+                                 const u8 *peer, u64 *cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_qos_hdr *nullfunc;
+       struct sk_buff *skb;
+       int size = sizeof(*nullfunc);
+       __le16 fc;
+       bool qos;
+       struct ieee80211_tx_info *info;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       sta = sta_info_get(sdata, peer);
+       if (sta) {
+               qos = test_sta_flag(sta, WLAN_STA_WME);
+               rcu_read_unlock();
+       } else {
+               rcu_read_unlock();
+               return -ENOLINK;
+       }
+
+       if (qos) {
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_QOS_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       } else {
+               size -= 2;
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+       if (!skb)
+               return -ENOMEM;
+
+       skb->dev = dev;
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (void *) skb_put(skb, size);
+       nullfunc->frame_control = fc;
+       nullfunc->duration_id = 0;
+       memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+       nullfunc->seq_ctrl = 0;
+
+       info = IEEE80211_SKB_CB(skb);
+
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
+                      IEEE80211_TX_INTFL_NL80211_FRAME_TX;
+
+       skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+       skb->priority = 7;
+       if (qos)
+               nullfunc->qos_ctrl = cpu_to_le16(7);
+
+       local_bh_disable();
+       ieee80211_xmit(sdata, skb);
+       local_bh_enable();
+
+       *cookie = (unsigned long) skb;
+       return 0;
+}
+
+static struct ieee80211_channel *
+ieee80211_wiphy_get_channel(struct wiphy *wiphy)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       return local->oper_channel;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -2553,4 +2696,6 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_rekey_data = ieee80211_set_rekey_data,
        .tdls_oper = ieee80211_tdls_oper,
        .tdls_mgmt = ieee80211_tdls_mgmt,
+       .probe_client = ieee80211_probe_client,
+       .get_channel = ieee80211_wiphy_get_channel,
 };
index 883996b2f99fae26bd21e53d1ce12d7b322a8608..00cefcb493ebea1fb0cd8ba0fe7955ad424e5175 100644 (file)
@@ -190,7 +190,7 @@ static ssize_t uapsd_max_sp_len_write(struct file *file,
                return -EFAULT;
        buf[len] = '\0';
 
-       ret = strict_strtoul(buf, 0, &val);
+       ret = kstrtoul(buf, 0, &val);
 
        if (ret)
                return -EINVAL;
index 5f165d7eb2db4c22c3411129c4f93b72216a2794..b12ed52732c814b976bfc0084e680782faf5442d 100644 (file)
@@ -5,6 +5,11 @@
 #include "ieee80211_i.h"
 #include "driver-trace.h"
 
+static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
+{
+       WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
+}
+
 static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 {
        local->ops->tx(&local->hw, skb);
@@ -69,15 +74,23 @@ static inline int drv_resume(struct ieee80211_local *local)
 #endif
 
 static inline int drv_add_interface(struct ieee80211_local *local,
-                                   struct ieee80211_vif *vif)
+                                   struct ieee80211_sub_if_data *sdata)
 {
        int ret;
 
        might_sleep();
 
-       trace_drv_add_interface(local, vif_to_sdata(vif));
-       ret = local->ops->add_interface(&local->hw, vif);
+       if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR))
+               return -EINVAL;
+
+       trace_drv_add_interface(local, sdata);
+       ret = local->ops->add_interface(&local->hw, &sdata->vif);
        trace_drv_return_int(local, ret);
+
+       if (ret == 0)
+               sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
+
        return ret;
 }
 
@@ -89,6 +102,8 @@ static inline int drv_change_interface(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_change_interface(local, sdata, type, p2p);
        ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
        trace_drv_return_int(local, ret);
@@ -96,12 +111,15 @@ static inline int drv_change_interface(struct ieee80211_local *local,
 }
 
 static inline void drv_remove_interface(struct ieee80211_local *local,
-                                       struct ieee80211_vif *vif)
+                                       struct ieee80211_sub_if_data *sdata)
 {
        might_sleep();
 
-       trace_drv_remove_interface(local, vif_to_sdata(vif));
-       local->ops->remove_interface(&local->hw, vif);
+       check_sdata_in_driver(sdata);
+
+       trace_drv_remove_interface(local, sdata);
+       local->ops->remove_interface(&local->hw, &sdata->vif);
+       sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
        trace_drv_return_void(local);
 }
 
@@ -124,6 +142,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_bss_info_changed(local, sdata, info, changed);
        if (local->ops->bss_info_changed)
                local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
@@ -139,6 +159,8 @@ static inline int drv_tx_sync(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_tx_sync(local, sdata, bssid, type);
        if (local->ops->tx_sync)
                ret = local->ops->tx_sync(&local->hw, &sdata->vif,
@@ -154,6 +176,8 @@ static inline void drv_finish_tx_sync(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_finish_tx_sync(local, sdata, bssid, type);
        if (local->ops->finish_tx_sync)
                local->ops->finish_tx_sync(&local->hw, &sdata->vif,
@@ -211,6 +235,8 @@ static inline int drv_set_key(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_key(local, cmd, sdata, sta, key);
        ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
        trace_drv_return_int(local, ret);
@@ -228,6 +254,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
        if (sta)
                ista = &sta->sta;
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
        if (local->ops->update_tkip_key)
                local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
@@ -243,6 +271,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_hw_scan(local, sdata);
        ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
        trace_drv_return_int(local, ret);
@@ -254,6 +284,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_cancel_hw_scan(local, sdata);
        local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
@@ -269,6 +301,8 @@ drv_sched_scan_start(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sched_scan_start(local, sdata);
        ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
                                              req, ies);
@@ -281,6 +315,8 @@ static inline void drv_sched_scan_stop(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sched_scan_stop(local, sdata);
        local->ops->sched_scan_stop(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
@@ -377,6 +413,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
                                  enum sta_notify_cmd cmd,
                                  struct ieee80211_sta *sta)
 {
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_notify(local, sdata, cmd, sta);
        if (local->ops->sta_notify)
                local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
@@ -391,6 +429,8 @@ static inline int drv_sta_add(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_add(local, sdata, sta);
        if (local->ops->sta_add)
                ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
@@ -406,6 +446,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_remove(local, sdata, sta);
        if (local->ops->sta_remove)
                local->ops->sta_remove(&local->hw, &sdata->vif, sta);
@@ -421,6 +463,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_conf_tx(local, sdata, queue, params);
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, &sdata->vif,
@@ -436,6 +480,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_get_tsf(local, sdata);
        if (local->ops->get_tsf)
                ret = local->ops->get_tsf(&local->hw, &sdata->vif);
@@ -449,6 +495,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_tsf(local, sdata, tsf);
        if (local->ops->set_tsf)
                local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
@@ -460,6 +508,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_reset_tsf(local, sdata);
        if (local->ops->reset_tsf)
                local->ops->reset_tsf(&local->hw, &sdata->vif);
@@ -489,6 +539,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
 
        if (local->ops->ampdu_action)
@@ -644,6 +696,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_bitrate_mask(local, sdata, mask);
        if (local->ops->set_bitrate_mask)
                ret = local->ops->set_bitrate_mask(&local->hw,
@@ -657,6 +711,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
                                      struct ieee80211_sub_if_data *sdata,
                                      struct cfg80211_gtk_rekey_data *data)
 {
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_rekey_data(local, sdata, data);
        if (local->ops->set_rekey_data)
                local->ops->set_rekey_data(&local->hw, &sdata->vif, data);
index f0fb737efa8629bc8204f2f7cb8f5a568857853c..d06975098aad49b4ff9334d8b775b0227d7671ef 100644 (file)
@@ -196,7 +196,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
index ede9a8b341acadd2c2a491b1277a585f68eaea19..7d84af70132f8f0b4a6cdbbf80876b71cdca24c4 100644 (file)
@@ -97,6 +97,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        /* if merging, indicate to driver that we leave the old IBSS */
        if (sdata->vif.bss_conf.ibss_joined) {
                sdata->vif.bss_conf.ibss_joined = false;
+               netif_carrier_off(sdata->dev);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
        }
 
@@ -207,6 +208,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
                                        mgmt, skb->len, 0, GFP_KERNEL);
        cfg80211_put_bss(bss);
+       netif_carrier_on(sdata->dev);
        cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
 }
 
@@ -990,6 +992,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        }
 
        sta_info_flush(sdata->local, sdata);
+       netif_carrier_off(sdata->dev);
 
        /* remove beacon */
        kfree(sdata->u.ibss.ie);
index ea10a51babda9fa113c84ee000d46c62b86e69c6..068cc92d16aa8dea3f33ce2b7793f87aa7407798 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <linux/leds.h>
+#include <linux/idr.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -184,12 +185,15 @@ enum ieee80211_packet_rx_flags {
  * enum ieee80211_rx_flags - RX data flags
  *
  * @IEEE80211_RX_CMNTR: received on cooked monitor already
+ * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
+ *     to cfg80211_report_obss_beacon().
  *
  * These flags are used across handling multiple interfaces
  * for a single frame.
  */
 enum ieee80211_rx_flags {
        IEEE80211_RX_CMNTR              = BIT(0),
+       IEEE80211_RX_BEACON_REPORTED    = BIT(1),
 };
 
 struct ieee80211_rx_data {
@@ -228,6 +232,7 @@ struct beacon_data {
 
 struct ieee80211_if_ap {
        struct beacon_data __rcu *beacon;
+       struct sk_buff __rcu *probe_resp;
 
        struct list_head vlans;
 
@@ -543,6 +548,7 @@ struct ieee80211_if_mesh {
  *     associated stations and deliver multicast frames both
  *     back to wireless media and to the local net stack.
  * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
+ * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
@@ -550,6 +556,7 @@ enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_OPERATING_GMODE         = BIT(2),
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
        IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
+       IEEE80211_SDATA_IN_DRIVER               = BIT(5),
 };
 
 /**
@@ -722,17 +729,16 @@ enum {
  *     operating channel
  * @SCAN_SET_CHANNEL: Set the next channel to be scanned
  * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses
- * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP
- *     about us leaving the channel and stop all associated STA interfaces
- * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
- *     AP about us being back and restart all associated STA interfaces
+ * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to
+ *     send out data
+ * @SCAN_RESUME: Resume the scan and scan the next channel
  */
 enum mac80211_scan_state {
        SCAN_DECISION,
        SCAN_SET_CHANNEL,
        SCAN_SEND_PROBE,
-       SCAN_LEAVE_OPER_CHANNEL,
-       SCAN_ENTER_OPER_CHANNEL,
+       SCAN_SUSPEND,
+       SCAN_RESUME,
 };
 
 struct ieee80211_local {
@@ -1012,6 +1018,9 @@ struct ieee80211_local {
        u32 hw_roc_cookie;
        bool hw_roc_for_tx;
 
+       struct idr ack_status_frames;
+       spinlock_t ack_status_lock;
+
        /* dummy netdev for use w/ NAPI */
        struct net_device napi_dev;
 
@@ -1334,6 +1343,12 @@ void ieee80211_recalc_smps(struct ieee80211_local *local);
 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_vendor(const u8 *ies, size_t ielen, size_t offset);
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+                             u16 cap);
+u8 *ieee80211_ie_build_ht_info(u8 *pos,
+                               struct ieee80211_sta_ht_cap *ht_cap,
+                               struct ieee80211_channel *channel,
+                               enum nl80211_channel_type channel_type);
 
 /* internal work items */
 void ieee80211_work_init(struct ieee80211_local *local);
@@ -1362,6 +1377,8 @@ ieee80211_get_channel_mode(struct ieee80211_local *local,
 bool ieee80211_set_channel_type(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata,
                                enum nl80211_channel_type chantype);
+enum nl80211_channel_type
+ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index 30d73552e9ab0f89ef53707e564dd67aee47a3b8..12a6d4bb5d3736b348996bac224b43d5651873a1 100644 (file)
@@ -188,11 +188,22 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
                        return -ENOLINK;
                break;
-       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_AP_VLAN: {
+               struct ieee80211_sub_if_data *master;
+
                if (!sdata->bss)
                        return -ENOLINK;
+
                list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+
+               master = container_of(sdata->bss,
+                                     struct ieee80211_sub_if_data, u.ap);
+               sdata->control_port_protocol =
+                       master->control_port_protocol;
+               sdata->control_port_no_encrypt =
+                       master->control_port_no_encrypt;
                break;
+               }
        case NL80211_IFTYPE_AP:
                sdata->bss = &sdata->u.ap;
                break;
@@ -265,7 +276,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                break;
        default:
                if (coming_up) {
-                       res = drv_add_interface(local, &sdata->vif);
+                       res = drv_add_interface(local, sdata);
                        if (res)
                                goto err_stop;
                }
@@ -282,10 +293,18 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                changed |= ieee80211_reset_erp_info(sdata);
                ieee80211_bss_info_change_notify(sdata, changed);
 
-               if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+                   sdata->vif.type == NL80211_IFTYPE_ADHOC)
                        netif_carrier_off(dev);
                else
                        netif_carrier_on(dev);
+
+               /*
+                * set default queue parameters so drivers don't
+                * need to initialise the hardware if the hardware
+                * doesn't start up with sane defaults
+                */
+               ieee80211_set_wmm_default(sdata);
        }
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -329,15 +348,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
        if (coming_up)
                local->open_count++;
 
-       if (hw_reconf_flags) {
+       if (hw_reconf_flags)
                ieee80211_hw_config(local, hw_reconf_flags);
-               /*
-                * set default queue parameters so drivers don't
-                * need to initialise the hardware if the hardware
-                * doesn't start up with sane defaults
-                */
-               ieee80211_set_wmm_default(sdata);
-       }
 
        ieee80211_recalc_ps(local, -1);
 
@@ -345,7 +357,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 
        return 0;
  err_del_interface:
-       drv_remove_interface(local, &sdata->vif);
+       drv_remove_interface(local, sdata);
  err_stop:
        if (!local->open_count)
                drv_stop(local);
@@ -450,15 +462,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
                struct beacon_data *old_beacon =
                        rtnl_dereference(sdata->u.ap.beacon);
+               struct sk_buff *old_probe_resp =
+                       rtnl_dereference(sdata->u.ap.probe_resp);
 
                /* sdata_running will return false, so this will disable */
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_BEACON_ENABLED);
 
-               /* remove beacon */
+               /* remove beacon and probe response */
                RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+               RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
                synchronize_rcu();
                kfree(old_beacon);
+               kfree(old_probe_resp);
 
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
@@ -520,7 +536,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                ieee80211_free_keys(sdata);
 
                if (going_down)
-                       drv_remove_interface(local, &sdata->vif);
+                       drv_remove_interface(local, sdata);
        }
 
        sdata->bss = NULL;
index fb02ea52d2c2b46f760944de0f407f417d0fb492..87a89741432dce811cdb31168036788146f5721b 100644 (file)
@@ -134,9 +134,13 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                        sdata->crypto_tx_tailroom_needed_cnt--;
 
+               WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
+                       (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
+
                return 0;
        }
 
@@ -179,7 +183,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sdata = key->sdata;
 
        if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+             (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                increment_tailroom_need_count(sdata);
 
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
index d999bf3b84e1b27d0d79c91d44b7771756d92a3e..e323d4e6647bd702ab0a5f0a63e5d1dbfc4fed7d 100644 (file)
@@ -100,7 +100,7 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
  */
 bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        enum nl80211_channel_type channel_type;
 
        /* This logic needs to match logic in ieee80211_hw_config */
@@ -114,7 +114,7 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+               chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@ -126,8 +126,8 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
                return false;
 
        /* Check current hardware-config against oper_channel. */
-       if ((local->oper_channel != local->hw.conf.channel) ||
-           (local->_oper_channel_type != local->hw.conf.channel_type))
+       if (local->oper_channel != local->hw.conf.channel ||
+           local->_oper_channel_type != local->hw.conf.channel_type)
                return false;
 
        return true;
@@ -135,7 +135,7 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
@@ -143,14 +143,12 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 
        might_sleep();
 
-       scan_chan = local->scan_channel;
-
        /* If this off-channel logic ever changes,  ieee80211_on_oper_channel
         * may need to change as well.
         */
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
-       if (scan_chan) {
-               chan = scan_chan;
+       if (local->scan_channel) {
+               chan = local->scan_channel;
                /* If scanning on oper channel, use whatever channel-type
                 * is currently in use.
                 */
@@ -159,7 +157,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+               chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@ -595,7 +593,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
-                       WIPHY_FLAG_4ADDR_STATION;
+                       WIPHY_FLAG_4ADDR_STATION |
+                       WIPHY_FLAG_REPORTS_OBSS;
+
+       wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
 
        if (!ops->set_key)
                wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -670,6 +671,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        INIT_WORK(&local->sched_scan_stopped_work,
                  ieee80211_sched_scan_stopped_work);
 
+       spin_lock_init(&local->ack_status_lock);
+       idr_init(&local->ack_status_frames);
+       /* preallocate at least one entry */
+       idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
+
        sta_info_init(local);
 
        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -1045,6 +1051,13 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
+static int ieee80211_free_ack_frame(int id, void *p, void *data)
+{
+       WARN_ONCE(1, "Have pending ack frames!\n");
+       kfree_skb(p);
+       return 0;
+}
+
 void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -1055,6 +1068,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        if (local->wiphy_ciphers_allocated)
                kfree(local->hw.wiphy->cipher_suites);
 
+       idr_for_each(&local->ack_status_frames,
+                    ieee80211_free_ack_frame, NULL);
+       idr_destroy(&local->ack_status_frames);
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
index a7078fdba8ca7e3cf2a1f047f1f39c57c643f63e..b3a125f60347d47a9b474bdde83291611a3e505a 100644 (file)
@@ -76,6 +76,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
 bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       struct ieee80211_local *local = sdata->local;
 
        /*
         * As support for each feature is added, check for matching
@@ -87,15 +88,23 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
         *   - MDA enabled
         * - Power management control on fc
         */
-       if (ifmsh->mesh_id_len == ie->mesh_id_len &&
-               memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-               (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
-               (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
-               (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
-               (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
-               (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
-               return true;
-
+       if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
+            memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+            (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
+            (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
+            (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
+            (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
+            (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
+               goto mismatch;
+
+       /* disallow peering with mismatched channel types for now */
+       if (ie->ht_info_elem &&
+           (local->_oper_channel_type !=
+            ieee80211_ht_info_to_channel_type(ie->ht_info_elem)))
+               goto mismatch;
+
+       return true;
+mismatch:
        return false;
 }
 
@@ -341,6 +350,49 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
        return 0;
 }
 
+int mesh_add_ht_cap_ie(struct sk_buff *skb,
+                      struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       u8 *pos;
+
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       if (!sband->ht_cap.ht_supported ||
+           local->_oper_channel_type == NL80211_CHAN_NO_HT)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
+       ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
+
+       return 0;
+}
+
+int mesh_add_ht_info_ie(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel *channel = local->oper_channel;
+       enum nl80211_channel_type channel_type = local->_oper_channel_type;
+       struct ieee80211_supported_band *sband =
+                               local->hw.wiphy->bands[channel->band];
+       struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
+       u8 *pos;
+
+       if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_info))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info));
+       ieee80211_ie_build_ht_info(pos, ht_cap, channel, channel_type);
+
+       return 0;
+}
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
index 8c00e2d1d63612f3dfd483960805021f79acb204..622cc96eb4dea8fa900e9f17f8c29371a9768c1a 100644 (file)
@@ -31,6 +31,8 @@
  * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
  *     modified
  * @MESH_PATH_RESOLVED: the mesh path can has been resolved
+ * @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
+ * already queued up, waiting for the discovery process to start.
  *
  * MESH_PATH_RESOLVED is used by the mesh path timer to
  * decide when to stop or cancel the mesh path discovery.
@@ -41,6 +43,7 @@ enum mesh_path_flags {
        MESH_PATH_SN_VALID =    BIT(2),
        MESH_PATH_FIXED =       BIT(3),
        MESH_PATH_RESOLVED =    BIT(4),
+       MESH_PATH_REQ_QUEUED =  BIT(5),
 };
 
 /**
@@ -212,6 +215,10 @@ int mesh_add_vendor_ies(struct sk_buff *skb,
                        struct ieee80211_sub_if_data *sdata);
 int mesh_add_ds_params_ie(struct sk_buff *skb,
                          struct ieee80211_sub_if_data *sdata);
+int mesh_add_ht_cap_ie(struct sk_buff *skb,
+                      struct ieee80211_sub_if_data *sdata);
+int mesh_add_ht_info_ie(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
index 174040a42887c3eaf1d466fcfcf003ab83bd248d..a7afb2d32def7bfe308566b0147328827eb80067 100644 (file)
@@ -113,20 +113,20 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       int ie_len;
+       u8 *pos, ie_len;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
+                     sizeof(mgmt->u.action.u.mesh_action);
 
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + 37); /* max HWMP IE */
        if (!skb)
                return -1;
        skb_reserve(skb, local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
@@ -240,20 +240,20 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
                       struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       int ie_len;
+       u8 *pos, ie_len;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
+                     sizeof(mgmt->u.action.u.mesh_action);
 
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
        skb_reserve(skb, local->tx_headroom + local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
@@ -867,9 +867,19 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
                return;
        }
 
+       spin_lock_bh(&mpath->state_lock);
+       if (mpath->flags & MESH_PATH_REQ_QUEUED) {
+               spin_unlock_bh(&mpath->state_lock);
+               spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
+               return;
+       }
+
        memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
        preq_node->flags = flags;
 
+       mpath->flags |= MESH_PATH_REQ_QUEUED;
+       spin_unlock_bh(&mpath->state_lock);
+
        list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
        ++ifmsh->preq_queue_len;
        spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
@@ -921,6 +931,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                goto enddiscovery;
 
        spin_lock_bh(&mpath->state_lock);
+       mpath->flags &= ~MESH_PATH_REQ_QUEUED;
        if (preq_node->flags & PREQ_Q_F_START) {
                if (mpath->flags & MESH_PATH_RESOLVING) {
                        spin_unlock_bh(&mpath->state_lock);
@@ -1028,11 +1039,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                        mesh_queue_preq(mpath, PREQ_Q_F_START);
                }
 
-               if (skb_queue_len(&mpath->frame_queue) >=
-                               MESH_FRAME_QUEUE_LEN)
+               if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
                        skb_to_free = skb_dequeue(&mpath->frame_queue);
 
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+               ieee80211_set_qos_hdr(sdata, skb);
                skb_queue_tail(&mpath->frame_queue, skb);
                if (skb_to_free)
                        mesh_path_discard_frame(skb_to_free, sdata);
@@ -1061,6 +1072,7 @@ void mesh_path_timer(unsigned long data)
        } else if (mpath->discovery_retries < max_preq_retries(sdata)) {
                ++mpath->discovery_retries;
                mpath->discovery_timeout *= 2;
+               mpath->flags &= ~MESH_PATH_REQ_QUEUED;
                spin_unlock_bh(&mpath->state_lock);
                mesh_queue_preq(mpath, 0);
        } else {
index 7f54c5042235dd75fb87963fc7e2da04554d219f..4fc23d1b9c3af921036643d6ed7f242e817685ce 100644 (file)
@@ -213,7 +213,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        struct ieee80211_hdr *hdr;
        struct sk_buff_head tmpq;
        unsigned long flags;
-       struct ieee80211_sub_if_data *sdata = mpath->sdata;
 
        rcu_assign_pointer(mpath->next_hop, sta);
 
@@ -224,8 +223,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
                hdr = (struct ieee80211_hdr *) skb->data;
                memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
-               skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
-               ieee80211_set_qos_hdr(sdata, skb);
                __skb_queue_tail(&tmpq, skb);
        }
 
index 7e57f5d07f660ad7b19c432f95518952382832b9..0140e88a8220ce2f4c25c4758b6c555c2436b180 100644 (file)
@@ -80,11 +80,15 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
  *       on it in the lifecycle management section!
  */
 static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
-                                        u8 *hw_addr, u32 rates)
+                                        u8 *hw_addr, u32 rates,
+                                        struct ieee802_11_elems *elems)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
        struct sta_info *sta;
 
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+
        if (local->num_sta >= MESH_MAX_PLINKS)
                return NULL;
 
@@ -96,6 +100,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
        set_sta_flag(sta, WLAN_STA_AUTHORIZED);
        set_sta_flag(sta, WLAN_STA_WME);
        sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+       if (elems->ht_cap_elem)
+               ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem,
+                                                 &sta->sta.ht_cap);
        rate_control_rate_init(sta);
 
        return sta;
@@ -153,23 +160,31 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                enum ieee80211_self_protected_actioncode action,
                u8 *da, __le16 llid, __le16 plid, __le16 reason) {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
-                       sdata->u.mesh.ie_len);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        bool include_plid = false;
-       int ie_len = 4;
        u16 peering_proto = 0;
-       u8 *pos;
-
+       u8 *pos, ie_len = 4;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
+                     sizeof(mgmt->u.action.u.self_prot);
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + /* capability info */
+                           2 + /* AID */
+                           2 + 8 + /* supported rates */
+                           2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+                           2 + sdata->u.mesh.mesh_id_len +
+                           2 + sizeof(struct ieee80211_meshconf_ie) +
+                           2 + sizeof(struct ieee80211_ht_cap) +
+                           2 + sizeof(struct ieee80211_ht_info) +
+                           2 + 8 + /* peering IE */
+                           sdata->u.mesh.ie_len);
        if (!skb)
                return -1;
        skb_reserve(skb, local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        memcpy(mgmt->da, da, ETH_ALEN);
@@ -235,6 +250,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &reason, 2);
                pos += 2;
        }
+
+       if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+               if (mesh_add_ht_cap_ie(skb, sdata) ||
+                   mesh_add_ht_info_ie(skb, sdata))
+                       return -1;
+       }
+
        if (mesh_add_vendor_ies(skb, sdata))
                return -1;
 
@@ -261,7 +283,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
                                        elems->ie_start, elems->total_len,
                                        GFP_KERNEL);
                else
-                       sta = mesh_plink_alloc(sdata, hw_addr, rates);
+                       sta = mesh_plink_alloc(sdata, hw_addr, rates, elems);
                if (!sta)
                        return;
                if (sta_info_insert_rcu(sta)) {
@@ -552,7 +574,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                }
 
                rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
-               sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
+               sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
                if (!sta) {
                        mpl_dbg("Mesh plink error: plink table full\n");
                        return;
index b1b1bb368f701f61b47da0040ce9b0b477d09deb..f9ec15b3fe096dcb2a96682193dc01f7801dcb20 100644 (file)
@@ -1468,6 +1468,47 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
+static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
+                               u8 *supp_rates, unsigned int supp_rates_len,
+                               u32 *rates, u32 *basic_rates,
+                               bool *have_higher_than_11mbit,
+                               int *min_rate, int *min_rate_index)
+{
+       int i, j;
+
+       for (i = 0; i < supp_rates_len; i++) {
+               int rate = (supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(supp_rates[i] & 0x80);
+
+               if (rate > 110)
+                       *have_higher_than_11mbit = true;
+
+               /*
+                * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009
+                * 7.3.2.2 as a magic value instead of a rate. Hence, skip it.
+                *
+                * Note: Even through the membership selector and the basic
+                *       rate flag share the same bit, they are not exactly
+                *       the same.
+                */
+               if (!!(supp_rates[i] & 0x80) &&
+                   (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+                       continue;
+
+               for (j = 0; j < sband->n_bitrates; j++) {
+                       if (sband->bitrates[j].bitrate == rate) {
+                               *rates |= BIT(j);
+                               if (is_basic)
+                                       *basic_rates |= BIT(j);
+                               if (rate < *min_rate) {
+                                       *min_rate = rate;
+                                       *min_rate_index = j;
+                               }
+                               break;
+                       }
+               }
+       }
+}
 
 static bool ieee80211_assoc_success(struct ieee80211_work *wk,
                                    struct ieee80211_mgmt *mgmt, size_t len)
@@ -1484,7 +1525,7 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        u32 changed = 0;
-       int i, j, err;
+       int err;
        bool have_higher_than_11mbit = false;
        u16 ap_ht_cap_flags;
        int min_rate = INT_MAX, min_rate_index = -1;
@@ -1542,47 +1583,14 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        basic_rates = 0;
        sband = local->hw.wiphy->bands[wk->chan->band];
 
-       for (i = 0; i < elems.supp_rates_len; i++) {
-               int rate = (elems.supp_rates[i] & 0x7f) * 5;
-               bool is_basic = !!(elems.supp_rates[i] & 0x80);
-
-               if (rate > 110)
-                       have_higher_than_11mbit = true;
+       ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len,
+                           &rates, &basic_rates, &have_higher_than_11mbit,
+                           &min_rate, &min_rate_index);
 
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
-                               rates |= BIT(j);
-                               if (is_basic)
-                                       basic_rates |= BIT(j);
-                               if (rate < min_rate) {
-                                       min_rate = rate;
-                                       min_rate_index = j;
-                               }
-                               break;
-                       }
-               }
-       }
-
-       for (i = 0; i < elems.ext_supp_rates_len; i++) {
-               int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-               bool is_basic = !!(elems.ext_supp_rates[i] & 0x80);
-
-               if (rate > 110)
-                       have_higher_than_11mbit = true;
-
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
-                               rates |= BIT(j);
-                               if (is_basic)
-                                       basic_rates |= BIT(j);
-                               if (rate < min_rate) {
-                                       min_rate = rate;
-                                       min_rate_index = j;
-                               }
-                               break;
-                       }
-               }
-       }
+       ieee80211_get_rates(sband, elems.ext_supp_rates,
+                           elems.ext_supp_rates_len, &rates, &basic_rates,
+                           &have_higher_than_11mbit,
+                           &min_rate, &min_rate_index);
 
        /*
         * some buggy APs don't advertise basic_rates. use the lowest
index 9ee7164b207c23017eba9b9fc064eb1ab0248537..596efaf50e096c354aaa3fb0c01abefe1afe87ab 100644 (file)
@@ -125,7 +125,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                ieee80211_bss_info_change_notify(sdata,
                        BSS_CHANGED_BEACON_ENABLED);
 
-               drv_remove_interface(local, &sdata->vif);
+               drv_remove_interface(local, sdata);
        }
 
        /* stop hardware - this must stop RX */
index 58a89554b7882cc940ad6f7dce624c786e7f5c83..b39dda523f3986053c2d4e8d9a9619dce518d7c4 100644 (file)
@@ -334,8 +334,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
 
 
 static void
-calc_rate_durations(struct minstrel_sta_info *mi, struct ieee80211_local *local,
-                    struct minstrel_rate *d, struct ieee80211_rate *rate)
+calc_rate_durations(struct ieee80211_local *local, struct minstrel_rate *d,
+                   struct ieee80211_rate *rate)
 {
        int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
 
@@ -402,8 +402,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 
                mr->rix = i;
                mr->bitrate = sband->bitrates[i].bitrate / 5;
-               calc_rate_durations(mi, local, mr,
-                               &sband->bitrates[i]);
+               calc_rate_durations(local, mr, &sband->bitrates[i]);
 
                /* calculate maximum number of retransmissions before
                 * fallback (based on maximum segment size) */
index fb123e2e081a4c51495331f4d8cad945e53c3f40..d1a8869fe05d01e240bcbfcc50a2795555dadb9f 100644 (file)
@@ -748,10 +748,11 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
-       int tid;
+       u8 tid, ack_policy;
 
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto dont_reorder;
@@ -764,6 +765,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (!sta)
                goto dont_reorder;
 
+       ack_policy = *ieee80211_get_qos_ctl(hdr) &
+                    IEEE80211_QOS_CTL_ACK_POLICY_MASK;
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -774,6 +777,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
                goto dont_reorder;
 
+       /* not part of a BA session */
+       if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+           ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+               goto dont_reorder;
+
+       /* not actually part of this BA session */
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               goto dont_reorder;
+
        /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
@@ -858,6 +870,13 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                            rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
+
+               if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+                   cfg80211_rx_spurious_frame(rx->sdata->dev,
+                                              hdr->addr2,
+                                              GFP_ATOMIC))
+                       return RX_DROP_UNUSABLE;
+
                return RX_DROP_MONITOR;
        }
 
@@ -1327,15 +1346,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
                /*
                 * If we receive a 4-addr nullfunc frame from a STA
-                * that was not moved to a 4-addr STA vlan yet, drop
-                * the frame to the monitor interface, to make sure
-                * that hostapd sees it
+                * that was not moved to a 4-addr STA vlan yet send
+                * the event to userspace and for older hostapd drop
+                * the frame to the monitor interface.
                 */
                if (ieee80211_has_a4(hdr->frame_control) &&
                    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
                     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-                     !rx->sdata->u.vlan.sta)))
+                     !rx->sdata->u.vlan.sta))) {
+                       if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
+                               cfg80211_rx_unexpected_4addr_frame(
+                                       rx->sdata->dev, sta->sta.addr,
+                                       GFP_ATOMIC);
                        return RX_DROP_MONITOR;
+               }
                /*
                 * Update counter and free packet here to avoid
                 * counting this as a dropped packed.
@@ -1933,6 +1957,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
+       skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
        mesh_hdr->ttl--;
 
        if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
@@ -1957,12 +1982,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        info->control.vif = &rx->sdata->vif;
+                       info->control.jiffies = jiffies;
                        if (is_multicast_ether_addr(fwd_hdr->addr1)) {
                                IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
                                                                fwded_mcast);
-                               skb_set_queue_mapping(fwd_skb,
-                                       ieee80211_select_queue(sdata, fwd_skb));
-                               ieee80211_set_qos_hdr(sdata, fwd_skb);
                        } else {
                                int err;
                                /*
@@ -2014,12 +2037,17 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        /*
-        * Allow the cooked monitor interface of an AP to see 4-addr frames so
-        * that a 4-addr station can be detected and moved into a separate VLAN
+        * Send unexpected-4addr-frame event to hostapd. For older versions,
+        * also drop the frame to cooked monitor interfaces.
         */
        if (ieee80211_has_a4(hdr->frame_control) &&
-           sdata->vif.type == NL80211_IFTYPE_AP)
+           sdata->vif.type == NL80211_IFTYPE_AP) {
+               if (rx->sta &&
+                   !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
+                       cfg80211_rx_unexpected_4addr_frame(
+                               rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
                return RX_DROP_MONITOR;
+       }
 
        err = __ieee80211_data_to_8023(rx, &port_control);
        if (unlikely(err))
@@ -2174,6 +2202,18 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
        if (!ieee80211_is_mgmt(mgmt->frame_control))
                return RX_DROP_MONITOR;
 
+       if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+           ieee80211_is_beacon(mgmt->frame_control) &&
+           !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+               struct ieee80211_rx_status *status;
+
+               status = IEEE80211_SKB_RXCB(rx->skb);
+               cfg80211_report_obss_beacon(rx->local->hw.wiphy,
+                                           rx->skb->data, rx->skb->len,
+                                           status->freq, GFP_ATOMIC);
+               rx->flags |= IEEE80211_RX_BEACON_REPORTED;
+       }
+
        if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_MONITOR;
 
@@ -2207,13 +2247,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
-               /*
-                * The aggregation code is not prepared to handle
-                * anything but STA/AP due to the BSSID handling;
-                * IBSS could work in the code but isn't supported
-                * by drivers or the standard.
-                */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                   sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_AP)
                        break;
@@ -2493,6 +2528,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                goto out_free_skb;
        rx->flags |= IEEE80211_RX_CMNTR;
 
+       /* If there are no cooked monitor interfaces, just free the SKB */
+       if (!local->cooked_mntrs)
+               goto out_free_skb;
+
        if (skb_headroom(skb) < sizeof(*rthdr) &&
            pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
                goto out_free_skb;
index 105436dbb90dda1a3430fea9923fd46fa47bca00..81863031e0a326116b6aad620ac4df6667929d7e 100644 (file)
@@ -213,12 +213,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        if (bss)
                ieee80211_rx_bss_put(sdata->local, bss);
 
-       /* If we are on-operating-channel, and this packet is for the
-        * current channel, pass the pkt on up the stack so that
-        * the rest of the stack can make use of it.
-        */
-       if (ieee80211_cfg_on_oper_channel(sdata->local)
-           && (channel == sdata->local->oper_channel))
+       if (channel == sdata->local->oper_channel)
                return RX_CONTINUE;
 
        dev_kfree_skb(skb);
@@ -264,8 +259,6 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
                                       bool was_hw_scan)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       bool on_oper_chan;
-       bool enable_beacons = false;
 
        lockdep_assert_held(&local->mtx);
 
@@ -298,25 +291,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        local->scanning = 0;
        local->scan_channel = NULL;
 
-       on_oper_chan = ieee80211_cfg_on_oper_channel(local);
-
-       if (was_hw_scan || !on_oper_chan)
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       else
-               /* Set power back to normal operating levels. */
-               ieee80211_hw_config(local, 0);
+       /* Set power back to normal operating levels. */
+       ieee80211_hw_config(local, 0);
 
        if (!was_hw_scan) {
-               bool on_oper_chan2;
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
-               on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
-               /* We should always be on-channel at this point. */
-               WARN_ON(!on_oper_chan2);
-               if (on_oper_chan2 && (on_oper_chan != on_oper_chan2))
-                       enable_beacons = true;
-
-               ieee80211_offchannel_return(local, enable_beacons, true);
+               ieee80211_offchannel_return(local, true, true);
        }
 
        ieee80211_recalc_idle(local);
@@ -361,11 +342,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
-       /* We always want to use off-channel PS, even if we
-        * are not really leaving oper-channel.  Don't
-        * tell the AP though, as long as we are on-channel.
-        */
-       ieee80211_offchannel_enable_all_ps(local, false);
+       ieee80211_offchannel_stop_vifs(local, true);
 
        ieee80211_configure_filter(local);
 
@@ -373,8 +350,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        ieee80211_hw_config(local, 0);
 
        ieee80211_queue_delayed_work(&local->hw,
-                                    &local->scan_work,
-                                    IEEE80211_CHANNEL_TIME);
+                                    &local->scan_work, 0);
 
        return 0;
 }
@@ -510,96 +486,39 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
 
        next_chan = local->scan_req->channels[local->scan_channel_idx];
 
-       if (ieee80211_cfg_on_oper_channel(local)) {
-               /* We're currently on operating channel. */
-               if (next_chan == local->oper_channel)
-                       /* We don't need to move off of operating channel. */
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-               else
-                       /*
-                        * We do need to leave operating channel, as next
-                        * scan is somewhere else.
-                        */
-                       local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
-       } else {
-               /*
-                * we're currently scanning a different channel, let's
-                * see if we can scan another channel without interfering
-                * with the current traffic situation.
-                *
-                * Since we don't know if the AP has pending frames for us
-                * we can only check for our tx queues and use the current
-                * pm_qos requirements for rx. Hence, if no tx traffic occurs
-                * at all we will scan as many channels in a row as the pm_qos
-                * latency allows us to. Additionally we also check for the
-                * currently negotiated listen interval to prevent losing
-                * frames unnecessarily.
-                *
-                * Otherwise switch back to the operating channel.
-                */
-
-               bad_latency = time_after(jiffies +
-                               ieee80211_scan_get_channel_time(next_chan),
-                               local->leave_oper_channel_time +
-                               usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
-
-               listen_int_exceeded = time_after(jiffies +
-                               ieee80211_scan_get_channel_time(next_chan),
-                               local->leave_oper_channel_time +
-                               usecs_to_jiffies(min_beacon_int * 1024) *
-                               local->hw.conf.listen_interval);
-
-               if (associated && ( !tx_empty || bad_latency ||
-                   listen_int_exceeded))
-                       local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
-               else
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-       }
-
-       *next_delay = 0;
-}
-
-static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
-                                                   unsigned long *next_delay)
-{
-       /* PS will already be in off-channel mode,
-        * we do that once at the beginning of scanning.
-        */
-       ieee80211_offchannel_stop_vifs(local, false);
-
        /*
-        * What if the nullfunc frames didn't arrive?
+        * we're currently scanning a different channel, let's
+        * see if we can scan another channel without interfering
+        * with the current traffic situation.
+        *
+        * Since we don't know if the AP has pending frames for us
+        * we can only check for our tx queues and use the current
+        * pm_qos requirements for rx. Hence, if no tx traffic occurs
+        * at all we will scan as many channels in a row as the pm_qos
+        * latency allows us to. Additionally we also check for the
+        * currently negotiated listen interval to prevent losing
+        * frames unnecessarily.
+        *
+        * Otherwise switch back to the operating channel.
         */
-       drv_flush(local, false);
-       if (local->ops->flush)
-               *next_delay = 0;
-       else
-               *next_delay = HZ / 10;
 
-       /* remember when we left the operating channel */
-       local->leave_oper_channel_time = jiffies;
+       bad_latency = time_after(jiffies +
+                       ieee80211_scan_get_channel_time(next_chan),
+                       local->leave_oper_channel_time +
+                       usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
 
-       /* advance to the next channel to be scanned */
-       local->next_scan_state = SCAN_SET_CHANNEL;
-}
-
-static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
-                                                   unsigned long *next_delay)
-{
-       /* switch back to the operating channel */
-       local->scan_channel = NULL;
-       if (!ieee80211_cfg_on_oper_channel(local))
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       listen_int_exceeded = time_after(jiffies +
+                       ieee80211_scan_get_channel_time(next_chan),
+                       local->leave_oper_channel_time +
+                       usecs_to_jiffies(min_beacon_int * 1024) *
+                       local->hw.conf.listen_interval);
 
-       /*
-        * Re-enable vifs and beaconing.  Leave PS
-        * in off-channel state..will put that back
-        * on-channel at the end of scanning.
-        */
-       ieee80211_offchannel_return(local, true, false);
+       if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
+               local->next_scan_state = SCAN_SUSPEND;
+       else
+               local->next_scan_state = SCAN_SET_CHANNEL;
 
-       *next_delay = HZ / 5;
-       local->next_scan_state = SCAN_DECISION;
+       *next_delay = 0;
 }
 
 static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -613,10 +532,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 
        local->scan_channel = chan;
 
-       /* Only call hw-config if we really need to change channels. */
-       if (chan != local->hw.conf.channel)
-               if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
-                       skip = 1;
+       if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
+               skip = 1;
 
        /* advance state machine to next channel/band */
        local->scan_channel_idx++;
@@ -673,6 +590,44 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
        local->next_scan_state = SCAN_DECISION;
 }
 
+static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
+                                        unsigned long *next_delay)
+{
+       /* switch back to the operating channel */
+       local->scan_channel = NULL;
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+       /*
+        * Re-enable vifs and beaconing.  Leave PS
+        * in off-channel state..will put that back
+        * on-channel at the end of scanning.
+        */
+       ieee80211_offchannel_return(local, true, false);
+
+       *next_delay = HZ / 5;
+       /* afterwards, resume scan & go to next channel */
+       local->next_scan_state = SCAN_RESUME;
+}
+
+static void ieee80211_scan_state_resume(struct ieee80211_local *local,
+                                       unsigned long *next_delay)
+{
+       /* PS already is in off-channel mode */
+       ieee80211_offchannel_stop_vifs(local, false);
+
+       if (local->ops->flush) {
+               drv_flush(local, false);
+               *next_delay = 0;
+       } else
+               *next_delay = HZ / 10;
+
+       /* remember when we left the operating channel */
+       local->leave_oper_channel_time = jiffies;
+
+       /* advance to the next channel to be scanned */
+       local->next_scan_state = SCAN_DECISION;
+}
+
 void ieee80211_scan_work(struct work_struct *work)
 {
        struct ieee80211_local *local =
@@ -743,11 +698,11 @@ void ieee80211_scan_work(struct work_struct *work)
                case SCAN_SEND_PROBE:
                        ieee80211_scan_state_send_probe(local, &next_delay);
                        break;
-               case SCAN_LEAVE_OPER_CHANNEL:
-                       ieee80211_scan_state_leave_oper_channel(local, &next_delay);
+               case SCAN_SUSPEND:
+                       ieee80211_scan_state_suspend(local, &next_delay);
                        break;
-               case SCAN_ENTER_OPER_CHANNEL:
-                       ieee80211_scan_state_enter_oper_channel(local, &next_delay);
+               case SCAN_RESUME:
+                       ieee80211_scan_state_resume(local, &next_delay);
                        break;
                }
        } while (next_delay == 0);
index 8c8ce05ad26fd0090d0b08eb41809b25bd89a6db..c5923ab8a070c167e125bc64e99ce3cee6c15cd2 100644 (file)
@@ -52,6 +52,7 @@
  *     unblocks the station.
  * @WLAN_STA_SP: Station is in a service period, so don't try to
  *     reply to other uAPSD trigger frames or PS-Poll.
+ * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
  */
 enum ieee80211_sta_info_flags {
        WLAN_STA_AUTH,
@@ -71,6 +72,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_TDLS_PEER_AUTH,
        WLAN_STA_UAPSD,
        WLAN_STA_SP,
+       WLAN_STA_4ADDR_EVENT,
 };
 
 #define STA_TID_NUM 16
@@ -390,6 +392,12 @@ static inline int test_and_clear_sta_flag(struct sta_info *sta,
        return test_and_clear_bit(flag, &sta->_flags);
 }
 
+static inline int test_and_set_sta_flag(struct sta_info *sta,
+                                       enum ieee80211_sta_info_flags flag)
+{
+       return test_and_set_bit(flag, &sta->_flags);
+}
+
 void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
                             struct tid_ampdu_tx *tid_tx);
 
index 80de436eae20eed9aa58f2a99fc7366b4f840649..a9da6ee69803a86c59474c847c434a6ae2f38dd5 100644 (file)
@@ -517,27 +517,54 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
-               struct ieee80211_work *wk;
                u64 cookie = (unsigned long)skb;
 
-               rcu_read_lock();
-               list_for_each_entry_rcu(wk, &local->work_list, list) {
-                       if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-                               continue;
-                       if (wk->offchan_tx.frame != skb)
-                               continue;
-                       wk->offchan_tx.status = true;
-                       break;
-               }
-               rcu_read_unlock();
-               if (local->hw_roc_skb_for_status == skb) {
-                       cookie = local->hw_roc_cookie ^ 2;
-                       local->hw_roc_skb_for_status = NULL;
+               if (ieee80211_is_nullfunc(hdr->frame_control) ||
+                   ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+                       bool acked = info->flags & IEEE80211_TX_STAT_ACK;
+                       cfg80211_probe_status(skb->dev, hdr->addr1,
+                                             cookie, acked, GFP_ATOMIC);
+               } else {
+                       struct ieee80211_work *wk;
+
+                       rcu_read_lock();
+                       list_for_each_entry_rcu(wk, &local->work_list, list) {
+                               if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+                                       continue;
+                               if (wk->offchan_tx.frame != skb)
+                                       continue;
+                               wk->offchan_tx.status = true;
+                               break;
+                       }
+                       rcu_read_unlock();
+                       if (local->hw_roc_skb_for_status == skb) {
+                               cookie = local->hw_roc_cookie ^ 2;
+                               local->hw_roc_skb_for_status = NULL;
+                       }
+
+                       cfg80211_mgmt_tx_status(
+                               skb->dev, cookie, skb->data, skb->len,
+                               !!(info->flags & IEEE80211_TX_STAT_ACK),
+                               GFP_ATOMIC);
                }
+       }
 
-               cfg80211_mgmt_tx_status(
-                       skb->dev, cookie, skb->data, skb->len,
-                       !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               /* consumes ack_skb */
+               if (ack_skb)
+                       skb_complete_wifi_ack(ack_skb,
+                               info->flags & IEEE80211_TX_STAT_ACK);
        }
 
        /* this was a transmitted frame, but now we want to reuse it */
@@ -610,3 +637,29 @@ void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
                                    num_packets, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(ieee80211_report_low_ack);
+
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               /* consumes ack_skb */
+               if (ack_skb)
+                       dev_kfree_skb_any(ack_skb);
+       }
+
+       dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL(ieee80211_free_txskb);
index 1f8b120146d1d714c97dc949495a9fbb0afab51b..f044963feb9a13159b3137afe2c83caaa2d466a5 100644 (file)
@@ -1685,8 +1685,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        int nh_pos, h_pos;
        struct sta_info *sta = NULL;
        bool wme_sta = false, authorized = false, tdls_auth = false;
-       struct sk_buff *tmp_skb;
        bool tdls_direct = false;
+       bool multicast;
+       u32 info_flags = 0;
+       u16 info_id = 0;
 
        if (unlikely(skb->len < ETH_HLEN)) {
                ret = NETDEV_TX_OK;
@@ -1873,7 +1875,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         * if it is a multicast address (which can only happen
         * in AP mode)
         */
-       if (!is_multicast_ether_addr(hdr.addr1)) {
+       multicast = is_multicast_ether_addr(hdr.addr1);
+       if (!multicast) {
                rcu_read_lock();
                sta = sta_info_get(sdata, hdr.addr1);
                if (sta) {
@@ -1914,11 +1917,54 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                goto fail;
        }
 
+       if (unlikely(!multicast && skb->sk &&
+                    skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
+               struct sk_buff *orig_skb = skb;
+
+               skb = skb_clone(skb, GFP_ATOMIC);
+               if (skb) {
+                       unsigned long flags;
+                       int id, r;
+
+                       spin_lock_irqsave(&local->ack_status_lock, flags);
+                       r = idr_get_new_above(&local->ack_status_frames,
+                                             orig_skb, 1, &id);
+                       if (r == -EAGAIN) {
+                               idr_pre_get(&local->ack_status_frames,
+                                           GFP_ATOMIC);
+                               r = idr_get_new_above(&local->ack_status_frames,
+                                                     orig_skb, 1, &id);
+                       }
+                       if (WARN_ON(!id) || id > 0xffff) {
+                               idr_remove(&local->ack_status_frames, id);
+                               r = -ERANGE;
+                       }
+                       spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+                       if (!r) {
+                               info_id = id;
+                               info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+                       } else if (skb_shared(skb)) {
+                               kfree_skb(orig_skb);
+                       } else {
+                               kfree_skb(skb);
+                               skb = orig_skb;
+                       }
+               } else {
+                       /* couldn't clone -- lose tx status ... */
+                       skb = orig_skb;
+               }
+       }
+
        /*
         * If the skb is shared we need to obtain our own copy.
         */
        if (skb_shared(skb)) {
-               tmp_skb = skb;
+               struct sk_buff *tmp_skb = skb;
+
+               /* can't happen -- skb is a clone if info_id != 0 */
+               WARN_ON(info_id);
+
                skb = skb_clone(skb, GFP_ATOMIC);
                kfree_skb(tmp_skb);
 
@@ -2019,6 +2065,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        memset(info, 0, sizeof(*info));
 
        dev->trans_start = jiffies;
+
+       info->flags = info_flags;
+       info->ack_frame_id = info_id;
+
        ieee80211_xmit(sdata, skb);
 
        return NETDEV_TX_OK;
@@ -2279,22 +2329,31 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                struct ieee80211_mgmt *mgmt;
                u8 *pos;
+               int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
+                             sizeof(mgmt->u.beacon);
 
 #ifdef CONFIG_MAC80211_MESH
                if (!sdata->u.mesh.mesh_id_len)
                        goto out;
 #endif
 
-               /* headroom, head length, tail length and maximum TIM length */
-               skb = dev_alloc_skb(local->tx_headroom + 400 +
-                               sdata->u.mesh.ie_len);
+               skb = dev_alloc_skb(local->tx_headroom +
+                                   hdr_len +
+                                   2 + /* NULL SSID */
+                                   2 + 8 + /* supported rates */
+                                   2 + 3 + /* DS params */
+                                   2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+                                   2 + sizeof(struct ieee80211_ht_cap) +
+                                   2 + sizeof(struct ieee80211_ht_info) +
+                                   2 + sdata->u.mesh.mesh_id_len +
+                                   2 + sizeof(struct ieee80211_meshconf_ie) +
+                                   sdata->u.mesh.ie_len);
                if (!skb)
                        goto out;
 
                skb_reserve(skb, local->hw.extra_tx_headroom);
-               mgmt = (struct ieee80211_mgmt *)
-                       skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-               memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+               mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+               memset(mgmt, 0, hdr_len);
                mgmt->frame_control =
                    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
@@ -2313,6 +2372,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                    mesh_add_ds_params_ie(skb, sdata) ||
                    ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
                    mesh_add_rsn_ie(skb, sdata) ||
+                   mesh_add_ht_cap_ie(skb, sdata) ||
+                   mesh_add_ht_info_ie(skb, sdata) ||
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata) ||
                    mesh_add_vendor_ies(skb, sdata)) {
@@ -2355,6 +2416,37 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_beacon_get_tim);
 
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif)
+{
+       struct ieee80211_if_ap *ap = NULL;
+       struct sk_buff *presp = NULL, *skb = NULL;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
+               return NULL;
+
+       rcu_read_lock();
+
+       ap = &sdata->u.ap;
+       presp = rcu_dereference(ap->probe_resp);
+       if (!presp)
+               goto out;
+
+       skb = skb_copy(presp, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       memset(hdr->addr1, 0, sizeof(hdr->addr1));
+
+out:
+       rcu_read_unlock();
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_proberesp_get);
+
 struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
index eca0fad09709518266d9aed37c61f75e2f05afcf..3a00814699f028344b627c782e98c1a15daad344 100644 (file)
@@ -812,23 +812,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                offset = noffset;
        }
 
-       if (sband->ht_cap.ht_supported) {
-               u16 cap = sband->ht_cap.cap;
-               __le16 tmp;
-
-               *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_cap);
-               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-               tmp = cpu_to_le16(cap);
-               memcpy(pos, &tmp, sizeof(u16));
-               pos += sizeof(u16);
-               *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density <<
-                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-               memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-               pos += sizeof(sband->ht_cap.mcs);
-               pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
-       }
+       if (sband->ht_cap.ht_supported)
+               pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
 
        /*
         * If adding more here, adjust code in main.c
@@ -1026,7 +1011,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
                    ieee80211_sdata_running(sdata))
-                       res = drv_add_interface(local, &sdata->vif);
+                       res = drv_add_interface(local, sdata);
        }
 
        /* add STAs back */
@@ -1077,7 +1062,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_BEACON_INT |
                          BSS_CHANGED_BSSID |
                          BSS_CHANGED_CQM |
-                         BSS_CHANGED_QOS;
+                         BSS_CHANGED_QOS |
+                         BSS_CHANGED_IDLE;
 
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
@@ -1090,7 +1076,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
                case NL80211_IFTYPE_AP:
-                       changed |= BSS_CHANGED_SSID;
+                       changed |= BSS_CHANGED_SSID |
+                                  BSS_CHANGED_AP_PROBE_RESP;
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
@@ -1112,6 +1099,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                }
        }
 
+       ieee80211_recalc_ps(local, -1);
+
        /*
         * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
         * sessions can be established after a resume.
@@ -1367,6 +1356,103 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
 
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+                             u16 cap)
+{
+       __le16 tmp;
+
+       *pos++ = WLAN_EID_HT_CAPABILITY;
+       *pos++ = sizeof(struct ieee80211_ht_cap);
+       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+
+       /* capability flags */
+       tmp = cpu_to_le16(cap);
+       memcpy(pos, &tmp, sizeof(u16));
+       pos += sizeof(u16);
+
+       /* AMPDU parameters */
+       *pos++ = sband->ht_cap.ampdu_factor |
+                (sband->ht_cap.ampdu_density <<
+                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+
+       /* MCS set */
+       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+       pos += sizeof(sband->ht_cap.mcs);
+
+       /* extended capabilities */
+       pos += sizeof(__le16);
+
+       /* BF capabilities */
+       pos += sizeof(__le32);
+
+       /* antenna selection */
+       pos += sizeof(u8);
+
+       return pos;
+}
+
+u8 *ieee80211_ie_build_ht_info(u8 *pos,
+                              struct ieee80211_sta_ht_cap *ht_cap,
+                              struct ieee80211_channel *channel,
+                              enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_ht_info *ht_info;
+       /* Build HT Information */
+       *pos++ = WLAN_EID_HT_INFORMATION;
+       *pos++ = sizeof(struct ieee80211_ht_info);
+       ht_info = (struct ieee80211_ht_info *)pos;
+       ht_info->control_chan =
+                       ieee80211_frequency_to_channel(channel->center_freq);
+       switch (channel_type) {
+       case NL80211_CHAN_HT40MINUS:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+               break;
+       case NL80211_CHAN_HT40PLUS:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               break;
+       case NL80211_CHAN_HT20:
+       default:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+               break;
+       }
+       if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+               ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+       ht_info->operation_mode = 0x0000;
+       ht_info->stbc_param = 0x0000;
+
+       /* It seems that Basic MCS set and Supported MCS set
+          are identical for the first 10 bytes */
+       memset(&ht_info->basic_set, 0, 16);
+       memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
+
+       return pos + sizeof(struct ieee80211_ht_info);
+}
+
+enum nl80211_channel_type
+ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
+{
+       enum nl80211_channel_type channel_type;
+
+       if (!ht_info)
+               return NL80211_CHAN_NO_HT;
+
+       switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+               channel_type = NL80211_CHAN_HT20;
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+               channel_type = NL80211_CHAN_HT40PLUS;
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+               channel_type = NL80211_CHAN_HT40MINUS;
+               break;
+       default:
+               channel_type = NL80211_CHAN_NO_HT;
+       }
+
+       return channel_type;
+}
+
 int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
index fd52e695c071082b4b51bc3cbc20e535a9f47630..43327115b49098f0484b01922dea78dd385992b7 100644 (file)
@@ -83,7 +83,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
-               ra = skb->data;
+               qos = true;
                break;
 #endif
        case NL80211_IFTYPE_STATION:
@@ -143,11 +143,15 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
        /* Fill in the QoS header if there is one. */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *p = ieee80211_get_qos_ctl(hdr);
-               u8 ack_policy = 0, tid;
+               u8 ack_policy, tid;
 
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-               if (unlikely(sdata->local->wifi_wme_noack_test))
+               /* preserve EOSP bit */
+               ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
+
+               if (unlikely(sdata->local->wifi_wme_noack_test) ||
+                   is_multicast_ether_addr(hdr->addr1))
                        ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
                /* qos header is 2 bytes */
                *p++ = ack_policy | tid;
index 6c53b6d1002b5a2046837fe2ec60d7687bd0c973..3dd5a89e99a79f2cc37687928bee12ade66089d8 100644 (file)
@@ -103,7 +103,6 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
        u8 *pos;
        u32 flags = channel->flags;
        u16 cap = sband->ht_cap.cap;
-       __le16 tmp;
 
        if (!sband->ht_cap.ht_supported)
                return;
@@ -154,34 +153,8 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
        }
 
        /* reserve and fill IE */
-
        pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
-       *pos++ = WLAN_EID_HT_CAPABILITY;
-       *pos++ = sizeof(struct ieee80211_ht_cap);
-       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-
-       /* capability flags */
-       tmp = cpu_to_le16(cap);
-       memcpy(pos, &tmp, sizeof(u16));
-       pos += sizeof(u16);
-
-       /* AMPDU parameters */
-       *pos++ = sband->ht_cap.ampdu_factor |
-                (sband->ht_cap.ampdu_density <<
-                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-
-       /* MCS set */
-       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-       pos += sizeof(sband->ht_cap.mcs);
-
-       /* extended capabilities */
-       pos += sizeof(__le16);
-
-       /* BF capabilities */
-       pos += sizeof(__le32);
-
-       /* antenna selection */
-       pos += sizeof(u8);
+       ieee80211_ie_build_ht_cap(pos, sband, cap);
 }
 
 static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
@@ -969,10 +942,9 @@ static void ieee80211_work_work(struct work_struct *work)
                }
 
                if (!started && !local->tmp_channel) {
-                       bool on_oper_chan;
-                       bool tmp_chan_changed = false;
-                       bool on_oper_chan2;
+                       bool on_oper_chan, on_oper_chan2;
                        enum nl80211_channel_type wk_ct;
+
                        on_oper_chan = ieee80211_cfg_on_oper_channel(local);
 
                        /* Work with existing channel type if possible. */
@@ -981,11 +953,6 @@ static void ieee80211_work_work(struct work_struct *work)
                                wk_ct = ieee80211_calc_ct(wk->chan_type,
                                                local->hw.conf.channel_type);
 
-                       if (local->tmp_channel)
-                               if ((local->tmp_channel != wk->chan) ||
-                                   (local->tmp_channel_type != wk_ct))
-                                       tmp_chan_changed = true;
-
                        local->tmp_channel = wk->chan;
                        local->tmp_channel_type = wk_ct;
                        /*
@@ -1008,12 +975,7 @@ static void ieee80211_work_work(struct work_struct *work)
                                                                    true,
                                                                    false);
                                }
-                       } else if (tmp_chan_changed)
-                               /* Still off-channel, but on some other
-                                * channel, so update hardware.
-                                * PS should already be off-channel.
-                                */
-                               ieee80211_hw_config(local, 0);
+                       }
 
                        started = true;
                        wk->timeout = jiffies;
index f614ce7bb6e3b4aea4f9c445e2594b2c6366e6d0..106e15a4649f1f24ba5335227c44b5a79817e2fb 100644 (file)
@@ -390,7 +390,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        u8 scratch[6 * AES_BLOCK_SIZE];
 
        if (info->control.hw_key &&
-           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
                /*
                 * hwaccel has no need for preallocated room for CCMP
                 * header or MIC fields
@@ -412,6 +413,12 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        pos = skb_push(skb, CCMP_HDR_LEN);
        memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
+
+       /* the HW only needs room for the IV, but not the actual IV */
+       if (info->control.hw_key &&
+           (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
+               return 0;
+
        hdr = (struct ieee80211_hdr *) pos;
        pos += hdrlen;
 
index 3925c6578767ea61be8cc66933d38a6c500cd1d2..fe5ca89abfce3b0facaba030fd7c0c188720a3b7 100644 (file)
@@ -126,7 +126,10 @@ static inline int nci_request(struct nci_dev *ndev,
 
 static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
 {
-       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 0, NULL);
+       struct nci_core_reset_cmd cmd;
+
+       cmd.reset_type = NCI_RESET_TYPE_RESET_CONFIG;
+       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 1, &cmd);
 }
 
 static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
@@ -136,17 +139,11 @@ static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
 
 static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
 {
-       struct nci_core_conn_create_cmd conn_cmd;
        struct nci_rf_disc_map_cmd cmd;
        struct disc_map_config *cfg = cmd.mapping_configs;
        __u8 *num = &cmd.num_mapping_configs;
        int i;
 
-       /* create static rf connection */
-       conn_cmd.target_handle = 0;
-       conn_cmd.num_target_specific_params = 0;
-       nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, &conn_cmd);
-
        /* set rf mapping configurations */
        *num = 0;
 
@@ -470,7 +467,7 @@ static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
        ndev->data_exchange_cb = cb;
        ndev->data_exchange_cb_context = cb_context;
 
-       rc = nci_send_data(ndev, ndev->conn_id, skb);
+       rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
        if (rc)
                clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
 
@@ -726,7 +723,10 @@ static void nci_tx_work(struct work_struct *work)
                if (!skb)
                        return;
 
-               atomic_dec(&ndev->credits_cnt);
+               /* Check if data flow control is used */
+               if (atomic_read(&ndev->credits_cnt) !=
+                               NCI_DATA_FLOW_CONTROL_NOT_USED)
+                       atomic_dec(&ndev->credits_cnt);
 
                nfc_dbg("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d",
                                nci_pbf(skb->data),
index e5ed90fc1a9cf1bf6024e22bb2989644a48ed837..511fb96e21bc47252b58bf0c736bc19b31831cbc 100644 (file)
@@ -95,7 +95,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
        __skb_queue_head_init(&frags_q);
 
        while (total_len) {
-               frag_len = min_t(int, total_len, ndev->max_pkt_payload_size);
+               frag_len =
+                       min_t(int, total_len, ndev->max_data_pkt_payload_size);
 
                skb_frag = nci_skb_alloc(ndev,
                                        (NCI_DATA_HDR_SIZE + frag_len),
@@ -151,7 +152,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
        nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len);
 
        /* check if the packet need to be fragmented */
-       if (skb->len <= ndev->max_pkt_payload_size) {
+       if (skb->len <= ndev->max_data_pkt_payload_size) {
                /* no need to fragment packet */
                nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
 
index b19dc2fa90e13982352122615aa278bb8280ab77..e99adcfb1bcf10e2c4dd506f778d2a53f2539426 100644 (file)
@@ -42,12 +42,9 @@ int nci_to_errno(__u8 code)
        case NCI_STATUS_REJECTED:
                return -EBUSY;
 
-       case NCI_STATUS_MESSAGE_CORRUPTED:
+       case NCI_STATUS_RF_FRAME_CORRUPTED:
                return -EBADMSG;
 
-       case NCI_STATUS_BUFFER_FULL:
-               return -ENOBUFS;
-
        case NCI_STATUS_NOT_INITIALIZED:
                return -EHOSTDOWN;
 
@@ -80,9 +77,6 @@ int nci_to_errno(__u8 code)
        case NCI_STATUS_NFCEE_TIMEOUT_ERROR:
                return -ETIMEDOUT;
 
-       case NCI_STATUS_RF_LINK_LOSS_ERROR:
-               return -ENOLINK;
-
        case NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED:
                return -EDQUOT;
 
index 96633f5cda4f790d3bae4ecdfa4f3a6435c5797c..c1bf54172c25bbc606ea385a7251ed6d878c9cd0 100644 (file)
@@ -54,7 +54,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                        ntf->conn_entries[i].conn_id,
                        ntf->conn_entries[i].credits);
 
-               if (ntf->conn_entries[i].conn_id == ndev->conn_id) {
+               if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
                        /* found static rf connection */
                        atomic_add(ntf->conn_entries[i].credits,
                                &ndev->credits_cnt);
@@ -66,22 +66,12 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                queue_work(ndev->tx_wq, &ndev->tx_work);
 }
 
-static void nci_rf_field_info_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
-{
-       struct nci_rf_field_info_ntf *ntf = (void *) skb->data;
-
-       nfc_dbg("entry, rf_field_status %d", ntf->rf_field_status);
-}
-
-static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
-                       struct nci_rf_activate_ntf *ntf, __u8 *data)
+static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
+                       struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
 {
        struct rf_tech_specific_params_nfca_poll *nfca_poll;
-       struct activation_params_nfca_poll_iso_dep *nfca_poll_iso_dep;
 
        nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;
-       nfca_poll_iso_dep = &ntf->activation_params.nfca_poll_iso_dep;
 
        nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
        data += 2;
@@ -100,32 +90,32 @@ static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
        if (nfca_poll->sel_res_len != 0)
                nfca_poll->sel_res = *data++;
 
-       ntf->rf_interface_type = *data++;
-       ntf->activation_params_len = *data++;
-
-       nfc_dbg("sel_res_len %d, sel_res 0x%x, rf_interface_type %d, activation_params_len %d",
+       nfc_dbg("sel_res_len %d, sel_res 0x%x",
                nfca_poll->sel_res_len,
-               nfca_poll->sel_res,
-               ntf->rf_interface_type,
-               ntf->activation_params_len);
-
-       switch (ntf->rf_interface_type) {
-       case NCI_RF_INTERFACE_ISO_DEP:
-               nfca_poll_iso_dep->rats_res_len = *data++;
-               if (nfca_poll_iso_dep->rats_res_len > 0) {
-                       memcpy(nfca_poll_iso_dep->rats_res,
+               nfca_poll->sel_res);
+
+       return data;
+}
+
+static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
+                       struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
+{
+       struct activation_params_nfca_poll_iso_dep *nfca_poll;
+
+       switch (ntf->activation_rf_tech_and_mode) {
+       case NCI_NFC_A_PASSIVE_POLL_MODE:
+               nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
+               nfca_poll->rats_res_len = *data++;
+               if (nfca_poll->rats_res_len > 0) {
+                       memcpy(nfca_poll->rats_res,
                                data,
-                               nfca_poll_iso_dep->rats_res_len);
+                               nfca_poll->rats_res_len);
                }
                break;
 
-       case NCI_RF_INTERFACE_FRAME:
-               /* no activation params */
-               break;
-
        default:
-               nfc_err("unsupported rf_interface_type 0x%x",
-                       ntf->rf_interface_type);
+               nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
+                       ntf->activation_rf_tech_and_mode);
                return -EPROTO;
        }
 
@@ -133,7 +123,7 @@ static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
 }
 
 static void nci_target_found(struct nci_dev *ndev,
-                               struct nci_rf_activate_ntf *ntf)
+                               struct nci_rf_intf_activated_ntf *ntf)
 {
        struct nfc_target nfc_tgt;
 
@@ -141,6 +131,8 @@ static void nci_target_found(struct nci_dev *ndev,
                nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
        else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)   /* 4A */
                nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
+       else
+               nfc_tgt.supported_protocols = 0;
 
        nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
        nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
@@ -158,49 +150,86 @@ static void nci_target_found(struct nci_dev *ndev,
        nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
 }
 
-static void nci_rf_activate_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
+                                               struct sk_buff *skb)
 {
-       struct nci_rf_activate_ntf ntf;
+       struct nci_rf_intf_activated_ntf ntf;
        __u8 *data = skb->data;
-       int rc = -1;
+       int err = 0;
 
        clear_bit(NCI_DISCOVERY, &ndev->flags);
        set_bit(NCI_POLL_ACTIVE, &ndev->flags);
 
-       ntf.target_handle = *data++;
+       ntf.rf_discovery_id = *data++;
+       ntf.rf_interface_type = *data++;
        ntf.rf_protocol = *data++;
-       ntf.rf_tech_and_mode = *data++;
+       ntf.activation_rf_tech_and_mode = *data++;
        ntf.rf_tech_specific_params_len = *data++;
 
-       nfc_dbg("target_handle %d, rf_protocol 0x%x, rf_tech_and_mode 0x%x, rf_tech_specific_params_len %d",
-               ntf.target_handle,
-               ntf.rf_protocol,
-               ntf.rf_tech_and_mode,
+       nfc_dbg("rf_discovery_id %d", ntf.rf_discovery_id);
+       nfc_dbg("rf_interface_type 0x%x", ntf.rf_interface_type);
+       nfc_dbg("rf_protocol 0x%x", ntf.rf_protocol);
+       nfc_dbg("activation_rf_tech_and_mode 0x%x",
+               ntf.activation_rf_tech_and_mode);
+       nfc_dbg("rf_tech_specific_params_len %d",
                ntf.rf_tech_specific_params_len);
 
-       switch (ntf.rf_tech_and_mode) {
-       case NCI_NFC_A_PASSIVE_POLL_MODE:
-               rc = nci_rf_activate_nfca_passive_poll(ndev, &ntf,
-                       data);
-               break;
+       if (ntf.rf_tech_specific_params_len > 0) {
+               switch (ntf.activation_rf_tech_and_mode) {
+               case NCI_NFC_A_PASSIVE_POLL_MODE:
+                       data = nci_extract_rf_params_nfca_passive_poll(ndev,
+                               &ntf, data);
+                       break;
+
+               default:
+                       nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
+                               ntf.activation_rf_tech_and_mode);
+                       return;
+               }
+       }
 
-       default:
-               nfc_err("unsupported rf_tech_and_mode 0x%x",
-                       ntf.rf_tech_and_mode);
-               return;
+       ntf.data_exch_rf_tech_and_mode = *data++;
+       ntf.data_exch_tx_bit_rate = *data++;
+       ntf.data_exch_rx_bit_rate = *data++;
+       ntf.activation_params_len = *data++;
+
+       nfc_dbg("data_exch_rf_tech_and_mode 0x%x",
+               ntf.data_exch_rf_tech_and_mode);
+       nfc_dbg("data_exch_tx_bit_rate 0x%x",
+               ntf.data_exch_tx_bit_rate);
+       nfc_dbg("data_exch_rx_bit_rate 0x%x",
+               ntf.data_exch_rx_bit_rate);
+       nfc_dbg("activation_params_len %d",
+               ntf.activation_params_len);
+
+       if (ntf.activation_params_len > 0) {
+               switch (ntf.rf_interface_type) {
+               case NCI_RF_INTERFACE_ISO_DEP:
+                       err = nci_extract_activation_params_iso_dep(ndev,
+                               &ntf, data);
+                       break;
+
+               case NCI_RF_INTERFACE_FRAME:
+                       /* no activation params */
+                       break;
+
+               default:
+                       nfc_err("unsupported rf_interface_type 0x%x",
+                               ntf.rf_interface_type);
+                       return;
+               }
        }
 
-       if (!rc)
+       if (!err)
                nci_target_found(ndev, &ntf);
 }
 
 static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
                                        struct sk_buff *skb)
 {
-       __u8 type = skb->data[0];
+       struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
 
-       nfc_dbg("entry, type 0x%x", type);
+       nfc_dbg("entry, type 0x%x, reason 0x%x", ntf->type, ntf->reason);
 
        clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
        ndev->target_active_prot = 0;
@@ -214,6 +243,9 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
                ndev->rx_data_reassembly = 0;
        }
 
+       /* set the available credits to initial value */
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
+
        /* complete the data exchange transaction, if exists */
        if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
                nci_data_exchange_complete(ndev, NULL, -EIO);
@@ -237,12 +269,8 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
                nci_core_conn_credits_ntf_packet(ndev, skb);
                break;
 
-       case NCI_OP_RF_FIELD_INFO_NTF:
-               nci_rf_field_info_ntf_packet(ndev, skb);
-               break;
-
-       case NCI_OP_RF_ACTIVATE_NTF:
-               nci_rf_activate_ntf_packet(ndev, skb);
+       case NCI_OP_RF_INTF_ACTIVATED_NTF:
+               nci_rf_intf_activated_ntf_packet(ndev, skb);
                break;
 
        case NCI_OP_RF_DEACTIVATE_NTF:
index 0403d4cd091769de0731909d4497645f84ff650b..0591f5aff89fbc8c721bcc0e39bf43c3778e2625 100644 (file)
@@ -42,10 +42,11 @@ static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 
        nfc_dbg("entry, status 0x%x", rsp->status);
 
-       if (rsp->status == NCI_STATUS_OK)
+       if (rsp->status == NCI_STATUS_OK) {
                ndev->nci_ver = rsp->nci_ver;
-
-       nfc_dbg("nci_ver 0x%x", ndev->nci_ver);
+               nfc_dbg("nci_ver 0x%x, config_status 0x%x",
+                       rsp->nci_ver, rsp->config_status);
+       }
 
        nci_req_complete(ndev, rsp->status);
 }
@@ -58,13 +59,13 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
        nfc_dbg("entry, status 0x%x", rsp_1->status);
 
        if (rsp_1->status != NCI_STATUS_OK)
-               return;
+               goto exit;
 
        ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
        ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
 
        if (ndev->num_supported_rf_interfaces >
-               NCI_MAX_SUPPORTED_RF_INTERFACES) {
+                       NCI_MAX_SUPPORTED_RF_INTERFACES) {
                ndev->num_supported_rf_interfaces =
                        NCI_MAX_SUPPORTED_RF_INTERFACES;
        }
@@ -73,20 +74,26 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                rsp_1->supported_rf_interfaces,
                ndev->num_supported_rf_interfaces);
 
-       rsp_2 = (void *) (skb->data + 6 + ndev->num_supported_rf_interfaces);
+       rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces);
 
        ndev->max_logical_connections =
                rsp_2->max_logical_connections;
        ndev->max_routing_table_size =
                __le16_to_cpu(rsp_2->max_routing_table_size);
-       ndev->max_control_packet_payload_length =
-               rsp_2->max_control_packet_payload_length;
-       ndev->rf_sending_buffer_size =
-               __le16_to_cpu(rsp_2->rf_sending_buffer_size);
-       ndev->rf_receiving_buffer_size =
-               __le16_to_cpu(rsp_2->rf_receiving_buffer_size);
-       ndev->manufacturer_id =
-               __le16_to_cpu(rsp_2->manufacturer_id);
+       ndev->max_ctrl_pkt_payload_len =
+               rsp_2->max_ctrl_pkt_payload_len;
+       ndev->max_size_for_large_params =
+               __le16_to_cpu(rsp_2->max_size_for_large_params);
+       ndev->max_data_pkt_payload_size =
+               rsp_2->max_data_pkt_payload_size;
+       ndev->initial_num_credits =
+               rsp_2->initial_num_credits;
+       ndev->manufact_id =
+               rsp_2->manufact_id;
+       ndev->manufact_specific_info =
+               __le32_to_cpu(rsp_2->manufact_specific_info);
+
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
 
        nfc_dbg("nfcc_features 0x%x",
                ndev->nfcc_features);
@@ -104,39 +111,23 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                ndev->max_logical_connections);
        nfc_dbg("max_routing_table_size %d",
                ndev->max_routing_table_size);
-       nfc_dbg("max_control_packet_payload_length %d",
-               ndev->max_control_packet_payload_length);
-       nfc_dbg("rf_sending_buffer_size %d",
-               ndev->rf_sending_buffer_size);
-       nfc_dbg("rf_receiving_buffer_size %d",
-               ndev->rf_receiving_buffer_size);
-       nfc_dbg("manufacturer_id 0x%x",
-               ndev->manufacturer_id);
-
+       nfc_dbg("max_ctrl_pkt_payload_len %d",
+               ndev->max_ctrl_pkt_payload_len);
+       nfc_dbg("max_size_for_large_params %d",
+               ndev->max_size_for_large_params);
+       nfc_dbg("max_data_pkt_payload_size %d",
+               ndev->max_data_pkt_payload_size);
+       nfc_dbg("initial_num_credits %d",
+               ndev->initial_num_credits);
+       nfc_dbg("manufact_id 0x%x",
+               ndev->manufact_id);
+       nfc_dbg("manufact_specific_info 0x%x",
+               ndev->manufact_specific_info);
+
+exit:
        nci_req_complete(ndev, rsp_1->status);
 }
 
-static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
-{
-       struct nci_core_conn_create_rsp *rsp = (void *) skb->data;
-
-       nfc_dbg("entry, status 0x%x", rsp->status);
-
-       if (rsp->status != NCI_STATUS_OK)
-               return;
-
-       ndev->max_pkt_payload_size = rsp->max_pkt_payload_size;
-       ndev->initial_num_credits = rsp->initial_num_credits;
-       ndev->conn_id = rsp->conn_id;
-
-       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
-
-       nfc_dbg("max_pkt_payload_size %d", ndev->max_pkt_payload_size);
-       nfc_dbg("initial_num_credits %d", ndev->initial_num_credits);
-       nfc_dbg("conn_id %d", ndev->conn_id);
-}
-
 static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
                                        struct sk_buff *skb)
 {
@@ -196,10 +187,6 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                nci_core_init_rsp_packet(ndev, skb);
                break;
 
-       case NCI_OP_CORE_CONN_CREATE_RSP:
-               nci_core_conn_create_rsp_packet(ndev, skb);
-               break;
-
        case NCI_OP_RF_DISCOVER_MAP_RSP:
                nci_rf_disc_map_rsp_packet(ndev, skb);
                break;
index 82a6f34d39d012fb35d9a0d490503fcc2048e6e2..0da505c9ac233b9cf2ca4f20475dc8d987ef68d5 100644 (file)
@@ -1499,10 +1499,11 @@ retry:
 
        if (!skb) {
                size_t reserved = LL_RESERVED_SPACE(dev);
+               int tlen = dev->needed_tailroom;
                unsigned int hhlen = dev->header_ops ? dev->hard_header_len : 0;
 
                rcu_read_unlock();
-               skb = sock_wmalloc(sk, len + reserved, 0, GFP_KERNEL);
+               skb = sock_wmalloc(sk, len + reserved + tlen, 0, GFP_KERNEL);
                if (skb == NULL)
                        return -ENOBUFS;
                /* FIXME: Save some space for broken drivers that write a hard
@@ -1944,7 +1945,7 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
 
 static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                void *frame, struct net_device *dev, int size_max,
-               __be16 proto, unsigned char *addr)
+               __be16 proto, unsigned char *addr, int hlen)
 {
        union {
                struct tpacket_hdr *h1;
@@ -1978,7 +1979,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                return -EMSGSIZE;
        }
 
-       skb_reserve(skb, LL_RESERVED_SPACE(dev));
+       skb_reserve(skb, hlen);
        skb_reset_network_header(skb);
 
        data = ph.raw + po->tp_hdrlen - sizeof(struct sockaddr_ll);
@@ -2053,6 +2054,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        unsigned char *addr;
        int len_sum = 0;
        int status = 0;
+       int hlen, tlen;
 
        mutex_lock(&po->pg_vec_lock);
 
@@ -2101,16 +2103,17 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                }
 
                status = TP_STATUS_SEND_REQUEST;
+               hlen = LL_RESERVED_SPACE(dev);
+               tlen = dev->needed_tailroom;
                skb = sock_alloc_send_skb(&po->sk,
-                               LL_ALLOCATED_SPACE(dev)
-                               + sizeof(struct sockaddr_ll),
+                               hlen + tlen + sizeof(struct sockaddr_ll),
                                0, &err);
 
                if (unlikely(skb == NULL))
                        goto out_status;
 
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
-                               addr);
+                               addr, hlen);
 
                if (unlikely(tp_len < 0)) {
                        if (po->tp_loss) {
@@ -2207,6 +2210,7 @@ static int packet_snd(struct socket *sock,
        int vnet_hdr_len;
        struct packet_sock *po = pkt_sk(sk);
        unsigned short gso_type = 0;
+       int hlen, tlen;
 
        /*
         *      Get and verify the address.
@@ -2291,8 +2295,9 @@ static int packet_snd(struct socket *sock,
                goto out_unlock;
 
        err = -ENOBUFS;
-       skb = packet_alloc_skb(sk, LL_ALLOCATED_SPACE(dev),
-                              LL_RESERVED_SPACE(dev), len, vnet_hdr.hdr_len,
+       hlen = LL_RESERVED_SPACE(dev);
+       tlen = dev->needed_tailroom;
+       skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, vnet_hdr.hdr_len,
                               msg->msg_flags & MSG_DONTWAIT, &err);
        if (skb == NULL)
                goto out_unlock;
index 2ba6e9fb4cbcd9554b6cf3eadb9088ca9e577ad7..9f60008740e32875fb80d64b070cdf7262366650 100644 (file)
@@ -534,6 +534,29 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
        return pipe_handler_send_created_ind(sk);
 }
 
+static int pep_enableresp_rcv(struct sock *sk, struct sk_buff *skb)
+{
+       struct pnpipehdr *hdr = pnp_hdr(skb);
+
+       if (hdr->error_code != PN_PIPE_NO_ERROR)
+               return -ECONNREFUSED;
+
+       return pep_indicate(sk, PNS_PIPE_ENABLED_IND, 0 /* sub-blocks */,
+               NULL, 0, GFP_ATOMIC);
+
+}
+
+static void pipe_start_flow_control(struct sock *sk)
+{
+       struct pep_sock *pn = pep_sk(sk);
+
+       if (!pn_flow_safe(pn->tx_fc)) {
+               atomic_set(&pn->tx_credits, 1);
+               sk->sk_write_space(sk);
+       }
+       pipe_grant_credits(sk, GFP_ATOMIC);
+}
+
 /* Queue an skb to an actively connected sock.
  * Socket lock must be held. */
 static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
@@ -579,13 +602,25 @@ static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
                        sk->sk_state = TCP_CLOSE_WAIT;
                        break;
                }
+               if (pn->init_enable == PN_PIPE_DISABLE)
+                       sk->sk_state = TCP_SYN_RECV;
+               else {
+                       sk->sk_state = TCP_ESTABLISHED;
+                       pipe_start_flow_control(sk);
+               }
+               break;
 
-               sk->sk_state = TCP_ESTABLISHED;
-               if (!pn_flow_safe(pn->tx_fc)) {
-                       atomic_set(&pn->tx_credits, 1);
-                       sk->sk_write_space(sk);
+       case PNS_PEP_ENABLE_RESP:
+               if (sk->sk_state != TCP_SYN_SENT)
+                       break;
+
+               if (pep_enableresp_rcv(sk, skb)) {
+                       sk->sk_state = TCP_CLOSE_WAIT;
+                       break;
                }
-               pipe_grant_credits(sk, GFP_ATOMIC);
+
+               sk->sk_state = TCP_ESTABLISHED;
+               pipe_start_flow_control(sk);
                break;
 
        case PNS_PEP_DISCONNECT_RESP:
@@ -864,14 +899,32 @@ static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len)
        int err;
        u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD };
 
-       pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
+       if (pn->pipe_handle == PN_PIPE_INVALID_HANDLE)
+               pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
+
        err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ,
-                                       PN_PIPE_ENABLE, data, 4);
+                               pn->init_enable, data, 4);
        if (err) {
                pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
                return err;
        }
+
        sk->sk_state = TCP_SYN_SENT;
+
+       return 0;
+}
+
+static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len)
+{
+       int err;
+
+       err = pipe_handler_request(sk, PNS_PEP_ENABLE_REQ, PAD,
+                               NULL, 0);
+       if (err)
+               return err;
+
+       sk->sk_state = TCP_SYN_SENT;
+
        return 0;
 }
 
@@ -879,11 +932,14 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        struct pep_sock *pn = pep_sk(sk);
        int answ;
+       int ret = -ENOIOCTLCMD;
 
        switch (cmd) {
        case SIOCINQ:
-               if (sk->sk_state == TCP_LISTEN)
-                       return -EINVAL;
+               if (sk->sk_state == TCP_LISTEN) {
+                       ret = -EINVAL;
+                       break;
+               }
 
                lock_sock(sk);
                if (sock_flag(sk, SOCK_URGINLINE) &&
@@ -894,10 +950,22 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
                else
                        answ = 0;
                release_sock(sk);
-               return put_user(answ, (int __user *)arg);
+               ret = put_user(answ, (int __user *)arg);
+               break;
+
+       case SIOCPNENABLEPIPE:
+               lock_sock(sk);
+               if (sk->sk_state == TCP_SYN_SENT)
+                       ret =  -EBUSY;
+               else if (sk->sk_state == TCP_ESTABLISHED)
+                       ret = -EISCONN;
+               else
+                       ret = pep_sock_enable(sk, NULL, 0);
+               release_sock(sk);
+               break;
        }
 
-       return -ENOIOCTLCMD;
+       return ret;
 }
 
 static int pep_init(struct sock *sk)
@@ -960,6 +1028,18 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
                }
                goto out_norel;
 
+       case PNPIPE_HANDLE:
+               if ((sk->sk_state == TCP_CLOSE) &&
+                       (val >= 0) && (val < PN_PIPE_INVALID_HANDLE))
+                       pn->pipe_handle = val;
+               else
+                       err = -EINVAL;
+               break;
+
+       case PNPIPE_INITSTATE:
+               pn->init_enable = !!val;
+               break;
+
        default:
                err = -ENOPROTOOPT;
        }
@@ -995,6 +1075,10 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
                        return -EINVAL;
                break;
 
+       case PNPIPE_INITSTATE:
+               val = pn->init_enable;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
index 5be19575c340886ff869e94dc7ae65c0e959e00c..354760ebbbd254f1409a196e7c27140c0512e5e9 100644 (file)
@@ -644,7 +644,7 @@ static ssize_t rfkill_soft_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       err = strict_strtoul(buf, 0, &state);
+       err = kstrtoul(buf, 0, &state);
        if (err)
                return err;
 
@@ -688,7 +688,7 @@ static ssize_t rfkill_state_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       err = strict_strtoul(buf, 0, &state);
+       err = kstrtoul(buf, 0, &state);
        if (err)
                return err;
 
index 3422b25df9e46d8149ea0591ddc1625740b64bb6..061bcb744bbd3852df7e8c5df6c01293156afad2 100644 (file)
@@ -152,15 +152,14 @@ static bool choke_match_flow(struct sk_buff *skb1,
 {
        int off1, off2, poff;
        const u32 *ports1, *ports2;
+       u32 _ports1, _ports2;
        u8 ip_proto;
        __u32 hash1;
 
        if (skb1->protocol != skb2->protocol)
                return false;
 
-       /* Use hash value as quick check
-        * Assumes that __skb_get_rxhash makes IP header and ports linear
-        */
+       /* Use rxhash value as quick check */
        hash1 = skb_get_rxhash(skb1);
        if (!hash1 || hash1 != skb_get_rxhash(skb2))
                return false;
@@ -172,10 +171,12 @@ static bool choke_match_flow(struct sk_buff *skb1,
        switch (skb1->protocol) {
        case __constant_htons(ETH_P_IP): {
                const struct iphdr *ip1, *ip2;
+               struct iphdr _ip1, _ip2;
 
-               ip1 = (const struct iphdr *) (skb1->data + off1);
-               ip2 = (const struct iphdr *) (skb2->data + off2);
-
+               ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1);
+               ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2);
+               if (!ip1 || !ip2)
+                       return false;
                ip_proto = ip1->protocol;
                if (ip_proto != ip2->protocol ||
                    ip1->saddr != ip2->saddr || ip1->daddr != ip2->daddr)
@@ -190,9 +191,12 @@ static bool choke_match_flow(struct sk_buff *skb1,
 
        case __constant_htons(ETH_P_IPV6): {
                const struct ipv6hdr *ip1, *ip2;
+               struct ipv6hdr _ip1, _ip2;
 
-               ip1 = (const struct ipv6hdr *) (skb1->data + off1);
-               ip2 = (const struct ipv6hdr *) (skb2->data + off2);
+               ip1 = skb_header_pointer(skb1, off1, sizeof(_ip1), &_ip1);
+               ip2 = skb_header_pointer(skb2, off2, sizeof(_ip2), &_ip2);
+               if (!ip1 || !ip2)
+                       return false;
 
                ip_proto = ip1->nexthdr;
                if (ip_proto != ip2->nexthdr ||
@@ -214,8 +218,11 @@ static bool choke_match_flow(struct sk_buff *skb1,
        off1 += poff;
        off2 += poff;
 
-       ports1 = (__force u32 *)(skb1->data + off1);
-       ports2 = (__force u32 *)(skb2->data + off2);
+       ports1 = skb_header_pointer(skb1, off1, sizeof(_ports1), &_ports1);
+       ports2 = skb_header_pointer(skb2, off2, sizeof(_ports2), &_ports2);
+       if (!ports1 || !ports2)
+               return false;
+
        return *ports1 == *ports2;
 }
 
index 69fca2798804f29f5cd3cbdadd139fdc6801e9d5..79ac1458c2ba86a8457d0a6f5a7b091760b50234 100644 (file)
@@ -246,6 +246,7 @@ static void dev_watchdog(unsigned long arg)
                                    time_after(jiffies, (trans_start +
                                                         dev->watchdog_timeo))) {
                                        some_queue_timedout = 1;
+                                       txq->trans_timeout++;
                                        break;
                                }
                        }
index 0121e0ab035167d468c2976f17f210b2cb98a083..a85eeeb55dd0022e009895c53a6d8593929b7691 100644 (file)
@@ -3400,8 +3400,10 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
                asconf_len -= length;
        }
 
-       if (no_err && asoc->src_out_of_asoc_ok)
+       if (no_err && asoc->src_out_of_asoc_ok) {
                asoc->src_out_of_asoc_ok = 0;
+               sctp_transport_immediate_rtx(asoc->peer.primary_path);
+       }
 
        /* Free the cached last sent asconf chunk. */
        list_del_init(&asconf->transmitted_list);
index 76388b083f283a2e2c62ab3f605ee8a12469454f..1ff51c9d18d5d5ca925da9bd24544fe46014ad7b 100644 (file)
@@ -666,6 +666,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
                                  struct sctp_chunk *chunk)
 {
        sctp_sender_hb_info_t *hbinfo;
+       int was_unconfirmed = 0;
 
        /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
         * HEARTBEAT should clear the error counter of the destination
@@ -692,9 +693,11 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
        /* Mark the destination transport address as active if it is not so
         * marked.
         */
-       if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED))
+       if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED)) {
+               was_unconfirmed = 1;
                sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
                                             SCTP_HEARTBEAT_SUCCESS);
+       }
 
        /* The receiver of the HEARTBEAT ACK should also perform an
         * RTT measurement for that destination transport address
@@ -712,6 +715,9 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
        /* Update the heartbeat timer.  */
        if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t)))
                sctp_transport_hold(t);
+
+       if (was_unconfirmed && asoc->peer.transport_count == 1)
+               sctp_transport_immediate_rtx(t);
 }
 
 
index 394c57ca2f54210e4060654fb72f1937aee3bc75..3889330b7b04c06f33338be44bbf4effcf518827 100644 (file)
@@ -641,3 +641,19 @@ void sctp_transport_reset(struct sctp_transport *t)
        t->cacc.next_tsn_at_change = 0;
        t->cacc.cacc_saw_newack = 0;
 }
+
+/* Schedule retransmission on the given transport */
+void sctp_transport_immediate_rtx(struct sctp_transport *t)
+{
+       /* Stop pending T3_rtx_timer */
+       if (timer_pending(&t->T3_rtx_timer)) {
+               (void)del_timer(&t->T3_rtx_timer);
+               sctp_transport_put(t);
+       }
+       sctp_retransmit(&t->asoc->outqueue, t, SCTP_RTXR_T3_RTX);
+       if (!timer_pending(&t->T3_rtx_timer)) {
+               if (!mod_timer(&t->T3_rtx_timer, jiffies + t->rto))
+                       sctp_transport_hold(t);
+       }
+       return;
+}
index 2877647f347b06e75aaaa7fd355799a43cd65bf3..425ef42704605e83c0f366fc1edb000d18eeb419 100644 (file)
@@ -538,6 +538,8 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
                *tx_flags |= SKBTX_HW_TSTAMP;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
                *tx_flags |= SKBTX_SW_TSTAMP;
+       if (sock_flag(sk, SOCK_WIFI_STATUS))
+               *tx_flags |= SKBTX_WIFI_STATUS;
        return 0;
 }
 EXPORT_SYMBOL(sock_tx_timestamp);
@@ -674,6 +676,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
 
+void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb)
+{
+       int ack;
+
+       if (!sock_flag(sk, SOCK_WIFI_STATUS))
+               return;
+       if (!skb->wifi_acked_valid)
+               return;
+
+       ack = skb->wifi_acked;
+
+       put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
+}
+EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
+
 static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
                                   struct sk_buff *skb)
 {
index 220f3bd176f89cc33192b72ddcc11f296cba54fd..ccdfed897651bba0a96c6d6111b5067a976457ca 100644 (file)
@@ -492,6 +492,10 @@ int wiphy_register(struct wiphy *wiphy)
                    !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
                return -EINVAL;
 
+       if (WARN_ON(wiphy->ap_sme_capa &&
+                   !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
+               return -EINVAL;
+
        if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
                return -EINVAL;
 
index b9ec3061ed722c4dc58b526d0c545ce64ad5f163..1c7d4df5418cdef9929939a782c0fcf0893a0bd3 100644 (file)
@@ -54,6 +54,8 @@ struct cfg80211_registered_device {
        int opencount; /* also protected by devlist_mtx */
        wait_queue_head_t dev_wait;
 
+       u32 ap_beacons_nlpid;
+
        /* BSSes/scanning */
        spinlock_t bss_lock;
        struct list_head bss_list;
@@ -376,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie);
+                         bool dont_wait_for_ack, u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
index 21fc9702f81c355a772803f507aa8496801adb0e..6c1bafd508c8dabddee9422448084f92c04a2be8 100644 (file)
@@ -879,6 +879,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
        }
 
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
+
+       if (nlpid == wdev->ap_unexpected_nlpid)
+               wdev->ap_unexpected_nlpid = 0;
 }
 
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
@@ -901,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie)
+                         bool dont_wait_for_ack, u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const struct ieee80211_mgmt *mgmt;
@@ -992,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        /* Transmit the Action frame as requested by user space */
        return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
                                  channel_type, channel_type_valid,
-                                 wait, buf, len, no_cck, cookie);
+                                 wait, buf, len, no_cck, dont_wait_for_ack,
+                                 cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
@@ -1107,3 +1111,30 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
        nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+               return false;
+
+       return nl80211_unexpected_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
+
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype != NL80211_IFTYPE_AP_VLAN))
+               return false;
+
+       return nl80211_unexpected_4addr_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index b3a476fe82725f738f5215b32cdf2296970451d2..6bc7c4b32fa5786196dd39e5755d2dd3282e25a0 100644 (file)
@@ -98,7 +98,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
        [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
-       [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
 
        [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
@@ -196,6 +196,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
        [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
+       [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
+       [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
+                                     .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -203,7 +206,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
        [NL80211_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
-       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
        [NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@ -758,6 +761,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
                    dev->wiphy.available_antennas_rx);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
+               NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+                           dev->wiphy.probe_resp_offload);
+
        if ((dev->wiphy.available_antennas_tx ||
             dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
                u32 tx_ant = 0, rx_ant = 0;
@@ -890,6 +897,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        }
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                CMD(sched_scan_start, START_SCHED_SCAN);
+       CMD(probe_client, PROBE_CLIENT);
+       if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
+               i++;
+               NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
+       }
 
 #undef CMD
 
@@ -1007,6 +1019,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        if (nl80211_put_iface_combinations(&dev->wiphy, msg))
                goto nla_put_failure;
 
+       if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
+               NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
+                           dev->wiphy.ap_sme_capa);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
+
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -2155,6 +2173,13 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                        nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
        }
 
+       if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
+               params.probe_resp =
+                       nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
+               params.probe_resp_len =
+                       nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
+       }
+
        err = call(&rdev->wiphy, dev, &params);
        if (!err && params.interval)
                wdev->beacon_interval = params.interval;
@@ -5271,12 +5296,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        bool channel_type_valid = false;
        u32 freq;
        int err;
-       void *hdr;
+       void *hdr = NULL;
        u64 cookie;
-       struct sk_buff *msg;
+       struct sk_buff *msg = NULL;
        unsigned int wait = 0;
-       bool offchan;
-       bool no_cck;
+       bool offchan, no_cck, dont_wait_for_ack;
+
+       dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
 
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -5320,29 +5346,36 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (chan == NULL)
                return -EINVAL;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
+       if (!dont_wait_for_ack) {
+               msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+               if (!msg)
+                       return -ENOMEM;
 
-       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_FRAME);
+               hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                                    NL80211_CMD_FRAME);
 
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto free_msg;
+               if (IS_ERR(hdr)) {
+                       err = PTR_ERR(hdr);
+                       goto free_msg;
+               }
        }
+
        err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
                                    channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   no_cck, &cookie);
+                                   no_cck, dont_wait_for_ack, &cookie);
        if (err)
                goto free_msg;
 
-       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+       if (msg) {
+               NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
-       genlmsg_end(msg, hdr);
-       return genlmsg_reply(msg, info);
+               genlmsg_end(msg, hdr);
+               return genlmsg_reply(msg, info);
+       }
+
+       return 0;
 
  nla_put_failure:
        err = -ENOBUFS;
@@ -5832,6 +5865,91 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int nl80211_register_unexpected_frame(struct sk_buff *skb,
+                                            struct genl_info *info)
+{
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (wdev->iftype != NL80211_IFTYPE_AP &&
+           wdev->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
+
+       if (wdev->ap_unexpected_nlpid)
+               return -EBUSY;
+
+       wdev->ap_unexpected_nlpid = info->snd_pid;
+       return 0;
+}
+
+static int nl80211_probe_client(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 wireless_dev *wdev = dev->ieee80211_ptr;
+       struct sk_buff *msg;
+       void *hdr;
+       const u8 *addr;
+       u64 cookie;
+       int err;
+
+       if (wdev->iftype != NL80211_IFTYPE_AP &&
+           wdev->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!rdev->ops->probe_client)
+               return -EOPNOTSUPP;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                            NL80211_CMD_PROBE_CLIENT);
+
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto free_msg;
+       }
+
+       addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
+       if (err)
+               goto free_msg;
+
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       err = -ENOBUFS;
+ free_msg:
+       nlmsg_free(msg);
+       return err;
+}
+
+static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
+               return -EOPNOTSUPP;
+
+       if (rdev->ap_beacons_nlpid)
+               return -EBUSY;
+
+       rdev->ap_beacons_nlpid = info->snd_pid;
+
+       return 0;
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -6387,6 +6505,30 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_UNEXPECTED_FRAME,
+               .doit = nl80211_register_unexpected_frame,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_PROBE_CLIENT,
+               .doit = nl80211_probe_client,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_REGISTER_BEACONS,
+               .doit = nl80211_register_beacons,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6639,10 +6781,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
        if (wiphy_idx_valid(request->wiphy_idx))
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@ -6678,10 +6817,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6762,10 +6898,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
        NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6821,10 +6954,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
        if (resp_ie)
                NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6862,10 +6992,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
        if (resp_ie)
                NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6903,10 +7030,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
        if (ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, GFP_KERNEL);
@@ -6939,10 +7063,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6977,10 +7098,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
        if (ie_len && ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7019,10 +7137,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
        if (tsc)
                NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7073,10 +7188,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
                goto nla_put_failure;
        nla_nest_end(msg, nl_freq);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@ -7119,10 +7231,7 @@ static void nl80211_send_remain_on_chan_event(
        if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7193,10 +7302,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7207,13 +7313,68 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
+static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
+                                      const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+       u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid);
+
+       if (!nlpid)
+               return false;
+
+       msg = nlmsg_new(100, gfp);
+       if (!msg)
+               return true;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return true;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
+               nlmsg_free(msg);
+               return true;
+       }
+
+       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+       return true;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+       return true;
+}
+
+bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
+{
+       return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
+                                         addr, gfp);
+}
+
+bool nl80211_unexpected_4addr_frame(struct net_device *dev,
+                                   const u8 *addr, gfp_t gfp)
+{
+       return __nl80211_unexpected_frame(dev,
+                                         NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+                                         addr, gfp);
+}
+
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
                      struct net_device *netdev, u32 nlpid,
                      int freq, const u8 *buf, size_t len, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
-       int err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
@@ -7230,16 +7391,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return err;
-       }
+       genlmsg_end(msg, hdr);
 
-       err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
-       if (err < 0)
-               return err;
-       return 0;
+       return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -7272,10 +7426,7 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
        if (ack)
                NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
@@ -7317,10 +7468,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, pinfoattr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7362,10 +7510,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, rekey_attr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7408,10 +7553,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, attr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7453,7 +7595,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, pinfoattr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
+       genlmsg_end(msg, hdr);
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
+void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+                          u64 cookie, bool acked, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+       if (acked)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -7466,6 +7646,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_probe_status);
+
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+                                const u8 *frame, size_t len,
+                                int freq, gfp_t gfp)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid);
+
+       if (!nlpid)
+               return;
+
+       msg = nlmsg_new(len + 100, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       if (freq)
+               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_report_obss_beacon);
 
 static int nl80211_netlink_notify(struct notifier_block * nb,
                                  unsigned long state,
@@ -7480,9 +7699,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
        rcu_read_lock();
 
-       list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
+       list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
                list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
                        cfg80211_mlme_unregister_socket(wdev, notify->pid);
+               if (rdev->ap_beacons_nlpid == notify->pid)
+                       rdev->ap_beacons_nlpid = 0;
+       }
 
        rcu_read_unlock();
 
index f24a1fbeaf19a8bf3cee73a3ec8b3b33d6e0f0ad..12bf4d185abe7dd1f0e89494261c3441faab3680 100644 (file)
@@ -117,4 +117,9 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
                                    struct net_device *netdev, int index,
                                    const u8 *bssid, bool preauth, gfp_t gfp);
 
+bool nl80211_unexpected_frame(struct net_device *dev,
+                             const u8 *addr, gfp_t gfp);
+bool nl80211_unexpected_4addr_frame(struct net_device *dev,
+                                   const u8 *addr, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index dc23b31594e0f54758d0b59ffa5854c6e426e2e8..31119e32e092b6e2615a8653c768a5cd7531465b 100644 (file)
@@ -355,8 +355,8 @@ static bool is_mesh(struct cfg80211_bss *a,
            sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
 }
 
-static int cmp_bss(struct cfg80211_bss *a,
-                  struct cfg80211_bss *b)
+static int cmp_bss_core(struct cfg80211_bss *a,
+                       struct cfg80211_bss *b)
 {
        int r;
 
@@ -378,7 +378,15 @@ static int cmp_bss(struct cfg80211_bss *a,
                               b->len_information_elements);
        }
 
-       r = memcmp(a->bssid, b->bssid, ETH_ALEN);
+       return memcmp(a->bssid, b->bssid, ETH_ALEN);
+}
+
+static int cmp_bss(struct cfg80211_bss *a,
+                  struct cfg80211_bss *b)
+{
+       int r;
+
+       r = cmp_bss_core(a, b);
        if (r)
                return r;
 
@@ -389,6 +397,52 @@ static int cmp_bss(struct cfg80211_bss *a,
                       b->len_information_elements);
 }
 
+static int cmp_hidden_bss(struct cfg80211_bss *a,
+                  struct cfg80211_bss *b)
+{
+       const u8 *ie1;
+       const u8 *ie2;
+       int i;
+       int r;
+
+       r = cmp_bss_core(a, b);
+       if (r)
+               return r;
+
+       ie1 = cfg80211_find_ie(WLAN_EID_SSID,
+                       a->information_elements,
+                       a->len_information_elements);
+       ie2 = cfg80211_find_ie(WLAN_EID_SSID,
+                       b->information_elements,
+                       b->len_information_elements);
+
+       /* Key comparator must use same algorithm in any rb-tree
+        * search function (order is important), otherwise ordering
+        * of items in the tree is broken and search gives incorrect
+        * results. This code uses same order as cmp_ies() does. */
+
+       /* sort missing IE before (left of) present IE */
+       if (!ie1)
+               return -1;
+       if (!ie2)
+               return 1;
+
+       /* zero-size SSID is used as an indication of the hidden bss */
+       if (!ie2[1])
+               return 0;
+
+       /* sort by length first, then by contents */
+       if (ie1[1] != ie2[1])
+               return ie2[1] - ie1[1];
+
+       /* zeroed SSID ie is another indication of a hidden bss */
+       for (i = 0; i < ie2[1]; i++)
+               if (ie2[i + 2])
+                       return -1;
+
+       return 0;
+}
+
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      struct ieee80211_channel *channel,
                                      const u8 *bssid,
@@ -504,6 +558,48 @@ rb_find_bss(struct cfg80211_registered_device *dev,
        return NULL;
 }
 
+static struct cfg80211_internal_bss *
+rb_find_hidden_bss(struct cfg80211_registered_device *dev,
+           struct cfg80211_internal_bss *res)
+{
+       struct rb_node *n = dev->bss_tree.rb_node;
+       struct cfg80211_internal_bss *bss;
+       int r;
+
+       while (n) {
+               bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
+               r = cmp_hidden_bss(&res->pub, &bss->pub);
+
+               if (r == 0)
+                       return bss;
+               else if (r < 0)
+                       n = n->rb_left;
+               else
+                       n = n->rb_right;
+       }
+
+       return NULL;
+}
+
+static void
+copy_hidden_ies(struct cfg80211_internal_bss *res,
+                struct cfg80211_internal_bss *hidden)
+{
+       if (unlikely(res->pub.beacon_ies))
+               return;
+       if (WARN_ON(!hidden->pub.beacon_ies))
+               return;
+
+       res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC);
+       if (unlikely(!res->pub.beacon_ies))
+               return;
+
+       res->beacon_ies_allocated = true;
+       res->pub.len_beacon_ies = hidden->pub.len_beacon_ies;
+       memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies,
+                       res->pub.len_beacon_ies);
+}
+
 static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *dev,
                    struct cfg80211_internal_bss *res)
@@ -607,6 +703,21 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
                kref_put(&res->ref, bss_release);
        } else {
+               struct cfg80211_internal_bss *hidden;
+
+               /* First check if the beacon is a probe response from
+                * a hidden bss. If so, copy beacon ies (with nullified
+                * ssid) into the probe response bss entry (with real ssid).
+                * It is required basically for PSM implementation
+                * (probe responses do not contain tim ie) */
+
+               /* TODO: The code is not trying to update existing probe
+                * response bss entries when beacon ies are
+                * getting changed. */
+               hidden = rb_find_hidden_bss(dev, res);
+               if (hidden)
+                       copy_hidden_ies(res, hidden);
+
                /* this "consumes" the reference */
                list_add_tail(&res->list, &dev->bss_list);
                rb_insert_bss(dev, res);
index 6897436b1d3f9166c3df9ceafd7f1b84fabed9de..3c24eb97e9d7f0eaf60cff02f2372967f29e5284 100644 (file)
@@ -819,12 +819,24 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                                 struct iw_freq *freq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct ieee80211_channel *chan;
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
                return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+       case NL80211_IFTYPE_MONITOR:
+               if (!rdev->ops->get_channel)
+                       return -EINVAL;
+
+               chan = rdev->ops->get_channel(wdev->wiphy);
+               if (!chan)
+                       return -EINVAL;
+               freq->m = chan->center_freq;
+               freq->e = 6;
+               return 0;
        default:
                if (!wdev->channel)
                        return -EINVAL;