Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nftables
authorDavid S. Miller <davem@davemloft.net>
Thu, 16 Jan 2014 19:44:54 +0000 (11:44 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 16 Jan 2014 19:44:54 +0000 (11:44 -0800)
Pablo Neira Ayuso says:

====================
This small batch contains several Netfilter fixes for your net-next
tree, more specifically:

* Fix compilation warning in nft_ct in NF_CONNTRACK_MARK is not set,
  from Kristian Evensen.

* Add dependency to IPV6 for NF_TABLES_INET. This one has been reported
  by the several robots that are testing .config combinations, from Paul
  Gortmaker.

* Fix default base chain policy setting in nf_tables, from myself.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
672 files changed:
Documentation/ABI/testing/sysfs-class-net-mesh
Documentation/devicetree/bindings/clock/exynos5250-clock.txt
Documentation/networking/batman-adv.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/packet_mmap.txt
Documentation/networking/pktgen.txt
Documentation/s390/qeth.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arc/include/asm/Kbuild
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/crypto/aesbs-core.S_shipped
arch/arm/crypto/bsaes-armv7.pl
arch/arm/include/asm/io.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/xen/page.h
arch/arm/kernel/traps.c
arch/arm/mach-footbridge/dc21285-timer.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mm/flush.c
arch/cris/include/asm/Kbuild
arch/hexagon/include/asm/Kbuild
arch/microblaze/include/asm/Kbuild
arch/mn10300/include/asm/Kbuild
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/page.h
arch/parisc/kernel/cache.c
arch/s390/Kconfig
arch/s390/include/asm/css_chars.h
arch/s390/include/asm/qdio.h
arch/s390/include/asm/smp.h
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/pci/pci_event.c
arch/score/include/asm/Kbuild
arch/sh/kernel/sh_ksyms_32.c
arch/sparc/include/asm/uaccess_64.h
arch/sparc/kernel/iommu.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/kgdb_64.c
arch/sparc/kernel/smp_64.c
arch/x86/kvm/lapic.c
arch/x86/kvm/vmx.c
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/ata/ahci.c
drivers/ata/sata_sis.c
drivers/bcma/driver_chipcommon_sflash.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_vhci.c
drivers/char/tpm/tpm_ppi.c
drivers/clk/clk-divider.c
drivers/clk/samsung/clk-exynos-audss.c
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5250.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpuidle/cpuidle-calxeda.c
drivers/crypto/ixp4xx_crypto.c
drivers/dma/ioat/dma.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/nouveau/core/core/subdev.c
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/include/subdev/fb.h
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/si.c
drivers/idle/intel_idle.c
drivers/infiniband/core/cma.c
drivers/input/input.c
drivers/input/touchscreen/zforce_ts.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/mfd/rtsx_pcr.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_main.c
drivers/net/can/Kconfig
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/ti_hecc.c
drivers/net/eql.c
drivers/net/ethernet/3com/3c509.c
drivers/net/ethernet/amd/amd8111e.h
drivers/net/ethernet/atheros/alx/alx.h
drivers/net/ethernet/atheros/alx/ethtool.c
drivers/net/ethernet/atheros/alx/hw.c
drivers/net/ethernet/atheros/alx/hw.h
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/atheros/alx/reg.h
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/atheros/atlx/atl1.c
drivers/net/ethernet/atheros/atlx/atl1.h
drivers/net/ethernet/broadcom/bgmac.c
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_link.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/chelsio/cxgb4/l2t.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/freescale/gianfar_ethtool.c
drivers/net/ethernet/freescale/gianfar_ptp.c
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/i40e/Makefile
drivers/net/ethernet/intel/i40e/Module.symvers [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_hmc.c
drivers/net/ethernet/intel/i40e/i40e_hmc.h
drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_ptp.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/Kconfig
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/tehuti/tehuti.c
drivers/net/ethernet/tile/tilegx.c
drivers/net/macvlan.c
drivers/net/phy/phy_device.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/Kconfig
drivers/net/usb/cdc_ether.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c
drivers/net/usb/usbnet.c
drivers/net/vxlan.c
drivers/net/wan/hd64570.h
drivers/net/wan/hd64572.h
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar953x_initvals.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/spectral.c
drivers/net/wireless/ath/ath9k/wow.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/debug.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/wil6210/interrupt.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/atmel.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/atmel_pci.c
drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
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/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
drivers/net/wireless/brcm80211/include/brcmu_wifi.h
drivers/net/wireless/cw1200/fwio.c
drivers/net/wireless/cw1200/main.c
drivers/net/wireless/cw1200/pm.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/hostap/hostap_pci.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlegacy/3945-rs.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlegacy/4965.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/dvm/agn.h
drivers/net/wireless/iwlwifi/dvm/calib.c
drivers/net/wireless/iwlwifi/dvm/calib.h
drivers/net/wireless/iwlwifi/dvm/commands.h
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/devices.c
drivers/net/wireless/iwlwifi/dvm/led.c
drivers/net/wireless/iwlwifi/dvm/led.h
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/power.c
drivers/net/wireless/iwlwifi/dvm/power.h
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/iwlwifi/dvm/rs.h
drivers/net/wireless/iwlwifi/dvm/rx.c
drivers/net/wireless/iwlwifi/dvm/rxon.c
drivers/net/wireless/iwlwifi/dvm/scan.c
drivers/net/wireless/iwlwifi/dvm/sta.c
drivers/net/wireless/iwlwifi/dvm/tt.c
drivers/net/wireless/iwlwifi/dvm/tt.h
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-modparams.h
drivers/net/wireless/iwlwifi/iwl-notif-wait.c
drivers/net/wireless/iwlwifi/iwl-notif-wait.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-phy-db.c
drivers/net/wireless/iwlwifi/iwl-phy-db.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/binding.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/led.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/power_legacy.c
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sf.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/testmode.h
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.h
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/hermes.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/p54/eeprom.c
drivers/net/wireless/p54/fwio.c
drivers/net/wireless/p54/led.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl8180/grf5101.c
drivers/net/wireless/rtl818x/rtl8180/max2820.c
drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
drivers/net/wireless/rtl818x/rtl8180/sa2400.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/ti/wl1251/acx.c
drivers/net/wireless/ti/wl1251/acx.h
drivers/net/wireless/ti/wl1251/boot.c
drivers/net/wireless/ti/wl1251/cmd.c
drivers/net/wireless/ti/wl1251/cmd.h
drivers/net/wireless/ti/wl1251/event.c
drivers/net/wireless/ti/wl1251/event.h
drivers/net/wireless/ti/wl1251/init.c
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/ti/wl1251/rx.c
drivers/net/wireless/ti/wl1251/tx.c
drivers/net/wireless/ti/wl1251/wl1251.h
drivers/net/wireless/wl3501_cs.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/of/of_mdio.c
drivers/of/of_net.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/pci-acpi.c
drivers/phy/Kconfig
drivers/power/Kconfig
drivers/power/power_supply_core.c
drivers/ptp/Kconfig
drivers/s390/char/tty3270.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/qdio_main.c
drivers/s390/net/Makefile
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_mpc.c
drivers/s390/net/qeth_core_mpc.h
drivers/s390/net/qeth_l2.h [new file with mode: 0644]
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l2_sys.c [new file with mode: 0644]
drivers/ssb/driver_chipcommon_sflash.c
drivers/staging/bcm/Bcmnet.c
drivers/staging/cxt1e1/linux.c
drivers/staging/dgap/Kconfig
drivers/staging/iio/adc/Kconfig
drivers/staging/netlogic/xlr_net.c
drivers/staging/rtl8188eu/os_dep/os_intfs.c
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/cifs/link.c
fs/eventpoll.c
fs/ext4/extents.c
fs/gfs2/aops.c
fs/gfs2/glock.c
fs/gfs2/glops.c
fs/gfs2/log.c
fs/gfs2/meta_io.c
fs/gfs2/ops_fstype.c
fs/xfs/xfs_attr_remote.c
fs/xfs/xfs_bmap_util.c
include/acpi/acpi_bus.h
include/drm/drm_pciids.h
include/linux/etherdevice.h
include/linux/mmc/sdio_ids.h
include/linux/net.h
include/linux/netdevice.h
include/linux/of_mdio.h
include/linux/phy.h
include/linux/skbuff.h
include/net/act_api.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/ip.h
include/net/ipv6.h
include/net/mac80211.h
include/net/neighbour.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/net/pkt_cls.h
include/net/protocol.h
include/net/red.h
include/net/route.h
include/net/sch_generic.h
include/net/sctp/structs.h
include/net/xfrm.h
include/trace/events/net.h
include/uapi/drm/radeon_drm.h
include/uapi/linux/if_addr.h
include/uapi/linux/if_arp.h
include/uapi/linux/input.h
include/uapi/linux/netfilter/Kbuild
include/uapi/linux/netfilter/xt_l2tp.h [new file with mode: 0644]
include/uapi/linux/nl80211.h
include/uapi/linux/tcp_metrics.h
mm/fremap.c
mm/huge_memory.c
mm/memcontrol.c
mm/memory-failure.c
mm/mlock.c
net/802/garp.c
net/802/hippi.c
net/802/mrp.c
net/Makefile
net/batman-adv/Makefile
net/batman-adv/bat_algo.h
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bitarray.c
net/batman-adv/bitarray.h
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/bridge_loop_avoidance.h
net/batman-adv/debugfs.c
net/batman-adv/debugfs.h
net/batman-adv/distributed-arp-table.c
net/batman-adv/distributed-arp-table.h
net/batman-adv/fragmentation.c
net/batman-adv/fragmentation.h
net/batman-adv/gateway_client.c
net/batman-adv/gateway_client.h
net/batman-adv/gateway_common.c
net/batman-adv/gateway_common.h
net/batman-adv/hard-interface.c
net/batman-adv/hard-interface.h
net/batman-adv/hash.c
net/batman-adv/hash.h
net/batman-adv/icmp_socket.c
net/batman-adv/icmp_socket.h
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/network-coding.c
net/batman-adv/network-coding.h
net/batman-adv/originator.c
net/batman-adv/originator.h
net/batman-adv/packet.h
net/batman-adv/routing.c
net/batman-adv/routing.h
net/batman-adv/send.c
net/batman-adv/send.h
net/batman-adv/soft-interface.c
net/batman-adv/soft-interface.h
net/batman-adv/sysfs.c
net/batman-adv/sysfs.h
net/batman-adv/translation-table.c
net/batman-adv/translation-table.h
net/batman-adv/types.h
net/bluetooth/6lowpan.c [new file with mode: 0644]
net/bluetooth/6lowpan.h [new file with mode: 0644]
net/bluetooth/Kconfig
net/bluetooth/Makefile
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/rfcomm/tty.c
net/bridge/br.c
net/bridge/br_if.c
net/bridge/br_private.h
net/caif/chnl_net.c
net/can/gw.c
net/core/dev.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/netpoll.c
net/core/pktgen.c
net/core/skbuff.c
net/core/stream.c
net/dcb/dcbnl.c
net/dccp/ipv4.c
net/decnet/dn_route.c
net/ieee802154/6lowpan.c
net/ieee802154/6lowpan.h
net/ieee802154/6lowpan_iphc.c [new file with mode: 0644]
net/ieee802154/Kconfig
net/ieee802154/Makefile
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/gre_offload.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_forward.c
net/ipv4/ip_output.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_offload.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/fib6_rules.c
net/ipv6/icmp.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/sysctl_net_ipv6.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/mac80211/aes_cmac.c
net/mac80211/aes_cmac.h
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/tkip.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/nf_conntrack_seqadj.c
net/netfilter/nf_nat_irc.c
net/netfilter/xt_l2tp.c [new file with mode: 0644]
net/netfilter/xt_statistic.c
net/nfc/core.c
net/nfc/hci/llc_shdlc.c
net/openvswitch/actions.c
net/rds/bind.c
net/sched/act_api.c
net/sched/act_csum.c
net/sched/act_gact.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/cls_api.c
net/sched/cls_basic.c
net/sched/cls_bpf.c
net/sched/cls_cgroup.c
net/sched/cls_flow.c
net/sched/cls_fw.c
net/sched/cls_route.c
net/sched/cls_rsvp.h
net/sched/cls_tcindex.c
net/sched/cls_u32.c
net/sched/sch_fq_codel.c
net/sched/sch_generic.c
net/sched/sch_hhf.c
net/sched/sch_netem.c
net/sched/sch_pie.c
net/sched/sch_sfb.c
net/sched/sch_sfq.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/socket.c
net/sunrpc/cache.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
net/tipc/bearer.c
net/tipc/link.c
net/tipc/server.c
net/tipc/subscr.c
net/wireless/ap.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_proc.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c

index 0baa657..4793d3d 100644 (file)
@@ -68,6 +68,14 @@ Description:
                 Defines the penalty which will be applied to an
                 originator message's tq-field on every hop.
 
+What:          /sys/class/net/<mesh_iface>/mesh/isolation_mark
+Date:          Nov 2013
+Contact:       Antonio Quartulli <antonio@meshcoding.com>
+Description:
+               Defines the isolation mark (and its bitmask) which
+               is used to classify clients as "isolated" by the
+               Extended Isolation feature.
+
 What:           /sys/class/net/<mesh_iface>/mesh/network_coding
 Date:           Nov 2012
 Contact:        Martin Hundeboll <martin@hundeboll.net>
index 46f5c79..0f2f920 100644 (file)
@@ -159,6 +159,8 @@ clock which they consume.
   mixer                        343
   hdmi                 344
   g2d                  345
+  mdma0                        346
+  smmu_mdma0           347
 
 
    [Clock Muxes]
index 89490be..58e4904 100644 (file)
@@ -66,11 +66,10 @@ All  mesh  wide  settings  can be found in batman's own interface
 folder:
 
 # ls /sys/class/net/bat0/mesh/
-# aggregated_ogms        gw_bandwidth           log_level
-# ap_isolation           gw_mode                orig_interval
-# bonding                gw_sel_class           routing_algo
-# bridge_loop_avoidance  hop_penalty            fragmentation
-
+#aggregated_ogms        distributed_arp_table  gw_sel_class    orig_interval
+#ap_isolation           fragmentation          hop_penalty     routing_algo
+#bonding                gw_bandwidth           isolation_mark  vlan0
+#bridge_loop_avoidance  gw_mode                log_level
 
 There is a special folder for debugging information:
 
index 7373115..c97932c 100644 (file)
@@ -26,12 +26,36 @@ ip_no_pmtu_disc - INTEGER
        discarded. Outgoing frames are handled the same as in mode 1,
        implicitly setting IP_PMTUDISC_DONT on every created socket.
 
-       Possible values: 0-2
+       Mode 3 is a hardend pmtu discover mode. The kernel will only
+       accept fragmentation-needed errors if the underlying protocol
+       can verify them besides a plain socket lookup. Current
+       protocols for which pmtu events will be honored are TCP, SCTP
+       and DCCP as they verify e.g. the sequence number or the
+       association. This mode should not be enabled globally but is
+       only intended to secure e.g. name servers in namespaces where
+       TCP path mtu must still work but path MTU information of other
+       protocols should be discarded. If enabled globally this mode
+       could break other protocols.
+
+       Possible values: 0-3
        Default: FALSE
 
 min_pmtu - INTEGER
        default 552 - minimum discovered Path MTU
 
+ip_forward_use_pmtu - BOOLEAN
+       By default we don't trust protocol path MTUs while forwarding
+       because they could be easily forged and can lead to unwanted
+       fragmentation by the router.
+       You only need to enable this if you have user-space software
+       which tries to discover path mtus by itself and depends on the
+       kernel honoring this information. This is normally not the
+       case.
+       Default: 0 (disabled)
+       Possible values:
+       0 - disabled
+       1 - enabled
+
 route/max_size - INTEGER
        Maximum number of routes allowed in the kernel.  Increase
        this when using large numbers of interfaces and/or routes.
index 723bf3d..91ffe1d 100644 (file)
@@ -98,6 +98,11 @@ by the kernel.
 The destruction of the socket and all associated resources
 is done by a simple call to close(fd).
 
+Similarly as without PACKET_MMAP, it is possible to use one socket
+for capture and transmission. This can be done by mapping the
+allocated RX and TX buffer ring with a single mmap() call.
+See "Mapping and use of the circular buffer (ring)".
+
 Next I will describe PACKET_MMAP settings and its constraints,
 also the mapping of the circular buffer in the user process and 
 the use of this buffer.
@@ -414,6 +419,19 @@ tp_block_size/tp_frame_size frames there will be a gap between
 the frames. This is because a frame cannot be spawn across two
 blocks. 
 
+To use one socket for capture and transmission, the mapping of both the
+RX and TX buffer ring has to be done with one call to mmap:
+
+    ...
+    setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &foo, sizeof(foo));
+    setsockopt(fd, SOL_PACKET, PACKET_TX_RING, &bar, sizeof(bar));
+    ...
+    rx_ring = mmap(0, size * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    tx_ring = rx_ring + size;
+
+RX must be the first as the kernel maps the TX ring memory right
+after the RX one.
+
 At the beginning of each frame there is an status field (see 
 struct tpacket_hdr). If this field is 0 means that the frame is ready
 to be used for the kernel, If not, there is a frame the user can read 
index 75e4fd7..5a61a24 100644 (file)
@@ -108,7 +108,9 @@ Examples:
                               MPLS_RND, VID_RND, SVID_RND
                               QUEUE_MAP_RND # queue map random
                               QUEUE_MAP_CPU # queue map mirrors smp_processor_id()
+                              IPSEC # Make IPsec encapsulation for packet
 
+ pgset spi SPI_VALUE     Set specific SA used to transform packet.
 
  pgset "udp_src_min 9"   set UDP source port min, If < udp_src_max, then
                          cycle through the port range.
@@ -177,6 +179,18 @@ Note when adding devices to a specific CPU there good idea to also assign
 /proc/irq/XX/smp_affinity so the TX-interrupts gets bound to the same CPU.
 as this reduces cache bouncing when freeing skb's.
 
+Enable IPsec
+============
+Default IPsec transformation with ESP encapsulation plus Transport mode
+could be enabled by simply setting:
+
+pgset "flag IPSEC"
+pgset "flows 1"
+
+To avoid breaking existing testbed scripts for using AH type and tunnel mode,
+user could use "pgset spi SPI_VALUE" to specify which formal of transformation
+to employ.
+
 
 Current commands and configuration options
 ==========================================
@@ -225,6 +239,7 @@ flag
   UDPDST_RND
   MACSRC_RND
   MACDST_RND
+  IPSEC
 
 dst_min
 dst_max
diff --git a/Documentation/s390/qeth.txt b/Documentation/s390/qeth.txt
new file mode 100644 (file)
index 0000000..74122ad
--- /dev/null
@@ -0,0 +1,50 @@
+IBM s390 QDIO Ethernet Driver
+
+HiperSockets Bridge Port Support
+
+Uevents
+
+To generate the events the device must be assigned a role of either
+a primary or a secondary Bridge Port. For more information, see
+"z/VM Connectivity, SC24-6174".
+
+When run on HiperSockets Bridge Capable Port hardware, and the state
+of some configured Bridge Port device on the channel changes, a udev
+event with ACTION=CHANGE is emitted on behalf of the corresponding
+ccwgroup device. The event has the following attributes:
+
+BRIDGEPORT=statechange -  indicates that the Bridge Port device changed
+  its state.
+
+ROLE={primary|secondary|none} - the role assigned to the port.
+
+STATE={active|standby|inactive} - the newly assumed state of the port.
+
+When run on HiperSockets Bridge Capable Port hardware with host address
+notifications enabled, a udev event with ACTION=CHANGE is emitted.
+It is emitted on behalf of the corresponding ccwgroup device when a host
+or a VLAN is registered or unregistered on the network served by the device.
+The event has the following attributes:
+
+BRIDGEDHOST={reset|register|deregister|abort} - host address
+  notifications are started afresh, a new host or VLAN is registered or
+  deregistered on the Bridge Port HiperSockets channel, or address
+  notifications are aborted.
+
+VLAN=numeric-vlan-id - VLAN ID on which the event occurred. Not included
+  if no VLAN is involved in the event.
+
+MAC=xx:xx:xx:xx:xx:xx - MAC address of the host that is being registered
+  or deregistered from the HiperSockets channel. Not reported if the
+  event reports the creation or destruction of a VLAN.
+
+NTOK_BUSID=x.y.zzzz - device bus ID (CSSID, SSID and device number).
+
+NTOK_IID=xx - device IID.
+
+NTOK_CHPID=xx - device CHPID.
+
+NTOK_CHID=xxxx - device channel ID.
+
+Note that the NTOK_* attributes refer to devices other than  the one
+connected to the system on which the OS is running.
index e11d495..b358a3f 100644 (file)
@@ -1368,6 +1368,9 @@ T:        git git://git.xilinx.com/linux-xlnx.git
 S:     Supported
 F:     arch/arm/mach-zynq/
 F:     drivers/cpuidle/cpuidle-zynq.c
+N:     zynq
+N:     xilinx
+F:     drivers/clocksource/cadence_ttc_timer.c
 
 ARM SMMU DRIVER
 M:     Will Deacon <will.deacon@arm.com>
@@ -2815,8 +2818,10 @@ F:       include/uapi/drm/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Daniel Vetter <daniel.vetter@ffwll.ch>
+M:     Jani Nikula <jani.nikula@linux.intel.com>
 L:     intel-gfx@lists.freedesktop.org
 L:     dri-devel@lists.freedesktop.org
+Q:     http://patchwork.freedesktop.org/project/intel-gfx/
 T:     git git://people.freedesktop.org/~danvet/drm-intel
 S:     Supported
 F:     drivers/gpu/drm/i915/
index ab80be7..ae1a55a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 13
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc7
 NAME = One Giant Leap for Frogkind
 
 # *DOCUMENTATION*
index 93e6ca9..cf29d84 100644 (file)
@@ -11,6 +11,7 @@ generic-y += fcntl.h
 generic-y += fb.h
 generic-y += ftrace.h
 generic-y += hardirq.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -47,4 +48,3 @@ generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
 generic-y += preempt.h
-generic-y += hash.h
index 9db5047..177becd 100644 (file)
                        compatible = "arm,pl330", "arm,primecell";
                        reg = <0x10800000 0x1000>;
                        interrupts = <0 33 0>;
-                       clocks = <&clock 271>;
+                       clocks = <&clock 346>;
                        clock-names = "apb_pclk";
                        #dma-cells = <1>;
                        #dma-channels = <8>;
index 64205d4..71e5fc7 100644 (file)
@@ -58,7 +58,7 @@
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_ARCH__  7
 #endif
 
 #ifdef __thumb__
index f3d96d9..be068db 100644 (file)
@@ -701,7 +701,7 @@ $code.=<<___;
 # define VFP_ABI_FRAME 0
 # define BSAES_ASM_EXTENDED_KEY
 # define XTS_CHAIN_TWEAK
-# define __ARM_ARCH__ __LINUX_ARM_ARCH__
+# define __ARM_ARCH__  7
 #endif
 
 #ifdef __thumb__
index 3c597c2..fbeb39c 100644 (file)
@@ -329,7 +329,7 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
  */
 #define ioremap(cookie,size)           __arm_ioremap((cookie), (size), MT_DEVICE)
 #define ioremap_nocache(cookie,size)   __arm_ioremap((cookie), (size), MT_DEVICE)
-#define ioremap_cached(cookie,size)    __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
+#define ioremap_cache(cookie,size)     __arm_ioremap((cookie), (size), MT_DEVICE_CACHED)
 #define ioremap_wc(cookie,size)                __arm_ioremap((cookie), (size), MT_DEVICE_WC)
 #define iounmap                                __arm_iounmap
 
index 6976b03..8756e4b 100644 (file)
@@ -347,7 +347,8 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
 #define ARCH_PFN_OFFSET                PHYS_PFN_OFFSET
 
 #define virt_to_page(kaddr)    pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory)
+#define virt_addr_valid(kaddr) (((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) \
+                                       && pfn_valid(__pa(kaddr) >> PAGE_SHIFT) )
 
 #endif
 
index 75579a9..3759cac 100644 (file)
@@ -117,6 +117,6 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
        return __set_phys_to_machine(pfn, mfn);
 }
 
-#define xen_remap(cookie, size) ioremap_cached((cookie), (size));
+#define xen_remap(cookie, size) ioremap_cache((cookie), (size));
 
 #endif /* _ASM_ARM_XEN_PAGE_H */
index 7940241..6eda3bf 100644 (file)
 #include <asm/system_misc.h>
 #include <asm/opcodes.h>
 
-static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
+static const char *handler[]= {
+       "prefetch abort",
+       "data abort",
+       "address exception",
+       "interrupt",
+       "undefined instruction",
+};
 
 void *vectors_page;
 
index 9ee78f7..782f6c7 100644 (file)
@@ -96,11 +96,12 @@ static struct irqaction footbridge_timer_irq = {
 void __init footbridge_timer_init(void)
 {
        struct clock_event_device *ce = &ckevt_dc21285;
+       unsigned rate = DIV_ROUND_CLOSEST(mem_fclk_21285, 16);
 
-       clocksource_register_hz(&cksrc_dc21285, (mem_fclk_21285 + 8) / 16);
+       clocksource_register_hz(&cksrc_dc21285, rate);
 
        setup_irq(ce->irq, &footbridge_timer_irq);
 
        ce->cpumask = cpumask_of(smp_processor_id());
-       clockevents_config_and_register(ce, mem_fclk_21285, 0x4, 0xffffff);
+       clockevents_config_and_register(ce, rate, 0x4, 0xffffff);
 }
index c186891..8ea87bd 100644 (file)
@@ -483,7 +483,7 @@ static struct platform_device lcdc0_device = {
        .id             = 0,
        .dev    = {
                .platform_data  = &lcdc0_info,
-               .coherent_dma_mask = ~0,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
@@ -580,7 +580,7 @@ static struct platform_device hdmi_lcdc_device = {
        .id             = 1,
        .dev    = {
                .platform_data  = &hdmi_lcdc_info,
-               .coherent_dma_mask = ~0,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
index fe689b7..bc40b85 100644 (file)
@@ -334,7 +334,7 @@ static struct platform_device lcdc_device = {
        .resource       = lcdc_resources,
        .dev    = {
                .platform_data  = &lcdc_info,
-               .coherent_dma_mask = ~0,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
index af06753..e721d2c 100644 (file)
@@ -409,7 +409,7 @@ static struct platform_device lcdc_device = {
        .resource       = lcdc_resources,
        .dev    = {
                .platform_data  = &lcdc_info,
-               .coherent_dma_mask = ~0,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
@@ -499,7 +499,7 @@ static struct platform_device hdmi_lcdc_device = {
        .id             = 1,
        .dev    = {
                .platform_data  = &hdmi_lcdc_info,
-               .coherent_dma_mask = ~0,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
        },
 };
 
index 6d5ba9a..3387e60 100644 (file)
@@ -175,16 +175,16 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
                unsigned long i;
                if (cache_is_vipt_nonaliasing()) {
                        for (i = 0; i < (1 << compound_order(page)); i++) {
-                               void *addr = kmap_atomic(page);
+                               void *addr = kmap_atomic(page + i);
                                __cpuc_flush_dcache_area(addr, PAGE_SIZE);
                                kunmap_atomic(addr);
                        }
                } else {
                        for (i = 0; i < (1 << compound_order(page)); i++) {
-                               void *addr = kmap_high_get(page);
+                               void *addr = kmap_high_get(page + i);
                                if (addr) {
                                        __cpuc_flush_dcache_area(addr, PAGE_SIZE);
-                                       kunmap_high(page);
+                                       kunmap_high(page + i);
                                }
                        }
                }
index c5963b3..406cbd3 100644 (file)
@@ -5,6 +5,7 @@ header-y += arch-v32/
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += kvm_para.h
 generic-y += linkage.h
 generic-y += module.h
@@ -12,4 +13,3 @@ generic-y += trace_clock.h
 generic-y += vga.h
 generic-y += xor.h
 generic-y += preempt.h
-generic-y += hash.h
index 469d223..ae45d75 100644 (file)
@@ -15,6 +15,7 @@ generic-y += fb.h
 generic-y += fcntl.h
 generic-y += ftrace.h
 generic-y += hardirq.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ioctls.h
@@ -54,4 +55,3 @@ generic-y += ucontext.h
 generic-y += unaligned.h
 generic-y += xor.h
 generic-y += preempt.h
-generic-y += hash.h
index 43eec33..ca60945 100644 (file)
@@ -1,7 +1,7 @@
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += trace_clock.h
 generic-y += syscalls.h
 generic-y += preempt.h
-generic-y += hash.h
index bc42f14..1993452 100644 (file)
@@ -1,6 +1,6 @@
 
 generic-y += clkdev.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += trace_clock.h
 generic-y += preempt.h
-generic-y += hash.h
index f0e2784..2f9b751 100644 (file)
@@ -125,42 +125,38 @@ flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vma
 void mark_rodata_ro(void);
 #endif
 
-#ifdef CONFIG_PA8X00
-/* Only pa8800, pa8900 needs this */
-
 #include <asm/kmap_types.h>
 
 #define ARCH_HAS_KMAP
 
-void kunmap_parisc(void *addr);
-
 static inline void *kmap(struct page *page)
 {
        might_sleep();
+       flush_dcache_page(page);
        return page_address(page);
 }
 
 static inline void kunmap(struct page *page)
 {
-       kunmap_parisc(page_address(page));
+       flush_kernel_dcache_page_addr(page_address(page));
 }
 
 static inline void *kmap_atomic(struct page *page)
 {
        pagefault_disable();
+       flush_dcache_page(page);
        return page_address(page);
 }
 
 static inline void __kunmap_atomic(void *addr)
 {
-       kunmap_parisc(addr);
+       flush_kernel_dcache_page_addr(addr);
        pagefault_enable();
 }
 
 #define kmap_atomic_prot(page, prot)   kmap_atomic(page)
 #define kmap_atomic_pfn(pfn)   kmap_atomic(pfn_to_page(pfn))
 #define kmap_atomic_to_page(ptr)       virt_to_page(ptr)
-#endif
 
 #endif /* _PARISC_CACHEFLUSH_H */
 
index b7adb2a..c53fc63 100644 (file)
@@ -28,9 +28,8 @@ struct page;
 
 void clear_page_asm(void *page);
 void copy_page_asm(void *to, void *from);
-void clear_user_page(void *vto, unsigned long vaddr, struct page *pg);
-void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
-                          struct page *pg);
+#define clear_user_page(vto, vaddr, page) clear_page_asm(vto)
+#define copy_user_page(vto, vfrom, vaddr, page) copy_page_asm(vto, vfrom)
 
 /* #define CONFIG_PARISC_TMPALIAS */
 
index c035673..a725455 100644 (file)
@@ -388,41 +388,6 @@ void flush_kernel_dcache_page_addr(void *addr)
 }
 EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
 
-void clear_user_page(void *vto, unsigned long vaddr, struct page *page)
-{
-       clear_page_asm(vto);
-       if (!parisc_requires_coherency())
-               flush_kernel_dcache_page_asm(vto);
-}
-EXPORT_SYMBOL(clear_user_page);
-
-void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
-       struct page *pg)
-{
-       /* Copy using kernel mapping.  No coherency is needed
-          (all in kmap/kunmap) on machines that don't support
-          non-equivalent aliasing.  However, the `from' page
-          needs to be flushed before it can be accessed through
-          the kernel mapping. */
-       preempt_disable();
-       flush_dcache_page_asm(__pa(vfrom), vaddr);
-       preempt_enable();
-       copy_page_asm(vto, vfrom);
-       if (!parisc_requires_coherency())
-               flush_kernel_dcache_page_asm(vto);
-}
-EXPORT_SYMBOL(copy_user_page);
-
-#ifdef CONFIG_PA8X00
-
-void kunmap_parisc(void *addr)
-{
-       if (parisc_requires_coherency())
-               flush_kernel_dcache_page_addr(addr);
-}
-EXPORT_SYMBOL(kunmap_parisc);
-#endif
-
 void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 {
        unsigned long flags;
index 1e1a03d..e9f3125 100644 (file)
@@ -135,7 +135,6 @@ config S390
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_UID16 if 32BIT
        select HAVE_VIRT_CPU_ACCOUNTING
-       select INIT_ALL_POSSIBLE
        select KTIME_SCALAR if 32BIT
        select MODULES_USE_ELF_RELA
        select OLD_SIGACTION
index 7e1c917..09d1dd4 100644 (file)
@@ -29,6 +29,8 @@ struct css_general_char {
        u32 fcx : 1;     /* bit 88 */
        u32 : 19;
        u32 alt_ssi : 1; /* bit 108 */
+       u32:1;
+       u32 narf:1;      /* bit 110 */
 } __packed;
 
 extern struct css_general_char css_general_characteristics;
index 57d0d7e..0a1abf1 100644 (file)
@@ -378,6 +378,34 @@ struct qdio_initialize {
        struct qdio_outbuf_state *output_sbal_state_array;
 };
 
+/**
+ * enum qdio_brinfo_entry_type - type of address entry for qdio_brinfo_desc()
+ * @l3_ipv6_addr: entry contains IPv6 address
+ * @l3_ipv4_addr: entry contains IPv4 address
+ * @l2_addr_lnid: entry contains MAC address and VLAN ID
+ */
+enum qdio_brinfo_entry_type {l3_ipv6_addr, l3_ipv4_addr, l2_addr_lnid};
+
+/**
+ * struct qdio_brinfo_entry_XXX - Address entry for qdio_brinfo_desc()
+ * @nit:  Network interface token
+ * @addr: Address of one of the three types
+ *
+ * The struct is passed to the callback function by qdio_brinfo_desc()
+ */
+struct qdio_brinfo_entry_l3_ipv6 {
+       u64 nit;
+       struct { unsigned char _s6_addr[16]; } addr;
+} __packed;
+struct qdio_brinfo_entry_l3_ipv4 {
+       u64 nit;
+       struct { uint32_t _s_addr; } addr;
+} __packed;
+struct qdio_brinfo_entry_l2 {
+       u64 nit;
+       struct { u8 mac[6]; u16 lnid; } addr_lnid;
+} __packed;
+
 #define QDIO_STATE_INACTIVE            0x00000002 /* after qdio_cleanup */
 #define QDIO_STATE_ESTABLISHED         0x00000004 /* after qdio_establish */
 #define QDIO_STATE_ACTIVE              0x00000008 /* after qdio_activate */
@@ -399,5 +427,10 @@ extern int qdio_get_next_buffers(struct ccw_device *, int, int *, int *);
 extern int qdio_shutdown(struct ccw_device *, int);
 extern int qdio_free(struct ccw_device *);
 extern int qdio_get_ssqd_desc(struct ccw_device *, struct qdio_ssqd_desc *);
+extern int qdio_pnso_brinfo(struct subchannel_id schid,
+               int cnc, u16 *response,
+               void (*cb)(void *priv, enum qdio_brinfo_entry_type type,
+                               void *entry),
+               void *priv);
 
 #endif /* __QDIO_H__ */
index ac9bed8..1607793 100644 (file)
@@ -31,6 +31,7 @@ extern void smp_yield(void);
 extern void smp_stop_cpu(void);
 extern void smp_cpu_set_polarization(int cpu, int val);
 extern int smp_cpu_get_polarization(int cpu);
+extern void smp_fill_possible_mask(void);
 
 #else /* CONFIG_SMP */
 
@@ -50,6 +51,7 @@ static inline int smp_vcpu_scheduled(int cpu) { return 1; }
 static inline void smp_yield_cpu(int cpu) { }
 static inline void smp_yield(void) { }
 static inline void smp_stop_cpu(void) { }
+static inline void smp_fill_possible_mask(void) { }
 
 #endif /* CONFIG_SMP */
 
index 4444875..0f3d44e 100644 (file)
@@ -1023,6 +1023,7 @@ void __init setup_arch(char **cmdline_p)
        setup_vmcoreinfo();
        setup_lowcore();
 
+       smp_fill_possible_mask();
         cpu_init();
        s390_init_cpu_topology();
 
index dc4a534..9587047 100644 (file)
@@ -721,18 +721,14 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
        return 0;
 }
 
-static int __init setup_possible_cpus(char *s)
-{
-       int max, cpu;
+static unsigned int setup_possible_cpus __initdata;
 
-       if (kstrtoint(s, 0, &max) < 0)
-               return 0;
-       init_cpu_possible(cpumask_of(0));
-       for (cpu = 1; cpu < max && cpu < nr_cpu_ids; cpu++)
-               set_cpu_possible(cpu, true);
+static int __init _setup_possible_cpus(char *s)
+{
+       get_option(&s, &setup_possible_cpus);
        return 0;
 }
-early_param("possible_cpus", setup_possible_cpus);
+early_param("possible_cpus", _setup_possible_cpus);
 
 #ifdef CONFIG_HOTPLUG_CPU
 
@@ -775,6 +771,17 @@ void __noreturn cpu_die(void)
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
+void __init smp_fill_possible_mask(void)
+{
+       unsigned int possible, cpu;
+
+       possible = setup_possible_cpus;
+       if (!possible)
+               possible = MACHINE_IS_VM ? 64 : nr_cpu_ids;
+       for (cpu = 0; cpu < possible && cpu < nr_cpu_ids; cpu++)
+               set_cpu_possible(cpu, true);
+}
+
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        /* request the 0x1201 emergency signal external interrupt */
index 800f064..0696072 100644 (file)
@@ -75,6 +75,7 @@ void zpci_event_availability(void *data)
                if (!zdev || zdev->state == ZPCI_FN_STATE_CONFIGURED)
                        break;
                zdev->state = ZPCI_FN_STATE_CONFIGURED;
+               zdev->fh = ccdf->fh;
                ret = zpci_enable_device(zdev);
                if (ret)
                        break;
@@ -101,6 +102,7 @@ void zpci_event_availability(void *data)
                if (pdev)
                        pci_stop_and_remove_bus_device(pdev);
 
+               zdev->fh = ccdf->fh;
                zpci_disable_device(zdev);
                zdev->state = ZPCI_FN_STATE_STANDBY;
                break;
index 099e7ba..1d35e33 100644 (file)
@@ -2,8 +2,8 @@
 header-y +=
 
 generic-y += clkdev.h
+generic-y += hash.h
 generic-y += trace_clock.h
 generic-y += xor.h
 generic-y += preempt.h
-generic-y += hash.h
 
index 2a0a596..d77f2f6 100644 (file)
@@ -20,6 +20,11 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(__clear_user);
 EXPORT_SYMBOL(empty_zero_page);
+#ifdef CONFIG_FLATMEM
+/* need in pfn_valid macro */
+EXPORT_SYMBOL(min_low_pfn);
+EXPORT_SYMBOL(max_low_pfn);
+#endif
 
 #define DECLARE_EXPORT(name)           \
        extern void name(void);EXPORT_SYMBOL(name)
index e562d3c..ad7e178 100644 (file)
@@ -262,8 +262,8 @@ extern unsigned long __must_check __clear_user(void __user *, unsigned long);
 extern __must_check long strlen_user(const char __user *str);
 extern __must_check long strnlen_user(const char __user *str, long n);
 
-#define __copy_to_user_inatomic ___copy_to_user
-#define __copy_from_user_inatomic ___copy_from_user
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
 
 struct pt_regs;
 extern unsigned long compute_effective_address(struct pt_regs *,
index 070ed14..76663b0 100644 (file)
@@ -854,7 +854,7 @@ int dma_supported(struct device *dev, u64 device_mask)
                return 1;
 
 #ifdef CONFIG_PCI
-       if (dev->bus == &pci_bus_type)
+       if (dev_is_pci(dev))
                return pci64_dma_supported(to_pci_dev(dev), device_mask);
 #endif
 
index 2096468..e7e215d 100644 (file)
@@ -666,10 +666,9 @@ EXPORT_SYMBOL(dma_ops);
  */
 int dma_supported(struct device *dev, u64 mask)
 {
-#ifdef CONFIG_PCI
-       if (dev->bus == &pci_bus_type)
+       if (dev_is_pci(dev))
                return 1;
-#endif
+
        return 0;
 }
 EXPORT_SYMBOL(dma_supported);
index 60b19f5..b45fe3f 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/kgdb.h>
 #include <linux/kdebug.h>
 #include <linux/ftrace.h>
+#include <linux/context_tracking.h>
 
 #include <asm/cacheflush.h>
 #include <asm/kdebug.h>
index b66a533..b085311 100644 (file)
@@ -123,11 +123,12 @@ void smp_callin(void)
                rmb();
 
        set_cpu_online(cpuid, true);
-       local_irq_enable();
 
        /* idle thread is expected to have preempt disabled */
        preempt_disable();
 
+       local_irq_enable();
+
        cpu_startup_entry(CPUHP_ONLINE);
 }
 
index dec48bf..1673940 100644 (file)
@@ -1350,6 +1350,10 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
                return;
        }
 
+       if (!kvm_vcpu_is_bsp(apic->vcpu))
+               value &= ~MSR_IA32_APICBASE_BSP;
+       vcpu->arch.apic_base = value;
+
        /* update jump label if enable bit changes */
        if ((vcpu->arch.apic_base ^ value) & MSR_IA32_APICBASE_ENABLE) {
                if (value & MSR_IA32_APICBASE_ENABLE)
@@ -1359,10 +1363,6 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
                recalculate_apic_map(vcpu->kvm);
        }
 
-       if (!kvm_vcpu_is_bsp(apic->vcpu))
-               value &= ~MSR_IA32_APICBASE_BSP;
-
-       vcpu->arch.apic_base = value;
        if ((old_value ^ value) & X2APIC_ENABLE) {
                if (value & X2APIC_ENABLE) {
                        u32 id = kvm_apic_id(apic);
index b2fe1c2..da7837e 100644 (file)
@@ -8283,8 +8283,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
        vcpu->arch.cr4_guest_owned_bits = ~vmcs_readl(CR4_GUEST_HOST_MASK);
        kvm_set_cr4(vcpu, vmcs12->host_cr4);
 
-       if (nested_cpu_has_ept(vmcs12))
-               nested_ept_uninit_mmu_context(vcpu);
+       nested_ept_uninit_mmu_context(vcpu);
 
        kvm_set_cr3(vcpu, vmcs12->host_cr3);
        kvm_mmu_reset_context(vcpu);
index 8711e37..3c2e4aa 100644 (file)
@@ -207,7 +207,7 @@ static int acpi_ac_probe(struct platform_device *pdev)
                goto end;
 
        result = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
-                       ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, ac);
+                       ACPI_ALL_NOTIFY, acpi_ac_notify_handler, ac);
        if (result) {
                power_supply_unregister(&ac->charger);
                goto end;
@@ -255,7 +255,7 @@ static int acpi_ac_remove(struct platform_device *pdev)
                return -EINVAL;
 
        acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
-                       ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler);
+                       ACPI_ALL_NOTIFY, acpi_ac_notify_handler);
 
        ac = platform_get_drvdata(pdev);
        if (ac->charger.dev)
index fbf1ace..5876a49 100644 (file)
@@ -62,6 +62,7 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
 MODULE_DESCRIPTION("ACPI Battery Driver");
 MODULE_LICENSE("GPL");
 
+static int battery_bix_broken_package;
 static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
@@ -416,7 +417,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name));
                return -ENODEV;
        }
-       if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
+
+       if (battery_bix_broken_package)
+               result = extract_package(battery, buffer.pointer,
+                               extended_info_offsets + 1,
+                               ARRAY_SIZE(extended_info_offsets) - 1);
+       else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
                result = extract_package(battery, buffer.pointer,
                                extended_info_offsets,
                                ARRAY_SIZE(extended_info_offsets));
@@ -754,6 +760,17 @@ static int battery_notify(struct notifier_block *nb,
        return 0;
 }
 
+static struct dmi_system_id bat_dmi_table[] = {
+       {
+               .ident = "NEC LZ750/LS",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "NEC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"),
+               },
+       },
+       {},
+};
+
 static int acpi_battery_add(struct acpi_device *device)
 {
        int result = 0;
@@ -846,6 +863,9 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
 {
        if (acpi_disabled)
                return;
+
+       if (dmi_check_system(bat_dmi_table))
+               battery_bix_broken_package = 1;
        acpi_bus_register_driver(&acpi_battery_driver);
 }
 
index bba9b72..0710004 100644 (file)
@@ -156,6 +156,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
 }
 EXPORT_SYMBOL(acpi_bus_get_private_data);
 
+void acpi_bus_no_hotplug(acpi_handle handle)
+{
+       struct acpi_device *adev = NULL;
+
+       acpi_bus_get_device(handle, &adev);
+       if (adev)
+               adev->flags.no_hotplug = true;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_no_hotplug);
+
 static void acpi_print_osc_error(acpi_handle handle,
        struct acpi_osc_context *context, char *error)
 {
index c0ed4f2..e3a92a6 100644 (file)
@@ -427,6 +427,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
          .driver_data = board_ahci_yes_fbs },                  /* 88se9128 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9125 */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178,
+                        PCI_VENDOR_ID_MARVELL_EXT, 0x9170),
+         .driver_data = board_ahci_yes_fbs },                  /* 88se9170 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
          .driver_data = board_ahci_yes_fbs },                  /* 88se9172 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
index fe3ca09..1ad2f62 100644 (file)
@@ -83,6 +83,10 @@ static struct pci_driver sis_pci_driver = {
        .id_table               = sis_pci_tbl,
        .probe                  = sis_init_one,
        .remove                 = ata_pci_remove_one,
+#ifdef CONFIG_PM
+       .suspend                = ata_pci_device_suspend,
+       .resume                 = ata_pci_device_resume,
+#endif
 };
 
 static struct scsi_host_template sis_sht = {
index 4d07cce..7e11ef4 100644 (file)
@@ -38,7 +38,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
        { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
-       { 0 },
+       { NULL },
 };
 
 static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
@@ -56,7 +56,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
        { "SST25VF016", 0x41, 0x1000, 512, },
        { "SST25VF032", 0x4a, 0x1000, 1024, },
        { "SST25VF064", 0x4b, 0x1000, 2048, },
-       { 0 },
+       { NULL },
 };
 
 static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
@@ -67,7 +67,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
        { "AT45DB161", 0x2c, 512, 4096, },
        { "AT45DB321", 0x34, 512, 8192, },
        { "AT45DB642", 0x3c, 1024, 8192, },
-       { 0 },
+       { NULL },
 };
 
 static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
index b61440a..83f6437 100644 (file)
@@ -73,6 +73,7 @@ struct btsdio_data {
 #define REG_CL_INTRD 0x13      /* Interrupt Clear */
 #define REG_EN_INTRD 0x14      /* Interrupt Enable */
 #define REG_MD_STAT  0x20      /* Bluetooth Mode Status */
+#define REG_MD_SET   0x20      /* Bluetooth Mode Set */
 
 static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
 {
@@ -212,7 +213,7 @@ static int btsdio_open(struct hci_dev *hdev)
        }
 
        if (data->func->class == SDIO_CLASS_BT_B)
-               sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
+               sdio_writeb(data->func, 0x00, REG_MD_SET, NULL);
 
        sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
 
@@ -333,6 +334,9 @@ static int btsdio_probe(struct sdio_func *func,
        hdev->flush    = btsdio_flush;
        hdev->send     = btsdio_send_frame;
 
+       if (func->vendor == 0x0104 && func->device == 0x00c5)
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
        err = hci_register_dev(hdev);
        if (err < 0) {
                hci_free_dev(hdev);
index 9f7e539..baeaaed 100644 (file)
@@ -965,6 +965,45 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev)
        return 0;
 }
 
+static int btusb_setup_csr(struct hci_dev *hdev)
+{
+       struct hci_rp_read_local_version *rp;
+       struct sk_buff *skb;
+       int ret;
+
+       BT_DBG("%s", hdev->name);
+
+       skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+                            HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb));
+               return -PTR_ERR(skb);
+       }
+
+       rp = (struct hci_rp_read_local_version *) skb->data;
+
+       if (!rp->status) {
+               if (le16_to_cpu(rp->manufacturer) != 10) {
+                       /* Clear the reset quirk since this is not an actual
+                        * early Bluetooth 1.1 device from CSR.
+                        */
+                       clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+                       /* These fake CSR controllers have all a broken
+                        * stored link key handling and so just disable it.
+                        */
+                       set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY,
+                               &hdev->quirks);
+               }
+       }
+
+       ret = -bt_to_errno(rp->status);
+
+       kfree_skb(skb);
+
+       return ret;
+}
+
 struct intel_version {
        u8 status;
        u8 hw_platform;
@@ -1465,10 +1504,15 @@ static int btusb_probe(struct usb_interface *intf,
 
        if (id->driver_info & BTUSB_CSR) {
                struct usb_device *udev = data->udev;
+               u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
 
                /* Old firmware would otherwise execute USB reset */
-               if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
+               if (bcdDevice < 0x117)
                        set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+               /* Fake CSR devices with broken commands */
+               if (bcdDevice <= 0x100)
+                       hdev->setup = btusb_setup_csr;
        }
 
        if (id->driver_info & BTUSB_SNIFFER) {
index 7b16738..1ef6990 100644 (file)
@@ -141,22 +141,28 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
 }
 
 static inline ssize_t vhci_get_user(struct vhci_data *data,
-                                   const char __user *buf, size_t count)
+                                   const struct iovec *iov,
+                                   unsigned long count)
 {
+       size_t len = iov_length(iov, count);
        struct sk_buff *skb;
        __u8 pkt_type, dev_type;
+       unsigned long i;
        int ret;
 
-       if (count < 2 || count > HCI_MAX_FRAME_SIZE)
+       if (len < 2 || len > HCI_MAX_FRAME_SIZE)
                return -EINVAL;
 
-       skb = bt_skb_alloc(count, GFP_KERNEL);
+       skb = bt_skb_alloc(len, GFP_KERNEL);
        if (!skb)
                return -ENOMEM;
 
-       if (copy_from_user(skb_put(skb, count), buf, count)) {
-               kfree_skb(skb);
-               return -EFAULT;
+       for (i = 0; i < count; i++) {
+               if (copy_from_user(skb_put(skb, iov[i].iov_len),
+                                  iov[i].iov_base, iov[i].iov_len)) {
+                       kfree_skb(skb);
+                       return -EFAULT;
+               }
        }
 
        pkt_type = *((__u8 *) skb->data);
@@ -205,7 +211,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
                return -EINVAL;
        }
 
-       return (ret < 0) ? ret : count;
+       return (ret < 0) ? ret : len;
 }
 
 static inline ssize_t vhci_put_user(struct vhci_data *data,
@@ -272,12 +278,13 @@ static ssize_t vhci_read(struct file *file,
        return ret;
 }
 
-static ssize_t vhci_write(struct file *file,
-                         const char __user *buf, size_t count, loff_t *pos)
+static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov,
+                         unsigned long count, loff_t pos)
 {
+       struct file *file = iocb->ki_filp;
        struct vhci_data *data = file->private_data;
 
-       return vhci_get_user(data, buf, count);
+       return vhci_get_user(data, iov, count);
 }
 
 static unsigned int vhci_poll(struct file *file, poll_table *wait)
@@ -342,7 +349,7 @@ static int vhci_release(struct inode *inode, struct file *file)
 static const struct file_operations vhci_fops = {
        .owner          = THIS_MODULE,
        .read           = vhci_read,
-       .write          = vhci_write,
+       .aio_write      = vhci_write,
        .poll           = vhci_poll,
        .open           = vhci_open,
        .release        = vhci_release,
index 8e562dc..e1f3337 100644 (file)
@@ -27,15 +27,18 @@ static char *tpm_device_name = "TPM";
 static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
                                void **return_value)
 {
-       acpi_status status;
+       acpi_status status = AE_OK;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-       if (strstr(buffer.pointer, context) != NULL) {
-               *return_value = handle;
+
+       if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) {
+               if (strstr(buffer.pointer, context) != NULL) {
+                       *return_value = handle;
+                       status = AE_CTRL_TERMINATE;
+               }
                kfree(buffer.pointer);
-               return AE_CTRL_TERMINATE;
        }
-       return AE_OK;
+
+       return status;
 }
 
 static inline void ppi_assign_params(union acpi_object params[4],
index 8d3009e..5543b7d 100644 (file)
@@ -87,7 +87,7 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
        return 0;
 }
 
-static unsigned int _get_val(struct clk_divider *divider, u8 div)
+static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
 {
        if (divider->flags & CLK_DIVIDER_ONE_BASED)
                return div;
index 39b40aa..68e515d 100644 (file)
@@ -26,17 +26,17 @@ static struct clk_onecell_data clk_data;
 #define ASS_CLK_DIV 0x4
 #define ASS_CLK_GATE 0x8
 
+/* list of all parent clock list */
+static const char *mout_audss_p[] = { "fin_pll", "fout_epll" };
+static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" };
+
+#ifdef CONFIG_PM_SLEEP
 static unsigned long reg_save[][2] = {
        {ASS_CLK_SRC,  0},
        {ASS_CLK_DIV,  0},
        {ASS_CLK_GATE, 0},
 };
 
-/* list of all parent clock list */
-static const char *mout_audss_p[] = { "fin_pll", "fout_epll" };
-static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" };
-
-#ifdef CONFIG_PM_SLEEP
 static int exynos_audss_clk_suspend(void)
 {
        int i;
index ad5ff50..1a7c1b9 100644 (file)
@@ -39,7 +39,7 @@
 #define SRC_TOP1               0xc214
 #define SRC_CAM                        0xc220
 #define SRC_TV                 0xc224
-#define SRC_MFC                        0xcc28
+#define SRC_MFC                        0xc228
 #define SRC_G3D                        0xc22c
 #define E4210_SRC_IMAGE                0xc230
 #define SRC_LCD0               0xc234
index adf3234..e52359c 100644 (file)
@@ -25,6 +25,7 @@
 #define MPLL_LOCK              0x4000
 #define MPLL_CON0              0x4100
 #define SRC_CORE1              0x4204
+#define GATE_IP_ACP            0x8800
 #define CPLL_LOCK              0x10020
 #define EPLL_LOCK              0x10030
 #define VPLL_LOCK              0x10040
@@ -75,7 +76,6 @@
 #define SRC_CDREX              0x20200
 #define PLL_DIV2_SEL           0x20a24
 #define GATE_IP_DISP1          0x10928
-#define GATE_IP_ACP            0x10000
 
 /* list of PLLs to be registered */
 enum exynos5250_plls {
@@ -120,7 +120,8 @@ enum exynos5250_clks {
        spi2, i2s1, i2s2, pcm1, pcm2, pwm, spdif, ac97, hsi2c0, hsi2c1, hsi2c2,
        hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1,
        tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct,
-       wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, g2d,
+       wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, g2d, mdma0,
+       smmu_mdma0,
 
        /* mux clocks */
        mout_hdmi = 1024,
@@ -354,8 +355,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
        GATE(smmu_gscl2, "smmu_gscl2", "aclk266", GATE_IP_GSCL, 9, 0, 0),
        GATE(smmu_gscl3, "smmu_gscl3", "aclk266", GATE_IP_GSCL, 10, 0, 0),
        GATE(mfc, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0),
-       GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0),
-       GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0),
+       GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 2, 0, 0),
+       GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 1, 0, 0),
        GATE(rotator, "rotator", "aclk266", GATE_IP_GEN, 1, 0, 0),
        GATE(jpeg, "jpeg", "aclk166", GATE_IP_GEN, 2, 0, 0),
        GATE(mdma1, "mdma1", "aclk266", GATE_IP_GEN, 4, 0, 0),
@@ -406,7 +407,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
        GATE(hsi2c2, "hsi2c2", "aclk66", GATE_IP_PERIC, 30, 0, 0),
        GATE(hsi2c3, "hsi2c3", "aclk66", GATE_IP_PERIC, 31, 0, 0),
        GATE(chipid, "chipid", "aclk66", GATE_IP_PERIS, 0, 0, 0),
-       GATE(sysreg, "sysreg", "aclk66", GATE_IP_PERIS, 1, 0, 0),
+       GATE(sysreg, "sysreg", "aclk66",
+                       GATE_IP_PERIS, 1, CLK_IGNORE_UNUSED, 0),
        GATE(pmu, "pmu", "aclk66", GATE_IP_PERIS, 2, CLK_IGNORE_UNUSED, 0),
        GATE(tzpc0, "tzpc0", "aclk66", GATE_IP_PERIS, 6, 0, 0),
        GATE(tzpc1, "tzpc1", "aclk66", GATE_IP_PERIS, 7, 0, 0),
@@ -492,6 +494,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
        GATE(mixer, "mixer", "mout_aclk200_disp1", GATE_IP_DISP1, 5, 0, 0),
        GATE(hdmi, "hdmi", "mout_aclk200_disp1", GATE_IP_DISP1, 6, 0, 0),
        GATE(g2d, "g2d", "aclk200", GATE_IP_ACP, 3, 0, 0),
+       GATE(mdma0, "mdma0", "aclk266", GATE_IP_ACP, 1, 0, 0),
+       GATE(smmu_mdma0, "smmu_mdma0", "aclk266", GATE_IP_ACP, 5, 0, 0),
 };
 
 static struct samsung_pll_rate_table vpll_24mhz_tbl[] __initdata = {
index 16d7b4a..8d19f7c 100644 (file)
@@ -839,9 +839,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
 
        /* set default policy */
        ret = cpufreq_set_policy(policy, &new_policy);
-       policy->user_policy.policy = policy->policy;
-       policy->user_policy.governor = policy->governor;
-
        if (ret) {
                pr_debug("setting policy failed\n");
                if (cpufreq_driver->exit)
@@ -1016,15 +1013,17 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
        read_unlock_irqrestore(&cpufreq_driver_lock, flags);
 #endif
 
-       if (frozen)
-               /* Restore the saved policy when doing light-weight init */
-               policy = cpufreq_policy_restore(cpu);
-       else
+       /*
+        * Restore the saved policy when doing light-weight init and fall back
+        * to the full init if that fails.
+        */
+       policy = frozen ? cpufreq_policy_restore(cpu) : NULL;
+       if (!policy) {
+               frozen = false;
                policy = cpufreq_policy_alloc();
-
-       if (!policy)
-               goto nomem_out;
-
+               if (!policy)
+                       goto nomem_out;
+       }
 
        /*
         * In the resume path, since we restore a saved policy, the assignment
@@ -1069,8 +1068,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
         */
        cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
 
-       policy->user_policy.min = policy->min;
-       policy->user_policy.max = policy->max;
+       if (!frozen) {
+               policy->user_policy.min = policy->min;
+               policy->user_policy.max = policy->max;
+       }
 
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                                     CPUFREQ_START, policy);
@@ -1101,6 +1102,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
 
        cpufreq_init_policy(policy);
 
+       if (!frozen) {
+               policy->user_policy.policy = policy->policy;
+               policy->user_policy.governor = policy->governor;
+       }
+
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        up_read(&cpufreq_rwsem);
 
@@ -1118,8 +1124,11 @@ err_get_freq:
        if (cpufreq_driver->exit)
                cpufreq_driver->exit(policy);
 err_set_policy_cpu:
-       if (frozen)
+       if (frozen) {
+               /* Do not leave stale fallback data behind. */
+               per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL;
                cpufreq_policy_put_kobj(policy);
+       }
        cpufreq_policy_free(policy);
 
 nomem_out:
index 5f1cbae..d51f17e 100644 (file)
@@ -581,7 +581,8 @@ static void intel_pstate_timer_func(unsigned long __data)
 }
 
 #define ICPU(model, policy) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy }
+       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF,\
+                       (unsigned long)&policy }
 
 static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        ICPU(0x2a, core_params),
@@ -614,6 +615,11 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
        cpu = all_cpu_data[cpunum];
 
        intel_pstate_get_cpu_pstates(cpu);
+       if (!cpu->pstate.current_pstate) {
+               all_cpu_data[cpunum] = NULL;
+               kfree(cpu);
+               return -ENODATA;
+       }
 
        cpu->cpu = cpunum;
 
index 3679563..6e51114 100644 (file)
@@ -65,7 +65,7 @@ static struct cpuidle_driver calxeda_idle_driver = {
        .state_count = 2,
 };
 
-static int __init calxeda_cpuidle_probe(struct platform_device *pdev)
+static int calxeda_cpuidle_probe(struct platform_device *pdev)
 {
        return cpuidle_register(&calxeda_idle_driver, NULL);
 }
index 9dd6e01..f757a0f 100644 (file)
@@ -1410,14 +1410,12 @@ static const struct platform_device_info ixp_dev_info __initdata = {
 static int __init ixp_module_init(void)
 {
        int num = ARRAY_SIZE(ixp4xx_algos);
-       int i, err ;
+       int i, err;
 
        pdev = platform_device_register_full(&ixp_dev_info);
        if (IS_ERR(pdev))
                return PTR_ERR(pdev);
 
-       dev = &pdev->dev;
-
        spin_lock_init(&desc_lock);
        spin_lock_init(&emerg_lock);
 
index 1a49c77..8752918 100644 (file)
@@ -817,7 +817,15 @@ int ioat_dma_self_test(struct ioatdma_device *device)
        }
 
        dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, dma_src)) {
+               dev_err(dev, "mapping src buffer failed\n");
+               goto free_resources;
+       }
        dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE);
+       if (dma_mapping_error(dev, dma_dest)) {
+               dev_err(dev, "mapping dest buffer failed\n");
+               goto unmap_src;
+       }
        flags = DMA_PREP_INTERRUPT;
        tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src,
                                                   IOAT_TEST_SIZE, flags);
@@ -855,8 +863,9 @@ int ioat_dma_self_test(struct ioatdma_device *device)
        }
 
 unmap_dma:
-       dma_unmap_single(dev, dma_src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
        dma_unmap_single(dev, dma_dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE);
+unmap_src:
+       dma_unmap_single(dev, dma_src, IOAT_TEST_SIZE, DMA_TO_DEVICE);
 free_resources:
        dma->device_free_chan_resources(dma_chan);
 out:
index c79dd2b..d3c3b5b 100644 (file)
@@ -906,14 +906,12 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                WARN_ON(readq(&gtt_entries[i-1])
                        != gen8_pte_encode(addr, level, true));
 
-#if 0 /* TODO: Still needed on GEN8? */
        /* This next bit makes the above posting read even more important. We
         * want to flush the TLBs only after we're certain all the PTE updates
         * have finished.
         */
        I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
        POSTING_READ(GFX_FLSH_CNTL_GEN6);
-#endif
 }
 
 /*
index 54e82a8..769b864 100644 (file)
@@ -10541,11 +10541,20 @@ static struct intel_quirk intel_quirks[] = {
        /* Sony Vaio Y cannot use SSC on LVDS */
        { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
 
-       /*
-        * All GM45 Acer (and its brands eMachines and Packard Bell) laptops
-        * seem to use inverted backlight PWM.
-        */
-       { 0x2a42, 0x1025, PCI_ANY_ID, quirk_invert_brightness },
+       /* Acer Aspire 5734Z must invert backlight brightness */
+       { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
+
+       /* Acer/eMachines G725 */
+       { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness },
+
+       /* Acer/eMachines e725 */
+       { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness },
+
+       /* Acer/Packard Bell NCL20 */
+       { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness },
+
+       /* Acer Aspire 4736Z */
+       { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
 
        /* Dell XPS13 HD Sandy Bridge */
        { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
index 48f0637..2ea5568 100644 (file)
@@ -104,11 +104,8 @@ nouveau_subdev_create_(struct nouveau_object *parent,
 
        if (parent) {
                struct nouveau_device *device = nv_device(parent);
-               int subidx = nv_hclass(subdev) & 0xff;
-
                subdev->debug = nouveau_dbgopt(device->dbgopt, subname);
                subdev->mmio  = nv_subdev(device)->mmio;
-               device->subdev[subidx] = *pobject;
        }
 
        return 0;
index 9135b25..dd01c6c 100644 (file)
@@ -268,6 +268,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                if (ret)
                        return ret;
 
+               device->subdev[i] = devobj->subdev[i];
+
                /* note: can't init *any* subdevs until devinit has been run
                 * due to not knowing exactly what the vbios init tables will
                 * mess with.  devinit also can't be run until all of its
index 8d06eef..dbc5e33 100644 (file)
@@ -161,7 +161,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
index 434bb4b..5c8a63d 100644 (file)
@@ -334,7 +334,7 @@ nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds)
        while ((mthd = &mthds[i++]) && (init = mthd->init)) {
                u32  addr = 0x80000000 | mthd->oclass;
                for (data = 0; init->count; init++) {
-                       if (data != init->data) {
+                       if (init == mthd->init || data != init->data) {
                                nv_wr32(priv, 0x40448c, init->data);
                                data = init->data;
                        }
index 8541aa3..d89dbdf 100644 (file)
@@ -75,6 +75,11 @@ struct nouveau_fb {
 static inline struct nouveau_fb *
 nouveau_fb(void *obj)
 {
+       /* fbram uses this before device subdev pointer is valid */
+       if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
+           nv_subidx(obj) == NVDEV_SUBDEV_FB)
+               return obj;
+
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB];
 }
 
index 420908c..df1b1b4 100644 (file)
@@ -365,13 +365,13 @@ static u16
 init_script(struct nouveau_bios *bios, int index)
 {
        struct nvbios_init init = { .bios = bios };
-       u16 data;
+       u16 bmp_ver = bmp_version(bios), data;
 
-       if (bmp_version(bios) && bmp_version(bios) < 0x0510) {
-               if (index > 1)
+       if (bmp_ver && bmp_ver < 0x0510) {
+               if (index > 1 || bmp_ver < 0x0100)
                        return 0x0000;
 
-               data = bios->bmp_offset + (bios->version.major < 2 ? 14 : 18);
+               data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18);
                return nv_ro16(bios, data + (index * 2));
        }
 
@@ -1294,7 +1294,11 @@ init_jump(struct nvbios_init *init)
        u16 offset = nv_ro16(bios, init->offset + 1);
 
        trace("JUMP\t0x%04x\n", offset);
-       init->offset = offset;
+
+       if (init_exec(init))
+               init->offset = offset;
+       else
+               init->offset += 3;
 }
 
 /**
index 6828d81..900fae0 100644 (file)
@@ -447,6 +447,8 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
        if (ret)
                goto done;
 
+       info->offset = ntfy->node->offset;
+
 done:
        if (ret)
                nouveau_abi16_ntfy_fini(chan, ntfy);
index 95c7404..ba0183f 100644 (file)
@@ -51,6 +51,7 @@ static struct nouveau_dsm_priv {
        bool dsm_detected;
        bool optimus_detected;
        acpi_handle dhandle;
+       acpi_handle other_handle;
        acpi_handle rom_handle;
 } nouveau_dsm_priv;
 
@@ -260,9 +261,10 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
        if (!dhandle)
                return false;
 
-       if (!acpi_has_method(dhandle, "_DSM"))
+       if (!acpi_has_method(dhandle, "_DSM")) {
+               nouveau_dsm_priv.other_handle = dhandle;
                return false;
-
+       }
        if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
                retval |= NOUVEAU_DSM_HAS_MUX;
 
@@ -338,6 +340,16 @@ static bool nouveau_dsm_detect(void)
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
                        acpi_method_name);
                nouveau_dsm_priv.dsm_detected = true;
+               /*
+                * On some systems hotplug events are generated for the device
+                * being switched off when _DSM is executed.  They cause ACPI
+                * hotplug to trigger and attempt to remove the device from
+                * the system, which causes it to break down.  Prevent that from
+                * happening by setting the no_hotplug flag for the involved
+                * ACPI device objects.
+                */
+               acpi_bus_no_hotplug(nouveau_dsm_priv.dhandle);
+               acpi_bus_no_hotplug(nouveau_dsm_priv.other_handle);
                ret = true;
        }
 
index 29c3efd..25ea82f 100644 (file)
@@ -610,7 +610,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        ret = nouveau_fence_sync(fence, chan);
        nouveau_fence_unref(&fence);
        if (ret)
-               return ret;
+               goto fail_free;
 
        if (new_bo != old_bo) {
                ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
index b197059..0b9621c 100644 (file)
@@ -1143,31 +1143,53 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        }
 
        if (tiling_flags & RADEON_TILING_MACRO) {
-               if (rdev->family >= CHIP_BONAIRE)
-                       tmp = rdev->config.cik.tile_config;
-               else if (rdev->family >= CHIP_TAHITI)
-                       tmp = rdev->config.si.tile_config;
-               else if (rdev->family >= CHIP_CAYMAN)
-                       tmp = rdev->config.cayman.tile_config;
-               else
-                       tmp = rdev->config.evergreen.tile_config;
+               evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
 
-               switch ((tmp & 0xf0) >> 4) {
-               case 0: /* 4 banks */
-                       fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK);
-                       break;
-               case 1: /* 8 banks */
-               default:
-                       fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK);
-                       break;
-               case 2: /* 16 banks */
-                       fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK);
-                       break;
+               /* Set NUM_BANKS. */
+               if (rdev->family >= CHIP_BONAIRE) {
+                       unsigned tileb, index, num_banks, tile_split_bytes;
+
+                       /* Calculate the macrotile mode index. */
+                       tile_split_bytes = 64 << tile_split;
+                       tileb = 8 * 8 * target_fb->bits_per_pixel / 8;
+                       tileb = min(tile_split_bytes, tileb);
+
+                       for (index = 0; tileb > 64; index++) {
+                               tileb >>= 1;
+                       }
+
+                       if (index >= 16) {
+                               DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n",
+                                         target_fb->bits_per_pixel, tile_split);
+                               return -EINVAL;
+                       }
+
+                       num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+                       fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);
+               } else {
+                       /* SI and older. */
+                       if (rdev->family >= CHIP_TAHITI)
+                               tmp = rdev->config.si.tile_config;
+                       else if (rdev->family >= CHIP_CAYMAN)
+                               tmp = rdev->config.cayman.tile_config;
+                       else
+                               tmp = rdev->config.evergreen.tile_config;
+
+                       switch ((tmp & 0xf0) >> 4) {
+                       case 0: /* 4 banks */
+                               fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK);
+                               break;
+                       case 1: /* 8 banks */
+                       default:
+                               fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK);
+                               break;
+                       case 2: /* 16 banks */
+                               fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK);
+                               break;
+                       }
                }
 
                fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1);
-
-               evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
                fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split);
                fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
                fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
@@ -1180,19 +1202,12 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
                fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
 
        if (rdev->family >= CHIP_BONAIRE) {
-               u32 num_pipe_configs = rdev->config.cik.max_tile_pipes;
-               u32 num_rb = rdev->config.cik.max_backends_per_se;
-               if (num_pipe_configs > 8)
-                       num_pipe_configs = 8;
-               if (num_pipe_configs == 8)
-                       fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P8_32x32_16x16);
-               else if (num_pipe_configs == 4) {
-                       if (num_rb == 4)
-                               fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_16x16);
-                       else if (num_rb < 4)
-                               fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_8x16);
-               } else if (num_pipe_configs == 2)
-                       fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P2);
+               /* Read the pipe config from the 2D TILED SCANOUT mode.
+                * It should be the same for the other modes too, but not all
+                * modes set the pipe config field. */
+               u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f;
+
+               fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config);
        } else if ((rdev->family == CHIP_TAHITI) ||
                   (rdev->family == CHIP_PITCAIRN))
                fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16);
index b43a3a3..e950fab 100644 (file)
@@ -3057,7 +3057,7 @@ static u32 cik_create_bitmask(u32 bit_width)
  * Returns the disabled RB bitmask.
  */
 static u32 cik_get_rb_disabled(struct radeon_device *rdev,
-                             u32 max_rb_num, u32 se_num,
+                             u32 max_rb_num_per_se,
                              u32 sh_per_se)
 {
        u32 data, mask;
@@ -3071,7 +3071,7 @@ static u32 cik_get_rb_disabled(struct radeon_device *rdev,
 
        data >>= BACKEND_DISABLE_SHIFT;
 
-       mask = cik_create_bitmask(max_rb_num / se_num / sh_per_se);
+       mask = cik_create_bitmask(max_rb_num_per_se / sh_per_se);
 
        return data & mask;
 }
@@ -3088,7 +3088,7 @@ static u32 cik_get_rb_disabled(struct radeon_device *rdev,
  */
 static void cik_setup_rb(struct radeon_device *rdev,
                         u32 se_num, u32 sh_per_se,
-                        u32 max_rb_num)
+                        u32 max_rb_num_per_se)
 {
        int i, j;
        u32 data, mask;
@@ -3098,7 +3098,7 @@ static void cik_setup_rb(struct radeon_device *rdev,
        for (i = 0; i < se_num; i++) {
                for (j = 0; j < sh_per_se; j++) {
                        cik_select_se_sh(rdev, i, j);
-                       data = cik_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se);
+                       data = cik_get_rb_disabled(rdev, max_rb_num_per_se, sh_per_se);
                        if (rdev->family == CHIP_HAWAII)
                                disabled_rbs |= data << ((i * sh_per_se + j) * HAWAII_RB_BITMAP_WIDTH_PER_SH);
                        else
@@ -3108,12 +3108,14 @@ static void cik_setup_rb(struct radeon_device *rdev,
        cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
 
        mask = 1;
-       for (i = 0; i < max_rb_num; i++) {
+       for (i = 0; i < max_rb_num_per_se * se_num; i++) {
                if (!(disabled_rbs & mask))
                        enabled_rbs |= mask;
                mask <<= 1;
        }
 
+       rdev->config.cik.backend_enable_mask = enabled_rbs;
+
        for (i = 0; i < se_num; i++) {
                cik_select_se_sh(rdev, i, 0xffffffff);
                data = 0;
index b1f990d..45e1f44 100644 (file)
@@ -1940,7 +1940,7 @@ struct si_asic {
        unsigned sc_earlyz_tile_fifo_size;
 
        unsigned num_tile_pipes;
-       unsigned num_backends_per_se;
+       unsigned backend_enable_mask;
        unsigned backend_disable_mask_per_asic;
        unsigned backend_map;
        unsigned num_texture_channel_caches;
@@ -1970,7 +1970,7 @@ struct cik_asic {
        unsigned sc_earlyz_tile_fifo_size;
 
        unsigned num_tile_pipes;
-       unsigned num_backends_per_se;
+       unsigned backend_enable_mask;
        unsigned backend_disable_mask_per_asic;
        unsigned backend_map;
        unsigned num_texture_channel_caches;
index 9d302ea..485848f 100644 (file)
@@ -33,6 +33,7 @@ static struct radeon_atpx_priv {
        bool atpx_detected;
        /* handle for device - and atpx */
        acpi_handle dhandle;
+       acpi_handle other_handle;
        struct radeon_atpx atpx;
 } radeon_atpx_priv;
 
@@ -451,9 +452,10 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
                return false;
 
        status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
-       if (ACPI_FAILURE(status))
+       if (ACPI_FAILURE(status)) {
+               radeon_atpx_priv.other_handle = dhandle;
                return false;
-
+       }
        radeon_atpx_priv.dhandle = dhandle;
        radeon_atpx_priv.atpx.handle = atpx_handle;
        return true;
@@ -530,6 +532,16 @@ static bool radeon_atpx_detect(void)
                printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
                       acpi_method_name);
                radeon_atpx_priv.atpx_detected = true;
+               /*
+                * On some systems hotplug events are generated for the device
+                * being switched off when ATPX is executed.  They cause ACPI
+                * hotplug to trigger and attempt to remove the device from
+                * the system, which causes it to break down.  Prevent that from
+                * happening by setting the no_hotplug flag for the involved
+                * ACPI device objects.
+                */
+               acpi_bus_no_hotplug(radeon_atpx_priv.dhandle);
+               acpi_bus_no_hotplug(radeon_atpx_priv.other_handle);
                return true;
        }
        return false;
index 1958b36..db39ea3 100644 (file)
  *   2.33.0 - Add SI tiling mode array query
  *   2.34.0 - Add CIK tiling mode array query
  *   2.35.0 - Add CIK macrotile mode array query
+ *   2.36.0 - Fix CIK DCE tiling setup
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       35
+#define KMS_DRIVER_MINOR       36
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index 55d0b47..21d593c 100644 (file)
@@ -461,6 +461,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
        case RADEON_INFO_SI_CP_DMA_COMPUTE:
                *value = 1;
                break;
+       case RADEON_INFO_SI_BACKEND_ENABLED_MASK:
+               if (rdev->family >= CHIP_BONAIRE) {
+                       *value = rdev->config.cik.backend_enable_mask;
+               } else if (rdev->family >= CHIP_TAHITI) {
+                       *value = rdev->config.si.backend_enable_mask;
+               } else {
+                       DRM_DEBUG_KMS("BACKEND_ENABLED_MASK is si+ only!\n");
+               }
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
index 373d088..b9c0529 100644 (file)
@@ -473,7 +473,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
                return -EINVAL;
        }
 
-       if ((start >> 28) != (end >> 28)) {
+       if ((start >> 28) != ((end - 1) >> 28)) {
                DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n",
                          start, end);
                return -EINVAL;
index a36736d..85e1edf 100644 (file)
@@ -2811,7 +2811,7 @@ static void si_setup_spi(struct radeon_device *rdev,
 }
 
 static u32 si_get_rb_disabled(struct radeon_device *rdev,
-                             u32 max_rb_num, u32 se_num,
+                             u32 max_rb_num_per_se,
                              u32 sh_per_se)
 {
        u32 data, mask;
@@ -2825,14 +2825,14 @@ static u32 si_get_rb_disabled(struct radeon_device *rdev,
 
        data >>= BACKEND_DISABLE_SHIFT;
 
-       mask = si_create_bitmask(max_rb_num / se_num / sh_per_se);
+       mask = si_create_bitmask(max_rb_num_per_se / sh_per_se);
 
        return data & mask;
 }
 
 static void si_setup_rb(struct radeon_device *rdev,
                        u32 se_num, u32 sh_per_se,
-                       u32 max_rb_num)
+                       u32 max_rb_num_per_se)
 {
        int i, j;
        u32 data, mask;
@@ -2842,19 +2842,21 @@ static void si_setup_rb(struct radeon_device *rdev,
        for (i = 0; i < se_num; i++) {
                for (j = 0; j < sh_per_se; j++) {
                        si_select_se_sh(rdev, i, j);
-                       data = si_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se);
+                       data = si_get_rb_disabled(rdev, max_rb_num_per_se, sh_per_se);
                        disabled_rbs |= data << ((i * sh_per_se + j) * TAHITI_RB_BITMAP_WIDTH_PER_SH);
                }
        }
        si_select_se_sh(rdev, 0xffffffff, 0xffffffff);
 
        mask = 1;
-       for (i = 0; i < max_rb_num; i++) {
+       for (i = 0; i < max_rb_num_per_se * se_num; i++) {
                if (!(disabled_rbs & mask))
                        enabled_rbs |= mask;
                mask <<= 1;
        }
 
+       rdev->config.si.backend_enable_mask = enabled_rbs;
+
        for (i = 0; i < se_num; i++) {
                si_select_se_sh(rdev, i, 0xffffffff);
                data = 0;
index f80b700..797ed29 100644 (file)
@@ -123,7 +123,7 @@ static struct cpuidle_state *cpuidle_state_table;
  * which is also the index into the MWAIT hint array.
  * Thus C0 is a dummy.
  */
-static struct cpuidle_state nehalem_cstates[] __initdata = {
+static struct cpuidle_state nehalem_cstates[] = {
        {
                .name = "C1-NHM",
                .desc = "MWAIT 0x00",
@@ -156,7 +156,7 @@ static struct cpuidle_state nehalem_cstates[] __initdata = {
                .enter = NULL }
 };
 
-static struct cpuidle_state snb_cstates[] __initdata = {
+static struct cpuidle_state snb_cstates[] = {
        {
                .name = "C1-SNB",
                .desc = "MWAIT 0x00",
@@ -196,7 +196,7 @@ static struct cpuidle_state snb_cstates[] __initdata = {
                .enter = NULL }
 };
 
-static struct cpuidle_state ivb_cstates[] __initdata = {
+static struct cpuidle_state ivb_cstates[] = {
        {
                .name = "C1-IVB",
                .desc = "MWAIT 0x00",
@@ -236,7 +236,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = {
                .enter = NULL }
 };
 
-static struct cpuidle_state hsw_cstates[] __initdata = {
+static struct cpuidle_state hsw_cstates[] = {
        {
                .name = "C1-HSW",
                .desc = "MWAIT 0x00",
@@ -297,7 +297,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = {
                .enter = NULL }
 };
 
-static struct cpuidle_state atom_cstates[] __initdata = {
+static struct cpuidle_state atom_cstates[] = {
        {
                .name = "C1E-ATM",
                .desc = "MWAIT 0x00",
@@ -329,7 +329,7 @@ static struct cpuidle_state atom_cstates[] __initdata = {
        {
                .enter = NULL }
 };
-static struct cpuidle_state avn_cstates[] __initdata = {
+static struct cpuidle_state avn_cstates[] = {
        {
                .name = "C1-AVN",
                .desc = "MWAIT 0x00",
@@ -344,6 +344,8 @@ static struct cpuidle_state avn_cstates[] __initdata = {
                .exit_latency = 15,
                .target_residency = 45,
                .enter = &intel_idle },
+       {
+               .enter = NULL }
 };
 
 /**
index 8e49db6..6c17f2d 100644 (file)
@@ -2310,7 +2310,7 @@ static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
 
        inet_get_local_port_range(&init_net, &low, &high);
        remaining = (high - low) + 1;
-       rover = net_random() % remaining + low;
+       rover = prandom_u32() % remaining + low;
 retry:
        if (last_used_port != rover &&
            !idr_find(ps, (unsigned short) rover)) {
index 846ccdd..d2965e4 100644 (file)
@@ -1871,6 +1871,10 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
                break;
 
        case EV_ABS:
+               input_alloc_absinfo(dev);
+               if (!dev->absinfo)
+                       return;
+
                __set_bit(code, dev->absbit);
                break;
 
index 75762d6..aa127ba 100644 (file)
@@ -455,7 +455,18 @@ static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
        }
 }
 
-static irqreturn_t zforce_interrupt(int irq, void *dev_id)
+static irqreturn_t zforce_irq(int irq, void *dev_id)
+{
+       struct zforce_ts *ts = dev_id;
+       struct i2c_client *client = ts->client;
+
+       if (ts->suspended && device_may_wakeup(&client->dev))
+               pm_wakeup_event(&client->dev, 500);
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
 {
        struct zforce_ts *ts = dev_id;
        struct i2c_client *client = ts->client;
@@ -465,12 +476,10 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id)
        u8 *payload;
 
        /*
-        * When suspended, emit a wakeup signal if necessary and return.
+        * When still suspended, return.
         * Due to the level-interrupt we will get re-triggered later.
         */
        if (ts->suspended) {
-               if (device_may_wakeup(&client->dev))
-                       pm_wakeup_event(&client->dev, 500);
                msleep(20);
                return IRQ_HANDLED;
        }
@@ -763,8 +772,8 @@ static int zforce_probe(struct i2c_client *client,
         * Therefore we can trigger the interrupt anytime it is low and do
         * not need to limit it to the interrupt edge.
         */
-       ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
-                                       zforce_interrupt,
+       ret = devm_request_threaded_irq(&client->dev, client->irq,
+                                       zforce_irq, zforce_irq_thread,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                        input_dev->name, ts);
        if (ret) {
index 0518835..a97263e 100644 (file)
@@ -244,18 +244,12 @@ static int lp5521_update_program_memory(struct lp55xx_chip *chip,
        if (i % 2)
                goto err;
 
-       mutex_lock(&chip->lock);
-
        for (i = 0; i < LP5521_PROGRAM_LENGTH; i++) {
                ret = lp55xx_write(chip, addr[idx] + i, pattern[i]);
-               if (ret) {
-                       mutex_unlock(&chip->lock);
+               if (ret)
                        return -EINVAL;
-               }
        }
 
-       mutex_unlock(&chip->lock);
-
        return size;
 
 err:
@@ -427,15 +421,17 @@ static ssize_t store_engine_load(struct device *dev,
 {
        struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
        struct lp55xx_chip *chip = led->chip;
+       int ret;
 
        mutex_lock(&chip->lock);
 
        chip->engine_idx = nr;
        lp5521_load_engine(chip);
+       ret = lp5521_update_program_memory(chip, buf, len);
 
        mutex_unlock(&chip->lock);
 
-       return lp5521_update_program_memory(chip, buf, len);
+       return ret;
 }
 store_load(1)
 store_load(2)
index 6b553d9..fd9ab5f 100644 (file)
@@ -337,18 +337,12 @@ static int lp5523_update_program_memory(struct lp55xx_chip *chip,
        if (i % 2)
                goto err;
 
-       mutex_lock(&chip->lock);
-
        for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) {
                ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]);
-               if (ret) {
-                       mutex_unlock(&chip->lock);
+               if (ret)
                        return -EINVAL;
-               }
        }
 
-       mutex_unlock(&chip->lock);
-
        return size;
 
 err:
@@ -548,15 +542,17 @@ static ssize_t store_engine_load(struct device *dev,
 {
        struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
        struct lp55xx_chip *chip = led->chip;
+       int ret;
 
        mutex_lock(&chip->lock);
 
        chip->engine_idx = nr;
        lp5523_load_engine_and_select_page(chip);
+       ret = lp5523_update_program_memory(chip, buf, len);
 
        mutex_unlock(&chip->lock);
 
-       return lp5523_update_program_memory(chip, buf, len);
+       return ret;
 }
 store_load(1)
 store_load(2)
index 11e20af..705698f 100644 (file)
@@ -1228,8 +1228,14 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
 
        pcr->remove_pci = true;
 
-       cancel_delayed_work(&pcr->carddet_work);
-       cancel_delayed_work(&pcr->idle_work);
+       /* Disable interrupts at the pcr level */
+       spin_lock_irq(&pcr->lock);
+       rtsx_pci_writel(pcr, RTSX_BIER, 0);
+       pcr->bier = 0;
+       spin_unlock_irq(&pcr->lock);
+
+       cancel_delayed_work_sync(&pcr->carddet_work);
+       cancel_delayed_work_sync(&pcr->idle_work);
 
        mfd_remove_devices(&pcidev->dev);
 
index d210d13..0f55589 100644 (file)
@@ -73,7 +73,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
        info->map.cached =
-               ioremap_cached(info->map.phys, info->map.size);
+               ioremap_cache(info->map.phys, info->map.size);
        if (!info->map.cached)
                printk(KERN_WARNING "Failed to ioremap cached %s\n",
                       info->map.name);
index 539e24a..cce1f1b 100644 (file)
 #include "bonding.h"
 #include "bond_3ad.h"
 
-// General definitions
+/* General definitions */
 #define AD_SHORT_TIMEOUT           1
 #define AD_LONG_TIMEOUT            0
 #define AD_STANDBY                 0x2
 #define AD_MAX_TX_IN_SECOND        3
 #define AD_COLLECTOR_MAX_DELAY     0
 
-// Timer definitions(43.4.4 in the 802.3ad standard)
+/* Timer definitions (43.4.4 in the 802.3ad standard) */
 #define AD_FAST_PERIODIC_TIME      1
 #define AD_SLOW_PERIODIC_TIME      30
 #define AD_SHORT_TIMEOUT_TIME      (3*AD_FAST_PERIODIC_TIME)
@@ -49,7 +49,7 @@
 #define AD_CHURN_DETECTION_TIME    60
 #define AD_AGGREGATE_WAIT_TIME     2
 
-// Port state definitions(43.4.2.2 in the 802.3ad standard)
+/* Port state definitions (43.4.2.2 in the 802.3ad standard) */
 #define AD_STATE_LACP_ACTIVITY   0x1
 #define AD_STATE_LACP_TIMEOUT    0x2
 #define AD_STATE_AGGREGATION     0x4
@@ -59,7 +59,9 @@
 #define AD_STATE_DEFAULTED       0x40
 #define AD_STATE_EXPIRED         0x80
 
-// Port Variables definitions used by the State Machines(43.4.7 in the 802.3ad standard)
+/* Port Variables definitions used by the State Machines (43.4.7 in the
+ * 802.3ad standard)
+ */
 #define AD_PORT_BEGIN           0x1
 #define AD_PORT_LACP_ENABLED    0x2
 #define AD_PORT_ACTOR_CHURN     0x4
 #define AD_PORT_SELECTED        0x100
 #define AD_PORT_MOVED           0x200
 
-// Port Key definitions
-// key is determined according to the link speed, duplex and
-// user key(which is yet not supported)
-//              ------------------------------------------------------------
-// Port key :   | User key                       |      Speed       |Duplex|
-//              ------------------------------------------------------------
-//              16                               6               1 0
+/* Port Key definitions
+ * key is determined according to the link speed, duplex and
+ * user key (which is yet not supported)
+ * --------------------------------------------------------------
+ * Port key :  | User key      | Speed         | Duplex        |
+ * --------------------------------------------------------------
+ * 16            6               1               0
+ */
 #define  AD_DUPLEX_KEY_BITS    0x1
 #define  AD_SPEED_KEY_BITS     0x3E
 #define  AD_USER_KEY_BITS      0xFFC0
 
-//dalloun
 #define     AD_LINK_SPEED_BITMASK_1MBPS       0x1
 #define     AD_LINK_SPEED_BITMASK_10MBPS      0x2
 #define     AD_LINK_SPEED_BITMASK_100MBPS     0x4
 #define     AD_LINK_SPEED_BITMASK_1000MBPS    0x8
 #define     AD_LINK_SPEED_BITMASK_10000MBPS   0x10
-//endalloun
 
 /* compare MAC addresses */
 #define MAC_ADDRESS_EQUAL(A, B)        \
@@ -100,7 +101,7 @@ static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000;
 
 static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
-// ================= main 802.3ad protocol functions ==================
+/* ================= main 802.3ad protocol functions ================== */
 static int ad_lacpdu_send(struct port *port);
 static int ad_marker_send(struct port *port, struct bond_marker *marker);
 static void ad_mux_machine(struct port *port);
@@ -114,13 +115,13 @@ static void ad_initialize_agg(struct aggregator *aggregator);
 static void ad_initialize_port(struct port *port, int lacp_fast);
 static void ad_enable_collecting_distributing(struct port *port);
 static void ad_disable_collecting_distributing(struct port *port);
-static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port);
-static void ad_marker_response_received(struct bond_marker *marker, struct port *port);
+static void ad_marker_info_received(struct bond_marker *marker_info,
+                                   struct port *port);
+static void ad_marker_response_received(struct bond_marker *marker,
+                                       struct port *port);
 
 
-/////////////////////////////////////////////////////////////////////////////////
-// ================= api to bonding and kernel code ==================
-/////////////////////////////////////////////////////////////////////////////////
+/* ================= api to bonding and kernel code ================== */
 
 /**
  * __get_bond_by_port - get the port's bonding struct
@@ -142,26 +143,32 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
  *
  * Return the aggregator of the first slave in @bond, or %NULL if it can't be
  * found.
+ * The caller must hold RCU or RTNL lock.
  */
 static inline struct aggregator *__get_first_agg(struct port *port)
 {
        struct bonding *bond = __get_bond_by_port(port);
        struct slave *first_slave;
+       struct aggregator *agg;
 
        /* If there's no bond for this port, or bond has no slaves */
        if (bond == NULL)
                return NULL;
+
        rcu_read_lock();
        first_slave = bond_first_slave_rcu(bond);
+       agg = first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
        rcu_read_unlock();
-       return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL;
+
+       return agg;
 }
 
-/*
- * __agg_has_partner
+/**
+ * __agg_has_partner - see if we have a partner
+ * @agg: the agregator we're looking at
  *
  * Return nonzero if aggregator has a partner (denoted by a non-zero ether
- * address for the partner).  Return 0 if not.
+ * address for the partner). Return 0 if not.
  */
 static inline int __agg_has_partner(struct aggregator *agg)
 {
@@ -171,7 +178,6 @@ static inline int __agg_has_partner(struct aggregator *agg)
 /**
  * __disable_port - disable the port's slave
  * @port: the port we're looking at
- *
  */
 static inline void __disable_port(struct port *port)
 {
@@ -181,7 +187,6 @@ static inline void __disable_port(struct port *port)
 /**
  * __enable_port - enable the port's slave, if it's up
  * @port: the port we're looking at
- *
  */
 static inline void __enable_port(struct port *port)
 {
@@ -194,7 +199,6 @@ static inline void __enable_port(struct port *port)
 /**
  * __port_is_enabled - check if the port's slave is in active state
  * @port: the port we're looking at
- *
  */
 static inline int __port_is_enabled(struct port *port)
 {
@@ -220,7 +224,6 @@ static inline u32 __get_agg_selection_mode(struct port *port)
 /**
  * __check_agg_selection_timer - check if the selection timer has expired
  * @port: the port we're looking at
- *
  */
 static inline int __check_agg_selection_timer(struct port *port)
 {
@@ -235,7 +238,6 @@ static inline int __check_agg_selection_timer(struct port *port)
 /**
  * __get_state_machine_lock - lock the port's state machines
  * @port: the port we're looking at
- *
  */
 static inline void __get_state_machine_lock(struct port *port)
 {
@@ -245,7 +247,6 @@ static inline void __get_state_machine_lock(struct port *port)
 /**
  * __release_state_machine_lock - unlock the port's state machines
  * @port: the port we're looking at
- *
  */
 static inline void __release_state_machine_lock(struct port *port)
 {
@@ -268,10 +269,11 @@ static u16 __get_link_speed(struct port *port)
        struct slave *slave = port->slave;
        u16 speed;
 
-       /* this if covers only a special case: when the configuration starts with
-        * link down, it sets the speed to 0.
-        * This is done in spite of the fact that the e100 driver reports 0 to be
-        * compatible with MVT in the future.*/
+       /* this if covers only a special case: when the configuration starts
+        * with link down, it sets the speed to 0.
+        * This is done in spite of the fact that the e100 driver reports 0
+        * to be compatible with MVT in the future.
+        */
        if (slave->link != BOND_LINK_UP)
                speed = 0;
        else {
@@ -293,7 +295,8 @@ static u16 __get_link_speed(struct port *port)
                        break;
 
                default:
-                       speed = 0; // unknown speed value from ethtool. shouldn't happen
+                       /* unknown speed value from ethtool. shouldn't happen */
+                       speed = 0;
                        break;
                }
        }
@@ -317,8 +320,9 @@ static u8 __get_duplex(struct port *port)
 
        u8 retval;
 
-       //  handling a special case: when the configuration starts with
-       // link down, it sets the duplex to 0.
+       /* handling a special case: when the configuration starts with
+        * link down, it sets the duplex to 0.
+        */
        if (slave->link != BOND_LINK_UP)
                retval = 0x0;
        else {
@@ -342,15 +346,14 @@ static u8 __get_duplex(struct port *port)
 /**
  * __initialize_port_locks - initialize a port's STATE machine spinlock
  * @port: the slave of the port we're looking at
- *
  */
 static inline void __initialize_port_locks(struct slave *slave)
 {
-       // make sure it isn't called twice
+       /* make sure it isn't called twice */
        spin_lock_init(&(SLAVE_AD_INFO(slave).state_machine_lock));
 }
 
-//conversions
+/* Conversions */
 
 /**
  * __ad_timer_to_ticks - convert a given timer type to AD module ticks
@@ -359,39 +362,38 @@ static inline void __initialize_port_locks(struct slave *slave)
  *
  * If @timer_type is %current_while_timer, @par indicates long/short timer.
  * If @timer_type is %periodic_timer, @par is one of %FAST_PERIODIC_TIME,
- *                                                 %SLOW_PERIODIC_TIME.
+ *                                                  %SLOW_PERIODIC_TIME.
  */
 static u16 __ad_timer_to_ticks(u16 timer_type, u16 par)
 {
        u16 retval = 0; /* to silence the compiler */
 
        switch (timer_type) {
-       case AD_CURRENT_WHILE_TIMER:   // for rx machine usage
+       case AD_CURRENT_WHILE_TIMER:    /* for rx machine usage */
                if (par)
-                       retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); // short timeout
+                       retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec);
                else
-                       retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); // long timeout
+                       retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec);
                break;
-       case AD_ACTOR_CHURN_TIMER:          // for local churn machine
+       case AD_ACTOR_CHURN_TIMER:      /* for local churn machine */
                retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
                break;
-       case AD_PERIODIC_TIMER:     // for periodic machine
-               retval = (par*ad_ticks_per_sec); // long timeout
+       case AD_PERIODIC_TIMER:         /* for periodic machine */
+               retval = (par*ad_ticks_per_sec); /* long timeout */
                break;
-       case AD_PARTNER_CHURN_TIMER:   // for remote churn machine
+       case AD_PARTNER_CHURN_TIMER:    /* for remote churn machine */
                retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec);
                break;
-       case AD_WAIT_WHILE_TIMER:           // for selection machine
+       case AD_WAIT_WHILE_TIMER:       /* for selection machine */
                retval = (AD_AGGREGATE_WAIT_TIME*ad_ticks_per_sec);
                break;
        }
+
        return retval;
 }
 
 
-/////////////////////////////////////////////////////////////////////////////////
-// ================= ad_rx_machine helper functions ==================
-/////////////////////////////////////////////////////////////////////////////////
+/* ================= ad_rx_machine helper functions ================== */
 
 /**
  * __choose_matched - update a port's matched variable from a received lacpdu
@@ -451,7 +453,9 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
                struct port_params *partner = &port->partner_oper;
 
                __choose_matched(lacpdu, port);
-               // record the new parameter values for the partner operational
+               /* record the new parameter values for the partner
+                * operational
+                */
                partner->port_number = ntohs(lacpdu->actor_port);
                partner->port_priority = ntohs(lacpdu->actor_port_priority);
                partner->system = lacpdu->actor_system;
@@ -459,10 +463,12 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
                partner->key = ntohs(lacpdu->actor_key);
                partner->port_state = lacpdu->actor_state;
 
-               // set actor_oper_port_state.defaulted to FALSE
+               /* set actor_oper_port_state.defaulted to FALSE */
                port->actor_oper_port_state &= ~AD_STATE_DEFAULTED;
 
-               // set the partner sync. to on if the partner is sync. and the port is matched
+               /* set the partner sync. to on if the partner is sync,
+                * and the port is matched
+                */
                if ((port->sm_vars & AD_PORT_MATCHED)
                    && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION))
                        partner->port_state |= AD_STATE_SYNCHRONIZATION;
@@ -482,11 +488,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
 static void __record_default(struct port *port)
 {
        if (port) {
-               // record the partner admin parameters
+               /* record the partner admin parameters */
                memcpy(&port->partner_oper, &port->partner_admin,
                       sizeof(struct port_params));
 
-               // set actor_oper_port_state.defaulted to true
+               /* set actor_oper_port_state.defaulted to true */
                port->actor_oper_port_state |= AD_STATE_DEFAULTED;
        }
 }
@@ -591,36 +597,6 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
 }
 
 /**
- * __attach_bond_to_agg
- * @port: the port we're looking at
- *
- * Handle the attaching of the port's control parser/multiplexer and the
- * aggregator. This function does nothing since the parser/multiplexer of the
- * receive and the parser/multiplexer of the aggregator are already combined.
- */
-static void __attach_bond_to_agg(struct port *port)
-{
-       port = NULL; /* just to satisfy the compiler */
-       // This function does nothing since the parser/multiplexer of the receive
-       // and the parser/multiplexer of the aggregator are already combined
-}
-
-/**
- * __detach_bond_from_agg
- * @port: the port we're looking at
- *
- * Handle the detaching of the port's control parser/multiplexer from the
- * aggregator. This function does nothing since the parser/multiplexer of the
- * receive and the parser/multiplexer of the aggregator are already combined.
- */
-static void __detach_bond_from_agg(struct port *port)
-{
-       port = NULL; /* just to satisfy the compiler */
-       // This function does nothing since the parser/multiplexer of the receive
-       // and the parser/multiplexer of the aggregator are already combined
-}
-
-/**
  * __agg_ports_are_ready - check if all ports in an aggregator are ready
  * @aggregator: the aggregator we're looking at
  *
@@ -631,7 +607,9 @@ static int __agg_ports_are_ready(struct aggregator *aggregator)
        int retval = 1;
 
        if (aggregator) {
-               // scan all ports in this aggregator to verfy if they are all ready
+               /* scan all ports in this aggregator to verfy if they are
+                * all ready.
+                */
                for (port = aggregator->lag_ports;
                     port;
                     port = port->next_port_in_aggregator) {
@@ -691,7 +669,7 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
                        bandwidth = aggregator->num_of_ports * 10000;
                        break;
                default:
-                       bandwidth = 0; /*to silence the compiler ....*/
+                       bandwidth = 0; /* to silence the compiler */
                }
        }
        return bandwidth;
@@ -701,6 +679,7 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
  * __get_active_agg - get the current active aggregator
  * @aggregator: the aggregator we're looking at
  *
+ * Caller must hold RCU lock.
  */
 static struct aggregator *__get_active_agg(struct aggregator *aggregator)
 {
@@ -708,13 +687,9 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator)
        struct list_head *iter;
        struct slave *slave;
 
-       rcu_read_lock();
        bond_for_each_slave_rcu(bond, slave, iter)
-               if (SLAVE_AD_INFO(slave).aggregator.is_active) {
-                       rcu_read_unlock();
+               if (SLAVE_AD_INFO(slave).aggregator.is_active)
                        return &(SLAVE_AD_INFO(slave).aggregator);
-               }
-       rcu_read_unlock();
 
        return NULL;
 }
@@ -722,15 +697,14 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator)
 /**
  * __update_lacpdu_from_port - update a port's lacpdu fields
  * @port: the port we're looking at
- *
  */
 static inline void __update_lacpdu_from_port(struct port *port)
 {
        struct lacpdu *lacpdu = &port->lacpdu;
        const struct port_params *partner = &port->partner_oper;
 
-       /* update current actual Actor parameters */
-       /* lacpdu->subtype                   initialized
+       /* update current actual Actor parameters
+        * lacpdu->subtype                   initialized
         * lacpdu->version_number            initialized
         * lacpdu->tlv_type_actor_info       initialized
         * lacpdu->actor_information_length  initialized
@@ -766,9 +740,7 @@ static inline void __update_lacpdu_from_port(struct port *port)
         */
 }
 
-//////////////////////////////////////////////////////////////////////////////////////
-// ================= main 802.3ad protocol code ======================================
-//////////////////////////////////////////////////////////////////////////////////////
+/* ================= main 802.3ad protocol code ========================= */
 
 /**
  * ad_lacpdu_send - send out a lacpdu packet on a given port
@@ -798,11 +770,12 @@ static int ad_lacpdu_send(struct port *port)
 
        memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
        /* Note: source address is set to be the member's PERMANENT address,
-          because we use it to identify loopback lacpdus in receive. */
+        * because we use it to identify loopback lacpdus in receive.
+        */
        memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
        lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
-       lacpdu_header->lacpdu = port->lacpdu; // struct copy
+       lacpdu_header->lacpdu = port->lacpdu;
 
        dev_queue_xmit(skb);
 
@@ -839,11 +812,12 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
 
        memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
        /* Note: source address is set to be the member's PERMANENT address,
-          because we use it to identify loopback MARKERs in receive. */
+        * because we use it to identify loopback MARKERs in receive.
+        */
        memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
        marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
-       marker_header->marker = *marker; // struct copy
+       marker_header->marker = *marker;
 
        dev_queue_xmit(skb);
 
@@ -853,72 +827,90 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
 /**
  * ad_mux_machine - handle a port's mux state machine
  * @port: the port we're looking at
- *
  */
 static void ad_mux_machine(struct port *port)
 {
        mux_states_t last_state;
 
-       // keep current State Machine state to compare later if it was changed
+       /* keep current State Machine state to compare later if it was
+        * changed
+        */
        last_state = port->sm_mux_state;
 
        if (port->sm_vars & AD_PORT_BEGIN) {
-               port->sm_mux_state = AD_MUX_DETACHED;            // next state
+               port->sm_mux_state = AD_MUX_DETACHED;
        } else {
                switch (port->sm_mux_state) {
                case AD_MUX_DETACHED:
                        if ((port->sm_vars & AD_PORT_SELECTED)
                            || (port->sm_vars & AD_PORT_STANDBY))
                                /* if SELECTED or STANDBY */
-                               port->sm_mux_state = AD_MUX_WAITING; // next state
+                               port->sm_mux_state = AD_MUX_WAITING;
                        break;
                case AD_MUX_WAITING:
-                       // if SELECTED == FALSE return to DETACH state
-                       if (!(port->sm_vars & AD_PORT_SELECTED)) { // if UNSELECTED
+                       /* if SELECTED == FALSE return to DETACH state */
+                       if (!(port->sm_vars & AD_PORT_SELECTED)) {
                                port->sm_vars &= ~AD_PORT_READY_N;
-                               // in order to withhold the Selection Logic to check all ports READY_N value
-                               // every callback cycle to update ready variable, we check READY_N and update READY here
+                               /* in order to withhold the Selection Logic to
+                                * check all ports READY_N value every callback
+                                * cycle to update ready variable, we check
+                                * READY_N and update READY here
+                                */
                                __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
-                               port->sm_mux_state = AD_MUX_DETACHED;    // next state
+                               port->sm_mux_state = AD_MUX_DETACHED;
                                break;
                        }
 
-                       // check if the wait_while_timer expired
+                       /* check if the wait_while_timer expired */
                        if (port->sm_mux_timer_counter
                            && !(--port->sm_mux_timer_counter))
                                port->sm_vars |= AD_PORT_READY_N;
 
-                       // in order to withhold the selection logic to check all ports READY_N value
-                       // every callback cycle to update ready variable, we check READY_N and update READY here
+                       /* in order to withhold the selection logic to check
+                        * all ports READY_N value every callback cycle to
+                        * update ready variable, we check READY_N and update
+                        * READY here
+                        */
                        __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
 
-                       // if the wait_while_timer expired, and the port is in READY state, move to ATTACHED state
+                       /* if the wait_while_timer expired, and the port is
+                        * in READY state, move to ATTACHED state
+                        */
                        if ((port->sm_vars & AD_PORT_READY)
                            && !port->sm_mux_timer_counter)
-                               port->sm_mux_state = AD_MUX_ATTACHED;    // next state
+                               port->sm_mux_state = AD_MUX_ATTACHED;
                        break;
                case AD_MUX_ATTACHED:
-                       // check also if agg_select_timer expired(so the edable port will take place only after this timer)
-                       if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) {
-                               port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state
-                       } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) {    // if UNSELECTED or STANDBY
+                       /* check also if agg_select_timer expired (so the
+                        * edable port will take place only after this timer)
+                        */
+                       if ((port->sm_vars & AD_PORT_SELECTED) &&
+                           (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) &&
+                           !__check_agg_selection_timer(port)) {
+                               port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;
+                       } else if (!(port->sm_vars & AD_PORT_SELECTED) ||
+                                  (port->sm_vars & AD_PORT_STANDBY)) {
+                               /* if UNSELECTED or STANDBY */
                                port->sm_vars &= ~AD_PORT_READY_N;
-                               // in order to withhold the selection logic to check all ports READY_N value
-                               // every callback cycle to update ready variable, we check READY_N and update READY here
+                               /* in order to withhold the selection logic to
+                                * check all ports READY_N value every callback
+                                * cycle to update ready variable, we check
+                                * READY_N and update READY here
+                                */
                                __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
-                               port->sm_mux_state = AD_MUX_DETACHED;// next state
+                               port->sm_mux_state = AD_MUX_DETACHED;
                        }
                        break;
                case AD_MUX_COLLECTING_DISTRIBUTING:
-                       if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) ||
-                           !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)
-                          ) {
-                               port->sm_mux_state = AD_MUX_ATTACHED;// next state
-
+                       if (!(port->sm_vars & AD_PORT_SELECTED) ||
+                           (port->sm_vars & AD_PORT_STANDBY) ||
+                           !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)) {
+                               port->sm_mux_state = AD_MUX_ATTACHED;
                        } else {
-                               // if port state hasn't changed make
-                               // sure that a collecting distributing
-                               // port in an active aggregator is enabled
+                               /* if port state hasn't changed make
+                                * sure that a collecting distributing
+                                * port in an active aggregator is enabled
+                                */
                                if (port->aggregator &&
                                    port->aggregator->is_active &&
                                    !__port_is_enabled(port)) {
@@ -927,19 +919,18 @@ static void ad_mux_machine(struct port *port)
                                }
                        }
                        break;
-               default:    //to silence the compiler
+               default:
                        break;
                }
        }
 
-       // check if the state machine was changed
+       /* check if the state machine was changed */
        if (port->sm_mux_state != last_state) {
                pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n",
                         port->actor_port_number, last_state,
                         port->sm_mux_state);
                switch (port->sm_mux_state) {
                case AD_MUX_DETACHED:
-                       __detach_bond_from_agg(port);
                        port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
                        ad_disable_collecting_distributing(port);
                        port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
@@ -950,7 +941,6 @@ static void ad_mux_machine(struct port *port)
                        port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
                        break;
                case AD_MUX_ATTACHED:
-                       __attach_bond_to_agg(port);
                        port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION;
                        port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
                        port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
@@ -963,7 +953,7 @@ static void ad_mux_machine(struct port *port)
                        ad_enable_collecting_distributing(port);
                        port->ntt = true;
                        break;
-               default:    //to silence the compiler
+               default:
                        break;
                }
        }
@@ -982,59 +972,63 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 {
        rx_states_t last_state;
 
-       // keep current State Machine state to compare later if it was changed
+       /* keep current State Machine state to compare later if it was
+        * changed
+        */
        last_state = port->sm_rx_state;
 
-       // check if state machine should change state
-       // first, check if port was reinitialized
+       /* check if state machine should change state */
+
+       /* first, check if port was reinitialized */
        if (port->sm_vars & AD_PORT_BEGIN)
-               /* next state */
                port->sm_rx_state = AD_RX_INITIALIZE;
-       // check if port is not enabled
+       /* check if port is not enabled */
        else if (!(port->sm_vars & AD_PORT_BEGIN)
                 && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED))
-               /* next state */
                port->sm_rx_state = AD_RX_PORT_DISABLED;
-       // check if new lacpdu arrived
-       else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) {
-               port->sm_rx_timer_counter = 0; // zero timer
+       /* check if new lacpdu arrived */
+       else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) ||
+                (port->sm_rx_state == AD_RX_DEFAULTED) ||
+                (port->sm_rx_state == AD_RX_CURRENT))) {
+               port->sm_rx_timer_counter = 0;
                port->sm_rx_state = AD_RX_CURRENT;
        } else {
-               // if timer is on, and if it is expired
-               if (port->sm_rx_timer_counter && !(--port->sm_rx_timer_counter)) {
+               /* if timer is on, and if it is expired */
+               if (port->sm_rx_timer_counter &&
+                   !(--port->sm_rx_timer_counter)) {
                        switch (port->sm_rx_state) {
                        case AD_RX_EXPIRED:
-                               port->sm_rx_state = AD_RX_DEFAULTED;            // next state
+                               port->sm_rx_state = AD_RX_DEFAULTED;
                                break;
                        case AD_RX_CURRENT:
-                               port->sm_rx_state = AD_RX_EXPIRED;          // next state
+                               port->sm_rx_state = AD_RX_EXPIRED;
                                break;
-                       default:    //to silence the compiler
+                       default:
                                break;
                        }
                } else {
-                       // if no lacpdu arrived and no timer is on
+                       /* if no lacpdu arrived and no timer is on */
                        switch (port->sm_rx_state) {
                        case AD_RX_PORT_DISABLED:
                                if (port->sm_vars & AD_PORT_MOVED)
-                                       port->sm_rx_state = AD_RX_INITIALIZE;       // next state
+                                       port->sm_rx_state = AD_RX_INITIALIZE;
                                else if (port->is_enabled
                                         && (port->sm_vars
                                             & AD_PORT_LACP_ENABLED))
-                                       port->sm_rx_state = AD_RX_EXPIRED;      // next state
+                                       port->sm_rx_state = AD_RX_EXPIRED;
                                else if (port->is_enabled
                                         && ((port->sm_vars
                                              & AD_PORT_LACP_ENABLED) == 0))
-                                       port->sm_rx_state = AD_RX_LACP_DISABLED;    // next state
+                                       port->sm_rx_state = AD_RX_LACP_DISABLED;
                                break;
-                       default:    //to silence the compiler
+                       default:
                                break;
 
                        }
                }
        }
 
-       // check if the State machine was changed or new lacpdu arrived
+       /* check if the State machine was changed or new lacpdu arrived */
        if ((port->sm_rx_state != last_state) || (lacpdu)) {
                pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n",
                         port->actor_port_number, last_state,
@@ -1049,10 +1043,9 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        __record_default(port);
                        port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
                        port->sm_vars &= ~AD_PORT_MOVED;
-                       port->sm_rx_state = AD_RX_PORT_DISABLED;        // next state
-
-                       /*- Fall Through -*/
+                       port->sm_rx_state = AD_RX_PORT_DISABLED;
 
+                       /* Fall Through */
                case AD_RX_PORT_DISABLED:
                        port->sm_vars &= ~AD_PORT_MATCHED;
                        break;
@@ -1064,13 +1057,15 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
                        break;
                case AD_RX_EXPIRED:
-                       //Reset of the Synchronization flag. (Standard 43.4.12)
-                       //This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the
-                       //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
+                       /* Reset of the Synchronization flag (Standard 43.4.12)
+                        * This reset cause to disable this port in the
+                        * COLLECTING_DISTRIBUTING state of the mux machine in
+                        * case of EXPIRED even if LINK_DOWN didn't arrive for
+                        * the port.
+                        */
                        port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
                        port->sm_vars &= ~AD_PORT_MATCHED;
-                       port->partner_oper.port_state |=
-                               AD_STATE_LACP_ACTIVITY;
+                       port->partner_oper.port_state |= AD_STATE_LACP_ACTIVITY;
                        port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
                        port->actor_oper_port_state |= AD_STATE_EXPIRED;
                        break;
@@ -1082,10 +1077,11 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        break;
                case AD_RX_CURRENT:
                        /* detect loopback situation */
-                       if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system), &(port->actor_system))) {
-                               pr_err("%s: An illegal loopback occurred on adapter (%s).\n"
-                                      "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
-                                      port->slave->bond->dev->name, port->slave->dev->name);
+                       if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system),
+                                             &(port->actor_system))) {
+                               pr_err("%s: An illegal loopback occurred on adapter (%s).\nCheck the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
+                                      port->slave->bond->dev->name,
+                                      port->slave->dev->name);
                                return;
                        }
                        __update_selected(lacpdu, port);
@@ -1094,7 +1090,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT));
                        port->actor_oper_port_state &= ~AD_STATE_EXPIRED;
                        break;
-               default:    /* to silence the compiler */
+               default:
                        break;
                }
        }
@@ -1103,13 +1099,14 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
 /**
  * ad_tx_machine - handle a port's tx state machine
  * @port: the port we're looking at
- *
  */
 static void ad_tx_machine(struct port *port)
 {
-       // check if tx timer expired, to verify that we do not send more than 3 packets per second
+       /* check if tx timer expired, to verify that we do not send more than
+        * 3 packets per second
+        */
        if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) {
-               // check if there is something to send
+               /* check if there is something to send */
                if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
                        __update_lacpdu_from_port(port);
 
@@ -1117,14 +1114,16 @@ static void ad_tx_machine(struct port *port)
                                pr_debug("Sent LACPDU on port %d\n",
                                         port->actor_port_number);
 
-                               /* mark ntt as false, so it will not be sent again until
-                                  demanded */
+                               /* mark ntt as false, so it will not be sent
+                                * again until demanded
+                                */
                                port->ntt = false;
                        }
                }
-               // restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND
-               port->sm_tx_timer_counter =
-                       ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
+               /* restart tx timer(to verify that we will not exceed
+                * AD_MAX_TX_IN_SECOND
+                */
+               port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
        }
 }
 
@@ -1138,76 +1137,79 @@ static void ad_periodic_machine(struct port *port)
 {
        periodic_states_t last_state;
 
-       // keep current state machine state to compare later if it was changed
+       /* keep current state machine state to compare later if it was changed */
        last_state = port->sm_periodic_state;
 
-       // check if port was reinitialized
+       /* check if port was reinitialized */
        if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) ||
            (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & AD_STATE_LACP_ACTIVITY))
           ) {
-               port->sm_periodic_state = AD_NO_PERIODIC;            // next state
+               port->sm_periodic_state = AD_NO_PERIODIC;
        }
-       // check if state machine should change state
+       /* check if state machine should change state */
        else if (port->sm_periodic_timer_counter) {
-               // check if periodic state machine expired
+               /* check if periodic state machine expired */
                if (!(--port->sm_periodic_timer_counter)) {
-                       // if expired then do tx
-                       port->sm_periodic_state = AD_PERIODIC_TX;    // next state
+                       /* if expired then do tx */
+                       port->sm_periodic_state = AD_PERIODIC_TX;
                } else {
-                       // If not expired, check if there is some new timeout parameter from the partner state
+                       /* If not expired, check if there is some new timeout
+                        * parameter from the partner state
+                        */
                        switch (port->sm_periodic_state) {
                        case AD_FAST_PERIODIC:
                                if (!(port->partner_oper.port_state
                                      & AD_STATE_LACP_TIMEOUT))
-                                       port->sm_periodic_state = AD_SLOW_PERIODIC;  // next state
+                                       port->sm_periodic_state = AD_SLOW_PERIODIC;
                                break;
                        case AD_SLOW_PERIODIC:
                                if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) {
-                                       // stop current timer
                                        port->sm_periodic_timer_counter = 0;
-                                       port->sm_periodic_state = AD_PERIODIC_TX;        // next state
+                                       port->sm_periodic_state = AD_PERIODIC_TX;
                                }
                                break;
-                       default:    //to silence the compiler
+                       default:
                                break;
                        }
                }
        } else {
                switch (port->sm_periodic_state) {
                case AD_NO_PERIODIC:
-                       port->sm_periodic_state = AD_FAST_PERIODIC;      // next state
+                       port->sm_periodic_state = AD_FAST_PERIODIC;
                        break;
                case AD_PERIODIC_TX:
-                       if (!(port->partner_oper.port_state
-                             & AD_STATE_LACP_TIMEOUT))
-                               port->sm_periodic_state = AD_SLOW_PERIODIC;  // next state
+                       if (!(port->partner_oper.port_state &
+                           AD_STATE_LACP_TIMEOUT))
+                               port->sm_periodic_state = AD_SLOW_PERIODIC;
                        else
-                               port->sm_periodic_state = AD_FAST_PERIODIC;  // next state
+                               port->sm_periodic_state = AD_FAST_PERIODIC;
                        break;
-               default:    //to silence the compiler
+               default:
                        break;
                }
        }
 
-       // check if the state machine was changed
+       /* check if the state machine was changed */
        if (port->sm_periodic_state != last_state) {
                pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n",
                         port->actor_port_number, last_state,
                         port->sm_periodic_state);
                switch (port->sm_periodic_state) {
                case AD_NO_PERIODIC:
-                       port->sm_periodic_timer_counter = 0;       // zero timer
+                       port->sm_periodic_timer_counter = 0;
                        break;
                case AD_FAST_PERIODIC:
-                       port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle
+                       /* decrement 1 tick we lost in the PERIODIC_TX cycle */
+                       port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1;
                        break;
                case AD_SLOW_PERIODIC:
-                       port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle
+                       /* decrement 1 tick we lost in the PERIODIC_TX cycle */
+                       port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1;
                        break;
                case AD_PERIODIC_TX:
                        port->ntt = true;
                        break;
-               default:    //to silence the compiler
+               default:
                        break;
                }
        }
@@ -1230,30 +1232,38 @@ static void ad_port_selection_logic(struct port *port)
        struct slave *slave;
        int found = 0;
 
-       // if the port is already Selected, do nothing
+       /* if the port is already Selected, do nothing */
        if (port->sm_vars & AD_PORT_SELECTED)
                return;
 
        bond = __get_bond_by_port(port);
 
-       // if the port is connected to other aggregator, detach it
+       /* if the port is connected to other aggregator, detach it */
        if (port->aggregator) {
-               // detach the port from its former aggregator
+               /* detach the port from its former aggregator */
                temp_aggregator = port->aggregator;
                for (curr_port = temp_aggregator->lag_ports; curr_port;
                     last_port = curr_port,
-                            curr_port = curr_port->next_port_in_aggregator) {
+                    curr_port = curr_port->next_port_in_aggregator) {
                        if (curr_port == port) {
                                temp_aggregator->num_of_ports--;
-                               if (!last_port) {// if it is the first port attached to the aggregator
+                               /* if it is the first port attached to the
+                                * aggregator
+                                */
+                               if (!last_port) {
                                        temp_aggregator->lag_ports =
                                                port->next_port_in_aggregator;
-                               } else {// not the first port attached to the aggregator
+                               } else {
+                                       /* not the first port attached to the
+                                        * aggregator
+                                        */
                                        last_port->next_port_in_aggregator =
                                                port->next_port_in_aggregator;
                                }
 
-                               // clear the port's relations to this aggregator
+                               /* clear the port's relations to this
+                                * aggregator
+                                */
                                port->aggregator = NULL;
                                port->next_port_in_aggregator = NULL;
                                port->actor_port_aggregator_identifier = 0;
@@ -1261,25 +1271,30 @@ static void ad_port_selection_logic(struct port *port)
                                pr_debug("Port %d left LAG %d\n",
                                         port->actor_port_number,
                                         temp_aggregator->aggregator_identifier);
-                               // if the aggregator is empty, clear its parameters, and set it ready to be attached
+                               /* if the aggregator is empty, clear its
+                                * parameters, and set it ready to be attached
+                                */
                                if (!temp_aggregator->lag_ports)
                                        ad_clear_agg(temp_aggregator);
                                break;
                        }
                }
-               if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list
-                       pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
-                                  port->slave->bond->dev->name,
-                                  port->actor_port_number,
-                                  port->slave->dev->name,
-                                  port->aggregator->aggregator_identifier);
+               if (!curr_port) {
+                       /* meaning: the port was related to an aggregator
+                        * but was not on the aggregator port list
+                        */
+                       pr_warn("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
+                               port->slave->bond->dev->name,
+                               port->actor_port_number,
+                               port->slave->dev->name,
+                               port->aggregator->aggregator_identifier);
                }
        }
-       // search on all aggregators for a suitable aggregator for this port
+       /* search on all aggregators for a suitable aggregator for this port */
        bond_for_each_slave(bond, slave, iter) {
                aggregator = &(SLAVE_AD_INFO(slave).aggregator);
 
-               // keep a free aggregator for later use(if needed)
+               /* keep a free aggregator for later use(if needed) */
                if (!aggregator->lag_ports) {
                        if (!free_aggregator)
                                free_aggregator = aggregator;
@@ -1306,23 +1321,26 @@ static void ad_port_selection_logic(struct port *port)
                                 port->actor_port_number,
                                 port->aggregator->aggregator_identifier);
 
-                       // mark this port as selected
+                       /* mark this port as selected */
                        port->sm_vars |= AD_PORT_SELECTED;
                        found = 1;
                        break;
                }
        }
 
-       // the port couldn't find an aggregator - attach it to a new aggregator
+       /* the port couldn't find an aggregator - attach it to a new
+        * aggregator
+        */
        if (!found) {
                if (free_aggregator) {
-                       // assign port a new aggregator
+                       /* assign port a new aggregator */
                        port->aggregator = free_aggregator;
                        port->actor_port_aggregator_identifier =
                                port->aggregator->aggregator_identifier;
 
-                       // update the new aggregator's parameters
-                       // if port was responsed from the end-user
+                       /* update the new aggregator's parameters
+                        * if port was responsed from the end-user
+                        */
                        if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)
                                /* if port is full duplex */
                                port->aggregator->is_individual = false;
@@ -1341,7 +1359,7 @@ static void ad_port_selection_logic(struct port *port)
                        port->aggregator->lag_ports = port;
                        port->aggregator->num_of_ports++;
 
-                       // mark this port as selected
+                       /* mark this port as selected */
                        port->sm_vars |= AD_PORT_SELECTED;
 
                        pr_debug("Port %d joined LAG %d(new LAG)\n",
@@ -1353,23 +1371,24 @@ static void ad_port_selection_logic(struct port *port)
                               port->actor_port_number, port->slave->dev->name);
                }
        }
-       // if all aggregator's ports are READY_N == TRUE, set ready=TRUE in all aggregator's ports
-       // else set ready=FALSE in all aggregator's ports
-       __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
+       /* if all aggregator's ports are READY_N == TRUE, set ready=TRUE
+        * in all aggregator's ports, else set ready=FALSE in all
+        * aggregator's ports
+        */
+       __set_agg_ports_ready(port->aggregator,
+                             __agg_ports_are_ready(port->aggregator));
 
        aggregator = __get_first_agg(port);
        ad_agg_selection_logic(aggregator);
 }
 
-/*
- * Decide if "agg" is a better choice for the new active aggregator that
+/* Decide if "agg" is a better choice for the new active aggregator that
  * the current best, according to the ad_select policy.
  */
 static struct aggregator *ad_agg_selection_test(struct aggregator *best,
                                                struct aggregator *curr)
 {
-       /*
-        * 0. If no best, select current.
+       /* 0. If no best, select current.
         *
         * 1. If the current agg is not individual, and the best is
         *    individual, select current.
@@ -1425,9 +1444,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
                break;
 
        default:
-               pr_warning("%s: Impossible agg select mode %d\n",
-                          curr->slave->bond->dev->name,
-                          __get_agg_selection_mode(curr->lag_ports));
+               pr_warn("%s: Impossible agg select mode %d\n",
+                       curr->slave->bond->dev->name,
+                       __get_agg_selection_mode(curr->lag_ports));
                break;
        }
 
@@ -1437,10 +1456,12 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
 static int agg_device_up(const struct aggregator *agg)
 {
        struct port *port = agg->lag_ports;
+
        if (!port)
                return 0;
-       return (netif_running(port->slave->dev) &&
-               netif_carrier_ok(port->slave->dev));
+
+       return netif_running(port->slave->dev) &&
+              netif_carrier_ok(port->slave->dev);
 }
 
 /**
@@ -1476,11 +1497,11 @@ static void ad_agg_selection_logic(struct aggregator *agg)
        struct slave *slave;
        struct port *port;
 
+       rcu_read_lock();
        origin = agg;
        active = __get_active_agg(agg);
        best = (active && agg_device_up(active)) ? active : NULL;
 
-       rcu_read_lock();
        bond_for_each_slave_rcu(bond, slave, iter) {
                agg = &(SLAVE_AD_INFO(slave).aggregator);
 
@@ -1492,8 +1513,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
 
        if (best &&
            __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) {
-               /*
-                * For the STABLE policy, don't replace the old active
+               /* For the STABLE policy, don't replace the old active
                 * aggregator if it's still active (it has an answering
                 * partner) or if both the best and active don't have an
                 * answering partner.
@@ -1501,7 +1521,8 @@ static void ad_agg_selection_logic(struct aggregator *agg)
                if (active && active->lag_ports &&
                    active->lag_ports->is_enabled &&
                    (__agg_has_partner(active) ||
-                    (!__agg_has_partner(active) && !__agg_has_partner(best)))) {
+                    (!__agg_has_partner(active) &&
+                    !__agg_has_partner(best)))) {
                        if (!(!active->actor_oper_aggregator_key &&
                              best->actor_oper_aggregator_key)) {
                                best = NULL;
@@ -1538,7 +1559,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
 
                /* check if any partner replys */
                if (best->is_individual) {
-                       pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
+                       pr_warn("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
                                best->slave ?
                                best->slave->bond->dev->name : "NULL");
                }
@@ -1552,7 +1573,9 @@ static void ad_agg_selection_logic(struct aggregator *agg)
                         best->partner_oper_aggregator_key,
                         best->is_individual, best->is_active);
 
-               /* disable the ports that were related to the former active_aggregator */
+               /* disable the ports that were related to the former
+                * active_aggregator
+                */
                if (active) {
                        for (port = active->lag_ports; port;
                             port = port->next_port_in_aggregator) {
@@ -1561,8 +1584,7 @@ static void ad_agg_selection_logic(struct aggregator *agg)
                }
        }
 
-       /*
-        * if the selected aggregator is of join individuals
+       /* if the selected aggregator is of join individuals
         * (partner_system is NULL), enable their ports
         */
        active = __get_active_agg(origin);
@@ -1584,7 +1606,6 @@ static void ad_agg_selection_logic(struct aggregator *agg)
 /**
  * ad_clear_agg - clear a given aggregator's parameters
  * @aggregator: the aggregator we're looking at
- *
  */
 static void ad_clear_agg(struct aggregator *aggregator)
 {
@@ -1608,7 +1629,6 @@ static void ad_clear_agg(struct aggregator *aggregator)
 /**
  * ad_initialize_agg - initialize a given aggregator's parameters
  * @aggregator: the aggregator we're looking at
- *
  */
 static void ad_initialize_agg(struct aggregator *aggregator)
 {
@@ -1625,7 +1645,6 @@ static void ad_initialize_agg(struct aggregator *aggregator)
  * ad_initialize_port - initialize a given port's parameters
  * @aggregator: the aggregator we're looking at
  * @lacp_fast: boolean. whether fast periodic should be used
- *
  */
 static void ad_initialize_port(struct port *port, int lacp_fast)
 {
@@ -1657,8 +1676,10 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
                port->ntt = false;
                port->actor_admin_port_key = 1;
                port->actor_oper_port_key  = 1;
-               port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
-               port->actor_oper_port_state  = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY;
+               port->actor_admin_port_state = AD_STATE_AGGREGATION |
+                                              AD_STATE_LACP_ACTIVITY;
+               port->actor_oper_port_state  = AD_STATE_AGGREGATION |
+                                              AD_STATE_LACP_ACTIVITY;
 
                if (lacp_fast)
                        port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT;
@@ -1667,7 +1688,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
                memcpy(&port->partner_oper, &tmpl, sizeof(tmpl));
 
                port->is_enabled = true;
-               // ****** private parameters ******
+               /* private parameters */
                port->sm_vars = 0x3;
                port->sm_rx_state = 0;
                port->sm_rx_timer_counter = 0;
@@ -1705,11 +1726,12 @@ static void ad_enable_collecting_distributing(struct port *port)
 /**
  * ad_disable_collecting_distributing - disable a port's transmit/receive
  * @port: the port we're looking at
- *
  */
 static void ad_disable_collecting_distributing(struct port *port)
 {
-       if (port->aggregator && !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), &(null_mac_addr))) {
+       if (port->aggregator &&
+           !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system),
+                              &(null_mac_addr))) {
                pr_debug("Disabling port %d(LAG %d)\n",
                         port->actor_port_number,
                         port->aggregator->aggregator_identifier);
@@ -1717,66 +1739,22 @@ static void ad_disable_collecting_distributing(struct port *port)
        }
 }
 
-#if 0
-/**
- * ad_marker_info_send - send a marker information frame
- * @port: the port we're looking at
- *
- * This function does nothing since we decided not to implement send and handle
- * response for marker PDU's, in this stage, but only to respond to marker
- * information.
- */
-static void ad_marker_info_send(struct port *port)
-{
-       struct bond_marker marker;
-       u16 index;
-
-       // fill the marker PDU with the appropriate values
-       marker.subtype = 0x02;
-       marker.version_number = 0x01;
-       marker.tlv_type = AD_MARKER_INFORMATION_SUBTYPE;
-       marker.marker_length = 0x16;
-       // convert requester_port to Big Endian
-       marker.requester_port = (((port->actor_port_number & 0xFF) << 8) |((u16)(port->actor_port_number & 0xFF00) >> 8));
-       marker.requester_system = port->actor_system;
-       // convert requester_port(u32) to Big Endian
-       marker.requester_transaction_id =
-               (((++port->transaction_id & 0xFF) << 24)
-                | ((port->transaction_id & 0xFF00) << 8)
-                | ((port->transaction_id & 0xFF0000) >> 8)
-                | ((port->transaction_id & 0xFF000000) >> 24));
-       marker.pad = 0;
-       marker.tlv_type_terminator = 0x00;
-       marker.terminator_length = 0x00;
-       for (index = 0; index < 90; index++)
-               marker.reserved_90[index] = 0;
-
-       // send the marker information
-       if (ad_marker_send(port, &marker) >= 0) {
-               pr_debug("Sent Marker Information on port %d\n",
-                        port->actor_port_number);
-       }
-}
-#endif
-
 /**
  * ad_marker_info_received - handle receive of a Marker information frame
  * @marker_info: Marker info received
  * @port: the port we're looking at
- *
  */
 static void ad_marker_info_received(struct bond_marker *marker_info,
        struct port *port)
 {
        struct bond_marker marker;
 
-       // copy the received marker data to the response marker
-       //marker = *marker_info;
+       /* copy the received marker data to the response marker */
        memcpy(&marker, marker_info, sizeof(struct bond_marker));
-       // change the marker subtype to marker response
+       /* change the marker subtype to marker response */
        marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE;
-       // send the marker response
 
+       /* send the marker response */
        if (ad_marker_send(port, &marker) >= 0) {
                pr_debug("Sent Marker Response on port %d\n",
                         port->actor_port_number);
@@ -1793,22 +1771,21 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
  * information.
  */
 static void ad_marker_response_received(struct bond_marker *marker,
-       struct port *port)
+                                       struct port *port)
 {
-       marker = NULL; /* just to satisfy the compiler */
-       port = NULL;  /* just to satisfy the compiler */
-       // DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW
+       marker = NULL;
+       port = NULL;
+       /* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */
 }
 
-//////////////////////////////////////////////////////////////////////////////////////
-// ================= AD exported functions to the main bonding code ==================
-//////////////////////////////////////////////////////////////////////////////////////
+/* ========= AD exported functions to the main bonding code ========= */
 
-// Check aggregators status in team every T seconds
+/* Check aggregators status in team every T seconds */
 #define AD_AGGREGATOR_SELECTION_TIMER  8
 
-/*
- * bond_3ad_initiate_agg_selection(struct bonding *bond)
+/**
+ * bond_3ad_initiate_agg_selection - initate aggregator selection
+ * @bond: bonding struct
  *
  * Set the aggregation selection timer, to initiate an agg selection in
  * the very near future.  Called during first initialization, and during
@@ -1839,7 +1816,9 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
                BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
                BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
 
-               // initialize how many times this module is called in one second(should be about every 100ms)
+               /* initialize how many times this module is called in one
+                * second (should be about every 100ms)
+                */
                ad_ticks_per_sec = tick_resolution;
 
                bond_3ad_initiate_agg_selection(bond,
@@ -1874,21 +1853,21 @@ void bond_3ad_bind_slave(struct slave *slave)
                port->actor_port_number = SLAVE_AD_INFO(slave).id;
                /* key is determined according to the link speed, duplex and user key(which
                 * is yet not supported)
-                *              ------------------------------------------------------------
-                * Port key :   | User key                       |      Speed       |Duplex|
-                *              ------------------------------------------------------------
-                *              16                               6               1 0
                 */
-               port->actor_admin_port_key = 0; /* initialize this parameter */
+               port->actor_admin_port_key = 0;
                port->actor_admin_port_key |= __get_duplex(port);
                port->actor_admin_port_key |= (__get_link_speed(port) << 1);
                port->actor_oper_port_key = port->actor_admin_port_key;
-               /* if the port is not full duplex, then the port should be not lacp Enabled */
+               /* if the port is not full duplex, then the port should be not
+                * lacp Enabled
+                */
                if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS))
                        port->sm_vars &= ~AD_PORT_LACP_ENABLED;
                /* actor system is the bond's system */
                port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
-               /* tx timer(to verify that no more than MAX_TX_IN_SECOND lacpdu's are sent in one second) */
+               /* tx timer(to verify that no more than MAX_TX_IN_SECOND
+                * lacpdu's are sent in one second)
+                */
                port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND;
                port->aggregator = NULL;
                port->next_port_in_aggregator = NULL;
@@ -1925,16 +1904,13 @@ void bond_3ad_unbind_slave(struct slave *slave)
        struct slave *slave_iter;
        struct list_head *iter;
 
-       // find the aggregator related to this slave
        aggregator = &(SLAVE_AD_INFO(slave).aggregator);
-
-       // find the port related to this slave
        port = &(SLAVE_AD_INFO(slave).port);
 
-       // if slave is null, the whole port is not initialized
+       /* if slave is null, the whole port is not initialized */
        if (!port->slave) {
-               pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n",
-                          slave->bond->dev->name, slave->dev->name);
+               pr_warn("Warning: %s: Trying to unbind an uninitialized port on %s\n",
+                       slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -1946,34 +1922,42 @@ void bond_3ad_unbind_slave(struct slave *slave)
        __update_lacpdu_from_port(port);
        ad_lacpdu_send(port);
 
-       // check if this aggregator is occupied
+       /* check if this aggregator is occupied */
        if (aggregator->lag_ports) {
-               // check if there are other ports related to this aggregator except
-               // the port related to this slave(thats ensure us that there is a
-               // reason to search for new aggregator, and that we will find one
-               if ((aggregator->lag_ports != port) || (aggregator->lag_ports->next_port_in_aggregator)) {
-                       // find new aggregator for the related port(s)
+               /* check if there are other ports related to this aggregator
+                * except the port related to this slave(thats ensure us that
+                * there is a reason to search for new aggregator, and that we
+                * will find one
+                */
+               if ((aggregator->lag_ports != port) ||
+                   (aggregator->lag_ports->next_port_in_aggregator)) {
+                       /* find new aggregator for the related port(s) */
                        bond_for_each_slave(bond, slave_iter, iter) {
                                new_aggregator = &(SLAVE_AD_INFO(slave_iter).aggregator);
-                               // if the new aggregator is empty, or it is connected to our port only
-                               if (!new_aggregator->lag_ports
-                                   || ((new_aggregator->lag_ports == port)
-                                       && !new_aggregator->lag_ports->next_port_in_aggregator))
+                               /* if the new aggregator is empty, or it is
+                                * connected to our port only
+                                */
+                               if (!new_aggregator->lag_ports ||
+                                   ((new_aggregator->lag_ports == port) &&
+                                    !new_aggregator->lag_ports->next_port_in_aggregator))
                                        break;
                        }
                        if (!slave_iter)
                                new_aggregator = NULL;
-                       // if new aggregator found, copy the aggregator's parameters
-                       // and connect the related lag_ports to the new aggregator
+
+                       /* if new aggregator found, copy the aggregator's
+                        * parameters and connect the related lag_ports to the
+                        * new aggregator
+                        */
                        if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
                                pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n",
                                         aggregator->aggregator_identifier,
                                         new_aggregator->aggregator_identifier);
 
-                               if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) {
+                               if ((new_aggregator->lag_ports == port) &&
+                                   new_aggregator->is_active) {
                                        pr_info("%s: Removing an active aggregator\n",
                                                aggregator->slave->bond->dev->name);
-                                       // select new active aggregator
                                         select_new_active_agg = 1;
                                }
 
@@ -1989,30 +1973,33 @@ void bond_3ad_unbind_slave(struct slave *slave)
                                new_aggregator->is_active = aggregator->is_active;
                                new_aggregator->num_of_ports = aggregator->num_of_ports;
 
-                               // update the information that is written on the ports about the aggregator
+                               /* update the information that is written on
+                                * the ports about the aggregator
+                                */
                                for (temp_port = aggregator->lag_ports; temp_port;
                                     temp_port = temp_port->next_port_in_aggregator) {
                                        temp_port->aggregator = new_aggregator;
                                        temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier;
                                }
 
-                               // clear the aggregator
                                ad_clear_agg(aggregator);
 
                                if (select_new_active_agg)
                                        ad_agg_selection_logic(__get_first_agg(port));
                        } else {
-                               pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
-                                          slave->bond->dev->name);
+                               pr_warn("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n",
+                                       slave->bond->dev->name);
                        }
-               } else { // in case that the only port related to this aggregator is the one we want to remove
+               } else {
+                       /* in case that the only port related to this
+                        * aggregator is the one we want to remove
+                        */
                        select_new_active_agg = aggregator->is_active;
-                       // clear the aggregator
                        ad_clear_agg(aggregator);
                        if (select_new_active_agg) {
                                pr_info("%s: Removing an active aggregator\n",
                                        slave->bond->dev->name);
-                               // select new active aggregator
+                               /* select new active aggregator */
                                temp_aggregator = __get_first_agg(port);
                                if (temp_aggregator)
                                        ad_agg_selection_logic(temp_aggregator);
@@ -2021,15 +2008,19 @@ void bond_3ad_unbind_slave(struct slave *slave)
        }
 
        pr_debug("Unbinding port %d\n", port->actor_port_number);
-       // find the aggregator that this port is connected to
+
+       /* find the aggregator that this port is connected to */
        bond_for_each_slave(bond, slave_iter, iter) {
                temp_aggregator = &(SLAVE_AD_INFO(slave_iter).aggregator);
                prev_port = NULL;
-               // search the port in the aggregator's related ports
+               /* search the port in the aggregator's related ports */
                for (temp_port = temp_aggregator->lag_ports; temp_port;
                     prev_port = temp_port,
-                            temp_port = temp_port->next_port_in_aggregator) {
-                       if (temp_port == port) { // the aggregator found - detach the port from this aggregator
+                    temp_port = temp_port->next_port_in_aggregator) {
+                       if (temp_port == port) {
+                               /* the aggregator found - detach the port from
+                                * this aggregator
+                                */
                                if (prev_port)
                                        prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator;
                                else
@@ -2037,12 +2028,11 @@ void bond_3ad_unbind_slave(struct slave *slave)
                                temp_aggregator->num_of_ports--;
                                if (temp_aggregator->num_of_ports == 0) {
                                        select_new_active_agg = temp_aggregator->is_active;
-                                       // clear the aggregator
                                        ad_clear_agg(temp_aggregator);
                                        if (select_new_active_agg) {
                                                pr_info("%s: Removing an active aggregator\n",
                                                        slave->bond->dev->name);
-                                               // select new active aggregator
+                                               /* select new active aggregator */
                                                ad_agg_selection_logic(__get_first_agg(port));
                                        }
                                }
@@ -2083,15 +2073,16 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
                goto re_arm;
 
        /* check if agg_select_timer timer after initialize is timed out */
-       if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) {
+       if (BOND_AD_INFO(bond).agg_select_timer &&
+           !(--BOND_AD_INFO(bond).agg_select_timer)) {
                slave = bond_first_slave_rcu(bond);
                port = slave ? &(SLAVE_AD_INFO(slave).port) : NULL;
 
                /* select the active aggregator for the bond */
                if (port) {
                        if (!port->slave) {
-                               pr_warning("%s: Warning: bond's first port is uninitialized\n",
-                                          bond->dev->name);
+                               pr_warn("%s: Warning: bond's first port is uninitialized\n",
+                                       bond->dev->name);
                                goto re_arm;
                        }
 
@@ -2105,8 +2096,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        bond_for_each_slave_rcu(bond, slave, iter) {
                port = &(SLAVE_AD_INFO(slave).port);
                if (!port->slave) {
-                       pr_warning("%s: Warning: Found an uninitialized port\n",
-                                  bond->dev->name);
+                       pr_warn("%s: Warning: Found an uninitialized port\n",
+                               bond->dev->name);
                        goto re_arm;
                }
 
@@ -2145,7 +2136,8 @@ re_arm:
  * received frames (loopback). Since only the payload is given to this
  * function, it check for loopback.
  */
-static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length)
+static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
+                                 u16 length)
 {
        struct port *port;
        int ret = RX_HANDLER_ANOTHER;
@@ -2155,8 +2147,8 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1
                port = &(SLAVE_AD_INFO(slave).port);
 
                if (!port->slave) {
-                       pr_warning("%s: Warning: port of slave %s is uninitialized\n",
-                                  slave->dev->name, slave->bond->dev->name);
+                       pr_warn("%s: Warning: port of slave %s is uninitialized\n",
+                               slave->dev->name, slave->bond->dev->name);
                        return ret;
                }
 
@@ -2173,7 +2165,9 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1
 
                case AD_TYPE_MARKER:
                        ret = RX_HANDLER_CONSUMED;
-                       // No need to convert fields to Little Endian since we don't use the marker's fields.
+                       /* No need to convert fields to Little Endian since we
+                        * don't use the marker's fields.
+                        */
 
                        switch (((struct bond_marker *)lacpdu)->tlv_type) {
                        case AD_MARKER_INFORMATION_SUBTYPE:
@@ -2211,8 +2205,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave)
 
        /* if slave is null, the whole port is not initialized */
        if (!port->slave) {
-               pr_warning("Warning: %s: speed changed for uninitialized port on %s\n",
-                          slave->bond->dev->name, slave->dev->name);
+               pr_warn("Warning: %s: speed changed for uninitialized port on %s\n",
+                       slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -2244,8 +2238,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
 
        /* if slave is null, the whole port is not initialized */
        if (!port->slave) {
-               pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n",
-                          slave->bond->dev->name, slave->dev->name);
+               pr_warn("%s: Warning: duplex changed for uninitialized port on %s\n",
+                       slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -2278,8 +2272,8 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
 
        /* if slave is null, the whole port is not initialized */
        if (!port->slave) {
-               pr_warning("Warning: %s: link status changed for uninitialized port on %s\n",
-                          slave->bond->dev->name, slave->dev->name);
+               pr_warn("Warning: %s: link status changed for uninitialized port on %s\n",
+                       slave->bond->dev->name, slave->dev->name);
                return;
        }
 
@@ -2317,10 +2311,13 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
        __release_state_machine_lock(port);
 }
 
-/*
- * set link state for bonding master: if we have an active
- * aggregator, we're up, if not, we're down.  Presumes that we cannot
- * have an active aggregator if there are no slaves with link up.
+/**
+ * bond_3ad_set_carrier - set link state for bonding master
+ * @bond - bonding structure
+ *
+ * if we have an active aggregator, we're up, if not, we're down.
+ * Presumes that we cannot have an active aggregator if there are
+ * no slaves with link up.
  *
  * This behavior complies with IEEE 802.3 section 43.3.9.
  *
@@ -2331,32 +2328,32 @@ int bond_3ad_set_carrier(struct bonding *bond)
 {
        struct aggregator *active;
        struct slave *first_slave;
+       int ret = 1;
 
        rcu_read_lock();
        first_slave = bond_first_slave_rcu(bond);
-       rcu_read_unlock();
-       if (!first_slave)
-               return 0;
+       if (!first_slave) {
+               ret = 0;
+               goto out;
+       }
        active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator));
        if (active) {
                /* are enough slaves available to consider link up? */
                if (active->num_of_ports < bond->params.min_links) {
                        if (netif_carrier_ok(bond->dev)) {
                                netif_carrier_off(bond->dev);
-                               return 1;
+                               goto out;
                        }
                } else if (!netif_carrier_ok(bond->dev)) {
                        netif_carrier_on(bond->dev);
-                       return 1;
+                       goto out;
                }
-               return 0;
-       }
-
-       if (netif_carrier_ok(bond->dev)) {
+       } else if (netif_carrier_ok(bond->dev)) {
                netif_carrier_off(bond->dev);
-               return 1;
        }
-       return 0;
+out:
+       rcu_read_unlock();
+       return ret;
 }
 
 /**
@@ -2388,7 +2385,8 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
                ad_info->ports = aggregator->num_of_ports;
                ad_info->actor_key = aggregator->actor_oper_aggregator_key;
                ad_info->partner_key = aggregator->partner_oper_aggregator_key;
-               memcpy(ad_info->partner_system, aggregator->partner_system.mac_addr_value, ETH_ALEN);
+               memcpy(ad_info->partner_system,
+                      aggregator->partner_system.mac_addr_value, ETH_ALEN);
                return 0;
        }
 
@@ -2460,7 +2458,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
        }
 
        /* we couldn't find any suitable slave after the agg_no, so use the
-        * first suitable found, if found. */
+        * first suitable found, if found.
+        */
        if (first_ok_slave)
                bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);
        else
@@ -2493,7 +2492,10 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
        return ret;
 }
 
-/*
+/**
+ * bond_3ad_update_lacp_rate - change the lacp rate
+ * @bond - bonding struct
+ *
  * When modify lacp_rate parameter via sysfs,
  * update actor_oper_port_state of each port.
  *
index e06c445..f2fe6cb 100644 (file)
@@ -3213,37 +3213,34 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
        if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                return -EPERM;
 
-       slave_dev = dev_get_by_name(net, ifr->ifr_slave);
+       slave_dev = __dev_get_by_name(net, ifr->ifr_slave);
 
        pr_debug("slave_dev=%p:\n", slave_dev);
 
        if (!slave_dev)
-               res = -ENODEV;
-       else {
-               pr_debug("slave_dev->name=%s:\n", slave_dev->name);
-               switch (cmd) {
-               case BOND_ENSLAVE_OLD:
-               case SIOCBONDENSLAVE:
-                       res = bond_enslave(bond_dev, slave_dev);
-                       break;
-               case BOND_RELEASE_OLD:
-               case SIOCBONDRELEASE:
-                       res = bond_release(bond_dev, slave_dev);
-                       break;
-               case BOND_SETHWADDR_OLD:
-               case SIOCBONDSETHWADDR:
-                       bond_set_dev_addr(bond_dev, slave_dev);
-                       res = 0;
-                       break;
-               case BOND_CHANGE_ACTIVE_OLD:
-               case SIOCBONDCHANGEACTIVE:
-                       res = bond_option_active_slave_set(bond, slave_dev);
-                       break;
-               default:
-                       res = -EOPNOTSUPP;
-               }
+               return -ENODEV;
 
-               dev_put(slave_dev);
+       pr_debug("slave_dev->name=%s:\n", slave_dev->name);
+       switch (cmd) {
+       case BOND_ENSLAVE_OLD:
+       case SIOCBONDENSLAVE:
+               res = bond_enslave(bond_dev, slave_dev);
+               break;
+       case BOND_RELEASE_OLD:
+       case SIOCBONDRELEASE:
+               res = bond_release(bond_dev, slave_dev);
+               break;
+       case BOND_SETHWADDR_OLD:
+       case SIOCBONDSETHWADDR:
+               bond_set_dev_addr(bond_dev, slave_dev);
+               res = 0;
+               break;
+       case BOND_CHANGE_ACTIVE_OLD:
+       case SIOCBONDCHANGEACTIVE:
+               res = bond_option_active_slave_set(bond, slave_dev);
+               break;
+       default:
+               res = -EOPNOTSUPP;
        }
 
        return res;
@@ -3692,7 +3689,8 @@ static inline int bond_slave_override(struct bonding *bond,
 }
 
 
-static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb,
+                            void *accel_priv)
 {
        /*
         * This helper function exists to help dev_pick_tx get the correct
index 9e7d95d..d447b88 100644 (file)
@@ -104,7 +104,7 @@ config CAN_JANZ_ICAN3
 
 config CAN_FLEXCAN
        tristate "Support for Freescale FLEXCAN based chips"
-       depends on ARM || PPC
+       depends on (ARM && CPU_LITTLE_ENDIAN) || PPC
        ---help---
          Say Y here if you want to support for Freescale FlexCAN.
 
index 5df7f98..fbb61a0 100644 (file)
@@ -44,7 +44,8 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
                        "esd CAN-PCI/PMC/266, "
                        "esd CAN-PCIe/2000, "
                        "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), "
-                       "IXXAT PC-I 04/PCI")
+                       "IXXAT PC-I 04/PCI, "
+                       "ELCUS CAN-200-PCI")
 MODULE_LICENSE("GPL v2");
 
 #define PLX_PCI_MAX_CHAN 2
@@ -122,6 +123,11 @@ struct plx_pci_card {
 #define ESD_PCI_SUB_SYS_ID_PCIE2000    0x0200
 #define ESD_PCI_SUB_SYS_ID_PCI104200   0x0501
 
+#define CAN200PCI_DEVICE_ID            0x9030
+#define CAN200PCI_VENDOR_ID            0x10b5
+#define CAN200PCI_SUB_DEVICE_ID                0x0301
+#define CAN200PCI_SUB_VENDOR_ID                0xe1c5
+
 #define IXXAT_PCI_VENDOR_ID            0x10b5
 #define IXXAT_PCI_DEVICE_ID            0x9050
 #define IXXAT_PCI_SUB_SYS_ID           0x2540
@@ -233,6 +239,14 @@ static struct plx_pci_card_info plx_pci_card_info_cti = {
        /* based on PLX9030 */
 };
 
+static struct plx_pci_card_info plx_pci_card_info_elcus = {
+       "Eclus CAN-200-PCI", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {3, 0x00, 0x80} },
+       &plx_pci_reset_common
+       /* based on PLX9030 */
+};
+
 static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
        {
                /* Adlink PCI-7841/cPCI-7841 */
@@ -318,6 +332,13 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
                0, 0,
                (kernel_ulong_t)&plx_pci_card_info_cti
        },
+       {
+               /* Elcus CAN-200-PCI */
+               CAN200PCI_VENDOR_ID, CAN200PCI_DEVICE_ID,
+               CAN200PCI_SUB_VENDOR_ID, CAN200PCI_SUB_DEVICE_ID,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_elcus
+       },
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, plx_pci_tbl);
index 60d95b4..3e2bd9d 100644 (file)
@@ -518,10 +518,10 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
                data = (cf->can_id & CAN_SFF_MASK) << 18;
        hecc_write_mbx(priv, mbxno, HECC_CANMID, data);
        hecc_write_mbx(priv, mbxno, HECC_CANMDL,
-               be32_to_cpu(*(u32 *)(cf->data)));
+               be32_to_cpu(*(__be32 *)(cf->data)));
        if (cf->can_dlc > 4)
                hecc_write_mbx(priv, mbxno, HECC_CANMDH,
-                       be32_to_cpu(*(u32 *)(cf->data + 4)));
+                       be32_to_cpu(*(__be32 *)(cf->data + 4)));
        else
                *(u32 *)(cf->data + 4) = 0;
        can_put_echo_skb(skb, ndev, mbxno);
@@ -569,12 +569,10 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno)
                cf->can_id |= CAN_RTR_FLAG;
        cf->can_dlc = get_can_dlc(data & 0xF);
        data = hecc_read_mbx(priv, mbxno, HECC_CANMDL);
-       *(u32 *)(cf->data) = cpu_to_be32(data);
+       *(__be32 *)(cf->data) = cpu_to_be32(data);
        if (cf->can_dlc > 4) {
                data = hecc_read_mbx(priv, mbxno, HECC_CANMDH);
-               *(u32 *)(cf->data + 4) = cpu_to_be32(data);
-       } else {
-               *(u32 *)(cf->data + 4) = 0;
+               *(__be32 *)(cf->data + 4) = cpu_to_be32(data);
        }
        spin_lock_irqsave(&priv->mbx_lock, flags);
        hecc_clear_bit(priv, HECC_CANME, mbx_mask);
index f219d38..7a79b60 100644 (file)
@@ -395,6 +395,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave)
                if (duplicate_slave)
                        eql_kill_one_slave(queue, duplicate_slave);
 
+               dev_hold(slave->dev);
                list_add(&slave->list, &queue->all_slaves);
                queue->num_slaves++;
                slave->dev->flags |= IFF_SLAVE;
@@ -413,39 +414,35 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t __user *
        if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
                return -EFAULT;
 
-       slave_dev  = dev_get_by_name(&init_net, srq.slave_name);
-       if (slave_dev) {
-               if ((master_dev->flags & IFF_UP) == IFF_UP) {
-                       /* slave is not a master & not already a slave: */
-                       if (!eql_is_master(slave_dev) &&
-                           !eql_is_slave(slave_dev)) {
-                               slave_t *s = kmalloc(sizeof(*s), GFP_KERNEL);
-                               equalizer_t *eql = netdev_priv(master_dev);
-                               int ret;
-
-                               if (!s) {
-                                       dev_put(slave_dev);
-                                       return -ENOMEM;
-                               }
-
-                               memset(s, 0, sizeof(*s));
-                               s->dev = slave_dev;
-                               s->priority = srq.priority;
-                               s->priority_bps = srq.priority;
-                               s->priority_Bps = srq.priority / 8;
-
-                               spin_lock_bh(&eql->queue.lock);
-                               ret = __eql_insert_slave(&eql->queue, s);
-                               if (ret) {
-                                       dev_put(slave_dev);
-                                       kfree(s);
-                               }
-                               spin_unlock_bh(&eql->queue.lock);
-
-                               return ret;
-                       }
+       slave_dev = __dev_get_by_name(&init_net, srq.slave_name);
+       if (!slave_dev)
+               return -ENODEV;
+
+       if ((master_dev->flags & IFF_UP) == IFF_UP) {
+               /* slave is not a master & not already a slave: */
+               if (!eql_is_master(slave_dev) && !eql_is_slave(slave_dev)) {
+                       slave_t *s = kmalloc(sizeof(*s), GFP_KERNEL);
+                       equalizer_t *eql = netdev_priv(master_dev);
+                       int ret;
+
+                       if (!s)
+                               return -ENOMEM;
+
+                       memset(s, 0, sizeof(*s));
+                       s->dev = slave_dev;
+                       s->priority = srq.priority;
+                       s->priority_bps = srq.priority;
+                       s->priority_Bps = srq.priority / 8;
+
+                       spin_lock_bh(&eql->queue.lock);
+                       ret = __eql_insert_slave(&eql->queue, s);
+                       if (ret)
+                               kfree(s);
+
+                       spin_unlock_bh(&eql->queue.lock);
+
+                       return ret;
                }
-               dev_put(slave_dev);
        }
 
        return -EINVAL;
@@ -461,24 +458,20 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t __use
        if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
                return -EFAULT;
 
-       slave_dev = dev_get_by_name(&init_net, srq.slave_name);
-       ret = -EINVAL;
-       if (slave_dev) {
-               spin_lock_bh(&eql->queue.lock);
-
-               if (eql_is_slave(slave_dev)) {
-                       slave_t *slave = __eql_find_slave_dev(&eql->queue,
-                                                             slave_dev);
+       slave_dev = __dev_get_by_name(&init_net, srq.slave_name);
+       if (!slave_dev)
+               return -ENODEV;
 
-                       if (slave) {
-                               eql_kill_one_slave(&eql->queue, slave);
-                               ret = 0;
-                       }
+       ret = -EINVAL;
+       spin_lock_bh(&eql->queue.lock);
+       if (eql_is_slave(slave_dev)) {
+               slave_t *slave = __eql_find_slave_dev(&eql->queue, slave_dev);
+               if (slave) {
+                       eql_kill_one_slave(&eql->queue, slave);
+                       ret = 0;
                }
-               dev_put(slave_dev);
-
-               spin_unlock_bh(&eql->queue.lock);
        }
+       spin_unlock_bh(&eql->queue.lock);
 
        return ret;
 }
@@ -494,7 +487,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
        if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
                return -EFAULT;
 
-       slave_dev = dev_get_by_name(&init_net, sc.slave_name);
+       slave_dev = __dev_get_by_name(&init_net, sc.slave_name);
        if (!slave_dev)
                return -ENODEV;
 
@@ -510,8 +503,6 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
        }
        spin_unlock_bh(&eql->queue.lock);
 
-       dev_put(slave_dev);
-
        if (!ret && copy_to_user(scp, &sc, sizeof (slave_config_t)))
                ret = -EFAULT;
 
@@ -529,7 +520,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
        if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
                return -EFAULT;
 
-       slave_dev = dev_get_by_name(&init_net, sc.slave_name);
+       slave_dev = __dev_get_by_name(&init_net, sc.slave_name);
        if (!slave_dev)
                return -ENODEV;
 
@@ -548,8 +539,6 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
        }
        spin_unlock_bh(&eql->queue.lock);
 
-       dev_put(slave_dev);
-
        return ret;
 }
 
index 9142b47..c53384d 100644 (file)
@@ -252,7 +252,7 @@ static int el3_isa_id_sequence(__be16 *phys_addr)
                for (i = 0; i < el3_cards; i++) {
                        struct el3_private *lp = netdev_priv(el3_devs[i]);
                        if (lp->type == EL3_PNP &&
-                           ether_addr_equal(phys_addr, el3_devs[i]->dev_addr)) {
+                           ether_addr_equal((u8 *)phys_addr, el3_devs[i]->dev_addr)) {
                                if (el3_debug > 3)
                                        pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n",
                                                phys_addr[0] & 0xff, phys_addr[0] >> 8,
index b1fae36..a75092d 100644 (file)
@@ -751,7 +751,7 @@ struct amd8111e_priv{
        const char *name;
        struct pci_dev *pci_dev;        /* Ptr to the associated pci_dev */
        struct net_device* amd8111e_net_dev;    /* ptr to associated net_device */
-       /* Transmit and recive skbs */
+       /* Transmit and receive skbs */
        struct sk_buff *tx_skbuff[NUM_TX_BUFFERS];
        struct sk_buff *rx_skbuff[NUM_RX_BUFFERS];
        /* Transmit and receive dma mapped addr */
index d71103d..8fc93c5 100644 (file)
@@ -106,6 +106,9 @@ struct alx_priv {
        u16 msg_enable;
 
        bool msi;
+
+       /* protects hw.stats */
+       spinlock_t stats_lock;
 };
 
 extern const struct ethtool_ops alx_ethtool_ops;
index 45b3650..08e22df 100644 (file)
 #include "reg.h"
 #include "hw.h"
 
+/* The order of these strings must match the order of the fields in
+ * struct alx_hw_stats
+ * See hw.h
+ */
+static const char alx_gstrings_stats[][ETH_GSTRING_LEN] = {
+       "rx_packets",
+       "rx_bcast_packets",
+       "rx_mcast_packets",
+       "rx_pause_packets",
+       "rx_ctrl_packets",
+       "rx_fcs_errors",
+       "rx_length_errors",
+       "rx_bytes",
+       "rx_runt_packets",
+       "rx_fragments",
+       "rx_64B_or_less_packets",
+       "rx_65B_to_127B_packets",
+       "rx_128B_to_255B_packets",
+       "rx_256B_to_511B_packets",
+       "rx_512B_to_1023B_packets",
+       "rx_1024B_to_1518B_packets",
+       "rx_1519B_to_mtu_packets",
+       "rx_oversize_packets",
+       "rx_rxf_ov_drop_packets",
+       "rx_rrd_ov_drop_packets",
+       "rx_align_errors",
+       "rx_bcast_bytes",
+       "rx_mcast_bytes",
+       "rx_address_errors",
+       "tx_packets",
+       "tx_bcast_packets",
+       "tx_mcast_packets",
+       "tx_pause_packets",
+       "tx_exc_defer_packets",
+       "tx_ctrl_packets",
+       "tx_defer_packets",
+       "tx_bytes",
+       "tx_64B_or_less_packets",
+       "tx_65B_to_127B_packets",
+       "tx_128B_to_255B_packets",
+       "tx_256B_to_511B_packets",
+       "tx_512B_to_1023B_packets",
+       "tx_1024B_to_1518B_packets",
+       "tx_1519B_to_mtu_packets",
+       "tx_single_collision",
+       "tx_multiple_collisions",
+       "tx_late_collision",
+       "tx_abort_collision",
+       "tx_underrun",
+       "tx_trd_eop",
+       "tx_length_errors",
+       "tx_trunc_packets",
+       "tx_bcast_bytes",
+       "tx_mcast_bytes",
+       "tx_update",
+};
+
+#define ALX_NUM_STATS ARRAY_SIZE(alx_gstrings_stats)
+
+
 static u32 alx_get_supported_speeds(struct alx_hw *hw)
 {
        u32 supported = SUPPORTED_10baseT_Half |
@@ -201,6 +261,44 @@ static void alx_set_msglevel(struct net_device *netdev, u32 data)
        alx->msg_enable = data;
 }
 
+static void alx_get_ethtool_stats(struct net_device *netdev,
+                                 struct ethtool_stats *estats, u64 *data)
+{
+       struct alx_priv *alx = netdev_priv(netdev);
+       struct alx_hw *hw = &alx->hw;
+
+       spin_lock(&alx->stats_lock);
+
+       alx_update_hw_stats(hw);
+       BUILD_BUG_ON(sizeof(hw->stats) - offsetof(struct alx_hw_stats, rx_ok) <
+                    ALX_NUM_STATS * sizeof(u64));
+       memcpy(data, &hw->stats.rx_ok, ALX_NUM_STATS * sizeof(u64));
+
+       spin_unlock(&alx->stats_lock);
+}
+
+static void alx_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
+{
+       switch (stringset) {
+       case ETH_SS_STATS:
+               memcpy(buf, &alx_gstrings_stats, sizeof(alx_gstrings_stats));
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+static int alx_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ALX_NUM_STATS;
+       default:
+               return -EINVAL;
+       }
+}
+
 const struct ethtool_ops alx_ethtool_ops = {
        .get_settings   = alx_get_settings,
        .set_settings   = alx_set_settings,
@@ -209,4 +307,7 @@ const struct ethtool_ops alx_ethtool_ops = {
        .get_msglevel   = alx_get_msglevel,
        .set_msglevel   = alx_set_msglevel,
        .get_link       = ethtool_op_get_link,
+       .get_strings    = alx_get_strings,
+       .get_sset_count = alx_get_sset_count,
+       .get_ethtool_stats      = alx_get_ethtool_stats,
 };
index 1e8c24a..7712f06 100644 (file)
@@ -1050,3 +1050,61 @@ bool alx_get_phy_info(struct alx_hw *hw)
 
        return true;
 }
+
+void alx_update_hw_stats(struct alx_hw *hw)
+{
+       /* RX stats */
+       hw->stats.rx_ok          += alx_read_mem32(hw, ALX_MIB_RX_OK);
+       hw->stats.rx_bcast       += alx_read_mem32(hw, ALX_MIB_RX_BCAST);
+       hw->stats.rx_mcast       += alx_read_mem32(hw, ALX_MIB_RX_MCAST);
+       hw->stats.rx_pause       += alx_read_mem32(hw, ALX_MIB_RX_PAUSE);
+       hw->stats.rx_ctrl        += alx_read_mem32(hw, ALX_MIB_RX_CTRL);
+       hw->stats.rx_fcs_err     += alx_read_mem32(hw, ALX_MIB_RX_FCS_ERR);
+       hw->stats.rx_len_err     += alx_read_mem32(hw, ALX_MIB_RX_LEN_ERR);
+       hw->stats.rx_byte_cnt    += alx_read_mem32(hw, ALX_MIB_RX_BYTE_CNT);
+       hw->stats.rx_runt        += alx_read_mem32(hw, ALX_MIB_RX_RUNT);
+       hw->stats.rx_frag        += alx_read_mem32(hw, ALX_MIB_RX_FRAG);
+       hw->stats.rx_sz_64B      += alx_read_mem32(hw, ALX_MIB_RX_SZ_64B);
+       hw->stats.rx_sz_127B     += alx_read_mem32(hw, ALX_MIB_RX_SZ_127B);
+       hw->stats.rx_sz_255B     += alx_read_mem32(hw, ALX_MIB_RX_SZ_255B);
+       hw->stats.rx_sz_511B     += alx_read_mem32(hw, ALX_MIB_RX_SZ_511B);
+       hw->stats.rx_sz_1023B    += alx_read_mem32(hw, ALX_MIB_RX_SZ_1023B);
+       hw->stats.rx_sz_1518B    += alx_read_mem32(hw, ALX_MIB_RX_SZ_1518B);
+       hw->stats.rx_sz_max      += alx_read_mem32(hw, ALX_MIB_RX_SZ_MAX);
+       hw->stats.rx_ov_sz       += alx_read_mem32(hw, ALX_MIB_RX_OV_SZ);
+       hw->stats.rx_ov_rxf      += alx_read_mem32(hw, ALX_MIB_RX_OV_RXF);
+       hw->stats.rx_ov_rrd      += alx_read_mem32(hw, ALX_MIB_RX_OV_RRD);
+       hw->stats.rx_align_err   += alx_read_mem32(hw, ALX_MIB_RX_ALIGN_ERR);
+       hw->stats.rx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BCCNT);
+       hw->stats.rx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_MCCNT);
+       hw->stats.rx_err_addr    += alx_read_mem32(hw, ALX_MIB_RX_ERRADDR);
+
+       /* TX stats */
+       hw->stats.tx_ok          += alx_read_mem32(hw, ALX_MIB_TX_OK);
+       hw->stats.tx_bcast       += alx_read_mem32(hw, ALX_MIB_TX_BCAST);
+       hw->stats.tx_mcast       += alx_read_mem32(hw, ALX_MIB_TX_MCAST);
+       hw->stats.tx_pause       += alx_read_mem32(hw, ALX_MIB_TX_PAUSE);
+       hw->stats.tx_exc_defer   += alx_read_mem32(hw, ALX_MIB_TX_EXC_DEFER);
+       hw->stats.tx_ctrl        += alx_read_mem32(hw, ALX_MIB_TX_CTRL);
+       hw->stats.tx_defer       += alx_read_mem32(hw, ALX_MIB_TX_DEFER);
+       hw->stats.tx_byte_cnt    += alx_read_mem32(hw, ALX_MIB_TX_BYTE_CNT);
+       hw->stats.tx_sz_64B      += alx_read_mem32(hw, ALX_MIB_TX_SZ_64B);
+       hw->stats.tx_sz_127B     += alx_read_mem32(hw, ALX_MIB_TX_SZ_127B);
+       hw->stats.tx_sz_255B     += alx_read_mem32(hw, ALX_MIB_TX_SZ_255B);
+       hw->stats.tx_sz_511B     += alx_read_mem32(hw, ALX_MIB_TX_SZ_511B);
+       hw->stats.tx_sz_1023B    += alx_read_mem32(hw, ALX_MIB_TX_SZ_1023B);
+       hw->stats.tx_sz_1518B    += alx_read_mem32(hw, ALX_MIB_TX_SZ_1518B);
+       hw->stats.tx_sz_max      += alx_read_mem32(hw, ALX_MIB_TX_SZ_MAX);
+       hw->stats.tx_single_col  += alx_read_mem32(hw, ALX_MIB_TX_SINGLE_COL);
+       hw->stats.tx_multi_col   += alx_read_mem32(hw, ALX_MIB_TX_MULTI_COL);
+       hw->stats.tx_late_col    += alx_read_mem32(hw, ALX_MIB_TX_LATE_COL);
+       hw->stats.tx_abort_col   += alx_read_mem32(hw, ALX_MIB_TX_ABORT_COL);
+       hw->stats.tx_underrun    += alx_read_mem32(hw, ALX_MIB_TX_UNDERRUN);
+       hw->stats.tx_trd_eop     += alx_read_mem32(hw, ALX_MIB_TX_TRD_EOP);
+       hw->stats.tx_len_err     += alx_read_mem32(hw, ALX_MIB_TX_LEN_ERR);
+       hw->stats.tx_trunc       += alx_read_mem32(hw, ALX_MIB_TX_TRUNC);
+       hw->stats.tx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BCCNT);
+       hw->stats.tx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_MCCNT);
+
+       hw->stats.update         += alx_read_mem32(hw, ALX_MIB_UPDATE);
+}
index 96f3b43..1554880 100644 (file)
@@ -381,6 +381,73 @@ struct alx_rrd {
                                 ALX_ISR_RX_Q6 | \
                                 ALX_ISR_RX_Q7)
 
+/* Statistics counters collected by the MAC
+ *
+ * The order of the fields must match the strings in alx_gstrings_stats
+ * All stats fields should be u64
+ * See ethtool.c
+ */
+struct alx_hw_stats {
+       /* rx */
+       u64 rx_ok;              /* good RX packets */
+       u64 rx_bcast;           /* good RX broadcast packets */
+       u64 rx_mcast;           /* good RX multicast packets */
+       u64 rx_pause;           /* RX pause frames */
+       u64 rx_ctrl;            /* RX control packets other than pause frames */
+       u64 rx_fcs_err;         /* RX packets with bad FCS */
+       u64 rx_len_err;         /* RX packets with length != actual size */
+       u64 rx_byte_cnt;        /* good bytes received. FCS is NOT included */
+       u64 rx_runt;            /* RX packets < 64 bytes with good FCS */
+       u64 rx_frag;            /* RX packets < 64 bytes with bad FCS */
+       u64 rx_sz_64B;          /* 64 byte RX packets */
+       u64 rx_sz_127B;         /* 65-127 byte RX packets */
+       u64 rx_sz_255B;         /* 128-255 byte RX packets */
+       u64 rx_sz_511B;         /* 256-511 byte RX packets */
+       u64 rx_sz_1023B;        /* 512-1023 byte RX packets */
+       u64 rx_sz_1518B;        /* 1024-1518 byte RX packets */
+       u64 rx_sz_max;          /* 1519 byte to MTU RX packets */
+       u64 rx_ov_sz;           /* truncated RX packets, size > MTU */
+       u64 rx_ov_rxf;          /* frames dropped due to RX FIFO overflow */
+       u64 rx_ov_rrd;          /* frames dropped due to RRD overflow */
+       u64 rx_align_err;       /* alignment errors */
+       u64 rx_bc_byte_cnt;     /* RX broadcast bytes, excluding FCS */
+       u64 rx_mc_byte_cnt;     /* RX multicast bytes, excluding FCS */
+       u64 rx_err_addr;        /* packets dropped due to address filtering */
+
+       /* tx */
+       u64 tx_ok;              /* good TX packets */
+       u64 tx_bcast;           /* good TX broadcast packets */
+       u64 tx_mcast;           /* good TX multicast packets */
+       u64 tx_pause;           /* TX pause frames */
+       u64 tx_exc_defer;       /* TX packets deferred excessively */
+       u64 tx_ctrl;            /* TX control frames, excluding pause frames */
+       u64 tx_defer;           /* TX packets deferred */
+       u64 tx_byte_cnt;        /* bytes transmitted, FCS is NOT included */
+       u64 tx_sz_64B;          /* 64 byte TX packets */
+       u64 tx_sz_127B;         /* 65-127 byte TX packets */
+       u64 tx_sz_255B;         /* 128-255 byte TX packets */
+       u64 tx_sz_511B;         /* 256-511 byte TX packets */
+       u64 tx_sz_1023B;        /* 512-1023 byte TX packets */
+       u64 tx_sz_1518B;        /* 1024-1518 byte TX packets */
+       u64 tx_sz_max;          /* 1519 byte to MTU TX packets */
+       u64 tx_single_col;      /* packets TX after a single collision */
+       u64 tx_multi_col;       /* packets TX after multiple collisions */
+       u64 tx_late_col;        /* TX packets with late collisions */
+       u64 tx_abort_col;       /* TX packets aborted w/excessive collisions */
+       u64 tx_underrun;        /* TX packets aborted due to TX FIFO underrun
+                                * or TRD FIFO underrun
+                                */
+       u64 tx_trd_eop;         /* reads beyond the EOP into the next frame
+                                * when TRD was not written timely
+                                */
+       u64 tx_len_err;         /* TX packets where length != actual size */
+       u64 tx_trunc;           /* TX packets truncated due to size > MTU */
+       u64 tx_bc_byte_cnt;     /* broadcast bytes transmitted, excluding FCS */
+       u64 tx_mc_byte_cnt;     /* multicast bytes transmitted, excluding FCS */
+       u64 update;
+};
+
+
 /* maximum interrupt vectors for msix */
 #define ALX_MAX_MSIX_INTRS     16
 
@@ -424,6 +491,9 @@ struct alx_hw {
 
        /* PHY link patch flag */
        bool lnk_patch;
+
+       /* cumulated stats from the hardware (registers are cleared on read) */
+       struct alx_hw_stats stats;
 };
 
 static inline int alx_hw_revision(struct alx_hw *hw)
@@ -491,6 +561,7 @@ bool alx_phy_configured(struct alx_hw *hw);
 void alx_configure_basic(struct alx_hw *hw);
 void alx_disable_rss(struct alx_hw *hw);
 bool alx_get_phy_info(struct alx_hw *hw);
+void alx_update_hw_stats(struct alx_hw *hw);
 
 static inline u32 alx_speed_to_ethadv(int speed, u8 duplex)
 {
index c3c4c26..e92ffd6 100644 (file)
@@ -1166,10 +1166,60 @@ static void alx_poll_controller(struct net_device *netdev)
 }
 #endif
 
+static struct rtnl_link_stats64 *alx_get_stats64(struct net_device *dev,
+                                       struct rtnl_link_stats64 *net_stats)
+{
+       struct alx_priv *alx = netdev_priv(dev);
+       struct alx_hw_stats *hw_stats = &alx->hw.stats;
+
+       spin_lock(&alx->stats_lock);
+
+       alx_update_hw_stats(&alx->hw);
+
+       net_stats->tx_bytes   = hw_stats->tx_byte_cnt;
+       net_stats->rx_bytes   = hw_stats->rx_byte_cnt;
+       net_stats->multicast  = hw_stats->rx_mcast;
+       net_stats->collisions = hw_stats->tx_single_col +
+                               hw_stats->tx_multi_col +
+                               hw_stats->tx_late_col +
+                               hw_stats->tx_abort_col;
+
+       net_stats->rx_errors  = hw_stats->rx_frag +
+                               hw_stats->rx_fcs_err +
+                               hw_stats->rx_len_err +
+                               hw_stats->rx_ov_sz +
+                               hw_stats->rx_ov_rrd +
+                               hw_stats->rx_align_err +
+                               hw_stats->rx_ov_rxf;
+
+       net_stats->rx_fifo_errors   = hw_stats->rx_ov_rxf;
+       net_stats->rx_length_errors = hw_stats->rx_len_err;
+       net_stats->rx_crc_errors    = hw_stats->rx_fcs_err;
+       net_stats->rx_frame_errors  = hw_stats->rx_align_err;
+       net_stats->rx_dropped       = hw_stats->rx_ov_rrd;
+
+       net_stats->tx_errors = hw_stats->tx_late_col +
+                              hw_stats->tx_abort_col +
+                              hw_stats->tx_underrun +
+                              hw_stats->tx_trunc;
+
+       net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
+       net_stats->tx_fifo_errors    = hw_stats->tx_underrun;
+       net_stats->tx_window_errors  = hw_stats->tx_late_col;
+
+       net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors;
+       net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors;
+
+       spin_unlock(&alx->stats_lock);
+
+       return net_stats;
+}
+
 static const struct net_device_ops alx_netdev_ops = {
        .ndo_open               = alx_open,
        .ndo_stop               = alx_stop,
        .ndo_start_xmit         = alx_start_xmit,
+       .ndo_get_stats64        = alx_get_stats64,
        .ndo_set_rx_mode        = alx_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = alx_set_mac_address,
index e4358c9..af006b4 100644 (file)
 
 /* MIB */
 #define ALX_MIB_BASE                                   0x1700
+
 #define ALX_MIB_RX_OK                                  (ALX_MIB_BASE + 0)
+#define ALX_MIB_RX_BCAST                               (ALX_MIB_BASE + 4)
+#define ALX_MIB_RX_MCAST                               (ALX_MIB_BASE + 8)
+#define ALX_MIB_RX_PAUSE                               (ALX_MIB_BASE + 12)
+#define ALX_MIB_RX_CTRL                                        (ALX_MIB_BASE + 16)
+#define ALX_MIB_RX_FCS_ERR                             (ALX_MIB_BASE + 20)
+#define ALX_MIB_RX_LEN_ERR                             (ALX_MIB_BASE + 24)
+#define ALX_MIB_RX_BYTE_CNT                            (ALX_MIB_BASE + 28)
+#define ALX_MIB_RX_RUNT                                        (ALX_MIB_BASE + 32)
+#define ALX_MIB_RX_FRAG                                        (ALX_MIB_BASE + 36)
+#define ALX_MIB_RX_SZ_64B                              (ALX_MIB_BASE + 40)
+#define ALX_MIB_RX_SZ_127B                             (ALX_MIB_BASE + 44)
+#define ALX_MIB_RX_SZ_255B                             (ALX_MIB_BASE + 48)
+#define ALX_MIB_RX_SZ_511B                             (ALX_MIB_BASE + 52)
+#define ALX_MIB_RX_SZ_1023B                            (ALX_MIB_BASE + 56)
+#define ALX_MIB_RX_SZ_1518B                            (ALX_MIB_BASE + 60)
+#define ALX_MIB_RX_SZ_MAX                              (ALX_MIB_BASE + 64)
+#define ALX_MIB_RX_OV_SZ                               (ALX_MIB_BASE + 68)
+#define ALX_MIB_RX_OV_RXF                              (ALX_MIB_BASE + 72)
+#define ALX_MIB_RX_OV_RRD                              (ALX_MIB_BASE + 76)
+#define ALX_MIB_RX_ALIGN_ERR                           (ALX_MIB_BASE + 80)
+#define ALX_MIB_RX_BCCNT                               (ALX_MIB_BASE + 84)
+#define ALX_MIB_RX_MCCNT                               (ALX_MIB_BASE + 88)
 #define ALX_MIB_RX_ERRADDR                             (ALX_MIB_BASE + 92)
+
 #define ALX_MIB_TX_OK                                  (ALX_MIB_BASE + 96)
+#define ALX_MIB_TX_BCAST                               (ALX_MIB_BASE + 100)
+#define ALX_MIB_TX_MCAST                               (ALX_MIB_BASE + 104)
+#define ALX_MIB_TX_PAUSE                               (ALX_MIB_BASE + 108)
+#define ALX_MIB_TX_EXC_DEFER                           (ALX_MIB_BASE + 112)
+#define ALX_MIB_TX_CTRL                                        (ALX_MIB_BASE + 116)
+#define ALX_MIB_TX_DEFER                               (ALX_MIB_BASE + 120)
+#define ALX_MIB_TX_BYTE_CNT                            (ALX_MIB_BASE + 124)
+#define ALX_MIB_TX_SZ_64B                              (ALX_MIB_BASE + 128)
+#define ALX_MIB_TX_SZ_127B                             (ALX_MIB_BASE + 132)
+#define ALX_MIB_TX_SZ_255B                             (ALX_MIB_BASE + 136)
+#define ALX_MIB_TX_SZ_511B                             (ALX_MIB_BASE + 140)
+#define ALX_MIB_TX_SZ_1023B                            (ALX_MIB_BASE + 144)
+#define ALX_MIB_TX_SZ_1518B                            (ALX_MIB_BASE + 148)
+#define ALX_MIB_TX_SZ_MAX                              (ALX_MIB_BASE + 152)
+#define ALX_MIB_TX_SINGLE_COL                          (ALX_MIB_BASE + 156)
+#define ALX_MIB_TX_MULTI_COL                           (ALX_MIB_BASE + 160)
+#define ALX_MIB_TX_LATE_COL                            (ALX_MIB_BASE + 164)
+#define ALX_MIB_TX_ABORT_COL                           (ALX_MIB_BASE + 168)
+#define ALX_MIB_TX_UNDERRUN                            (ALX_MIB_BASE + 172)
+#define ALX_MIB_TX_TRD_EOP                             (ALX_MIB_BASE + 176)
+#define ALX_MIB_TX_LEN_ERR                             (ALX_MIB_BASE + 180)
+#define ALX_MIB_TX_TRUNC                               (ALX_MIB_BASE + 184)
+#define ALX_MIB_TX_BCCNT                               (ALX_MIB_BASE + 188)
 #define ALX_MIB_TX_MCCNT                               (ALX_MIB_BASE + 192)
+#define ALX_MIB_UPDATE                                 (ALX_MIB_BASE + 196)
 
-#define ALX_RX_STATS_BIN                               ALX_MIB_RX_OK
-#define ALX_RX_STATS_END                               ALX_MIB_RX_ERRADDR
-#define ALX_TX_STATS_BIN                               ALX_MIB_TX_OK
-#define ALX_TX_STATS_END                               ALX_MIB_TX_MCCNT
 
 #define ALX_ISR                                                0x1600
 #define ALX_ISR_DIS                                    BIT(31)
index 2980175..4d3258d 100644 (file)
@@ -1500,31 +1500,40 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
        struct net_device_stats *net_stats = &netdev->stats;
 
        atl1c_update_hw_stats(adapter);
-       net_stats->rx_packets = hw_stats->rx_ok;
-       net_stats->tx_packets = hw_stats->tx_ok;
        net_stats->rx_bytes   = hw_stats->rx_byte_cnt;
        net_stats->tx_bytes   = hw_stats->tx_byte_cnt;
        net_stats->multicast  = hw_stats->rx_mcast;
        net_stats->collisions = hw_stats->tx_1_col +
-                               hw_stats->tx_2_col * 2 +
-                               hw_stats->tx_late_col + hw_stats->tx_abort_col;
-       net_stats->rx_errors  = hw_stats->rx_frag + hw_stats->rx_fcs_err +
-                               hw_stats->rx_len_err + hw_stats->rx_sz_ov +
-                               hw_stats->rx_rrd_ov + hw_stats->rx_align_err;
+                               hw_stats->tx_2_col +
+                               hw_stats->tx_late_col +
+                               hw_stats->tx_abort_col;
+
+       net_stats->rx_errors  = hw_stats->rx_frag +
+                               hw_stats->rx_fcs_err +
+                               hw_stats->rx_len_err +
+                               hw_stats->rx_sz_ov +
+                               hw_stats->rx_rrd_ov +
+                               hw_stats->rx_align_err +
+                               hw_stats->rx_rxf_ov;
+
        net_stats->rx_fifo_errors   = hw_stats->rx_rxf_ov;
        net_stats->rx_length_errors = hw_stats->rx_len_err;
        net_stats->rx_crc_errors    = hw_stats->rx_fcs_err;
        net_stats->rx_frame_errors  = hw_stats->rx_align_err;
-       net_stats->rx_over_errors   = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov;
+       net_stats->rx_dropped       = hw_stats->rx_rrd_ov;
 
-       net_stats->rx_missed_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov;
+       net_stats->tx_errors = hw_stats->tx_late_col +
+                              hw_stats->tx_abort_col +
+                              hw_stats->tx_underrun +
+                              hw_stats->tx_trunc;
 
-       net_stats->tx_errors = hw_stats->tx_late_col + hw_stats->tx_abort_col +
-                               hw_stats->tx_underrun + hw_stats->tx_trunc;
        net_stats->tx_fifo_errors    = hw_stats->tx_underrun;
        net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
        net_stats->tx_window_errors  = hw_stats->tx_late_col;
 
+       net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors;
+       net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors;
+
        return net_stats;
 }
 
index 7a73f3a..d5c2d3e 100644 (file)
@@ -1177,32 +1177,40 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev)
        struct atl1e_hw_stats  *hw_stats = &adapter->hw_stats;
        struct net_device_stats *net_stats = &netdev->stats;
 
-       net_stats->rx_packets = hw_stats->rx_ok;
-       net_stats->tx_packets = hw_stats->tx_ok;
        net_stats->rx_bytes   = hw_stats->rx_byte_cnt;
        net_stats->tx_bytes   = hw_stats->tx_byte_cnt;
        net_stats->multicast  = hw_stats->rx_mcast;
        net_stats->collisions = hw_stats->tx_1_col +
-                               hw_stats->tx_2_col * 2 +
-                               hw_stats->tx_late_col + hw_stats->tx_abort_col;
+                               hw_stats->tx_2_col +
+                               hw_stats->tx_late_col +
+                               hw_stats->tx_abort_col;
+
+       net_stats->rx_errors  = hw_stats->rx_frag +
+                               hw_stats->rx_fcs_err +
+                               hw_stats->rx_len_err +
+                               hw_stats->rx_sz_ov +
+                               hw_stats->rx_rrd_ov +
+                               hw_stats->rx_align_err +
+                               hw_stats->rx_rxf_ov;
 
-       net_stats->rx_errors  = hw_stats->rx_frag + hw_stats->rx_fcs_err +
-                               hw_stats->rx_len_err + hw_stats->rx_sz_ov +
-                               hw_stats->rx_rrd_ov + hw_stats->rx_align_err;
        net_stats->rx_fifo_errors   = hw_stats->rx_rxf_ov;
        net_stats->rx_length_errors = hw_stats->rx_len_err;
        net_stats->rx_crc_errors    = hw_stats->rx_fcs_err;
        net_stats->rx_frame_errors  = hw_stats->rx_align_err;
-       net_stats->rx_over_errors   = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov;
+       net_stats->rx_dropped       = hw_stats->rx_rrd_ov;
 
-       net_stats->rx_missed_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov;
+       net_stats->tx_errors = hw_stats->tx_late_col +
+                              hw_stats->tx_abort_col +
+                              hw_stats->tx_underrun +
+                              hw_stats->tx_trunc;
 
-       net_stats->tx_errors = hw_stats->tx_late_col + hw_stats->tx_abort_col +
-                              hw_stats->tx_underrun + hw_stats->tx_trunc;
        net_stats->tx_fifo_errors    = hw_stats->tx_underrun;
        net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
        net_stats->tx_window_errors  = hw_stats->tx_late_col;
 
+       net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors;
+       net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors;
+
        return net_stats;
 }
 
index 55d86ec..287272d 100644 (file)
@@ -1678,33 +1678,42 @@ static void atl1_inc_smb(struct atl1_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        struct stats_msg_block *smb = adapter->smb.smb;
 
+       u64 new_rx_errors = smb->rx_frag +
+                           smb->rx_fcs_err +
+                           smb->rx_len_err +
+                           smb->rx_sz_ov +
+                           smb->rx_rxf_ov +
+                           smb->rx_rrd_ov +
+                           smb->rx_align_err;
+       u64 new_tx_errors = smb->tx_late_col +
+                           smb->tx_abort_col +
+                           smb->tx_underrun +
+                           smb->tx_trunc;
+
        /* Fill out the OS statistics structure */
-       adapter->soft_stats.rx_packets += smb->rx_ok;
-       adapter->soft_stats.tx_packets += smb->tx_ok;
+       adapter->soft_stats.rx_packets += smb->rx_ok + new_rx_errors;
+       adapter->soft_stats.tx_packets += smb->tx_ok + new_tx_errors;
        adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
        adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
        adapter->soft_stats.multicast += smb->rx_mcast;
-       adapter->soft_stats.collisions += (smb->tx_1_col + smb->tx_2_col * 2 +
-               smb->tx_late_col + smb->tx_abort_col * adapter->hw.max_retry);
+       adapter->soft_stats.collisions += smb->tx_1_col +
+                                         smb->tx_2_col +
+                                         smb->tx_late_col +
+                                         smb->tx_abort_col;
 
        /* Rx Errors */
-       adapter->soft_stats.rx_errors += (smb->rx_frag + smb->rx_fcs_err +
-               smb->rx_len_err + smb->rx_sz_ov + smb->rx_rxf_ov +
-               smb->rx_rrd_ov + smb->rx_align_err);
+       adapter->soft_stats.rx_errors += new_rx_errors;
        adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
        adapter->soft_stats.rx_length_errors += smb->rx_len_err;
        adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
        adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
-       adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
-               smb->rx_rxf_ov);
 
        adapter->soft_stats.rx_pause += smb->rx_pause;
        adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
        adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
 
        /* Tx Errors */
-       adapter->soft_stats.tx_errors += (smb->tx_late_col +
-               smb->tx_abort_col + smb->tx_underrun + smb->tx_trunc);
+       adapter->soft_stats.tx_errors += new_tx_errors;
        adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
        adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
        adapter->soft_stats.tx_window_errors += smb->tx_late_col;
@@ -1718,23 +1727,18 @@ static void atl1_inc_smb(struct atl1_adapter *adapter)
        adapter->soft_stats.tx_trunc += smb->tx_trunc;
        adapter->soft_stats.tx_pause += smb->tx_pause;
 
-       netdev->stats.rx_packets = adapter->soft_stats.rx_packets;
-       netdev->stats.tx_packets = adapter->soft_stats.tx_packets;
        netdev->stats.rx_bytes = adapter->soft_stats.rx_bytes;
        netdev->stats.tx_bytes = adapter->soft_stats.tx_bytes;
        netdev->stats.multicast = adapter->soft_stats.multicast;
        netdev->stats.collisions = adapter->soft_stats.collisions;
        netdev->stats.rx_errors = adapter->soft_stats.rx_errors;
-       netdev->stats.rx_over_errors =
-               adapter->soft_stats.rx_missed_errors;
        netdev->stats.rx_length_errors =
                adapter->soft_stats.rx_length_errors;
        netdev->stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
        netdev->stats.rx_frame_errors =
                adapter->soft_stats.rx_frame_errors;
        netdev->stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
-       netdev->stats.rx_missed_errors =
-               adapter->soft_stats.rx_missed_errors;
+       netdev->stats.rx_dropped = adapter->soft_stats.rx_rrd_ov;
        netdev->stats.tx_errors = adapter->soft_stats.tx_errors;
        netdev->stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
        netdev->stats.tx_aborted_errors =
@@ -1743,6 +1747,9 @@ static void atl1_inc_smb(struct atl1_adapter *adapter)
                adapter->soft_stats.tx_window_errors;
        netdev->stats.tx_carrier_errors =
                adapter->soft_stats.tx_carrier_errors;
+
+       netdev->stats.rx_packets = adapter->soft_stats.rx_packets;
+       netdev->stats.tx_packets = adapter->soft_stats.tx_packets;
 }
 
 static void atl1_update_mailbox(struct atl1_adapter *adapter)
@@ -1872,7 +1879,7 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
                                                adapter->rx_buffer_len);
                if (unlikely(!skb)) {
                        /* Better luck next round */
-                       adapter->netdev->stats.rx_dropped++;
+                       adapter->soft_stats.rx_dropped++;
                        break;
                }
 
index 3bf79a5..34a58cd 100644 (file)
@@ -666,6 +666,7 @@ struct atl1_sft_stats {
        u64 rx_errors;
        u64 rx_length_errors;
        u64 rx_crc_errors;
+       u64 rx_dropped;
        u64 rx_frame_errors;
        u64 rx_fifo_errors;
        u64 rx_missed_errors;
index 7f968a9..0297a79 100644 (file)
@@ -1518,14 +1518,12 @@ static int bgmac_probe(struct bcma_device *core)
        err = bgmac_mii_register(bgmac);
        if (err) {
                bgmac_err(bgmac, "Cannot register MDIO\n");
-               err = -ENOTSUPP;
                goto err_dma_free;
        }
 
        err = register_netdev(bgmac->net_dev);
        if (err) {
                bgmac_err(bgmac, "Cannot register net device\n");
-               err = -ENOTSUPP;
                goto err_mii_unregister;
        }
 
index eb105ab..391f29e 100644 (file)
@@ -520,10 +520,12 @@ struct bnx2x_fastpath {
 #define BNX2X_FP_STATE_IDLE                  0
 #define BNX2X_FP_STATE_NAPI            (1 << 0)    /* NAPI owns this FP */
 #define BNX2X_FP_STATE_POLL            (1 << 1)    /* poll owns this FP */
-#define BNX2X_FP_STATE_NAPI_YIELD      (1 << 2)    /* NAPI yielded this FP */
-#define BNX2X_FP_STATE_POLL_YIELD      (1 << 3)    /* poll yielded this FP */
+#define BNX2X_FP_STATE_DISABLED                (1 << 2)
+#define BNX2X_FP_STATE_NAPI_YIELD      (1 << 3)    /* NAPI yielded this FP */
+#define BNX2X_FP_STATE_POLL_YIELD      (1 << 4)    /* poll yielded this FP */
+#define BNX2X_FP_OWNED (BNX2X_FP_STATE_NAPI | BNX2X_FP_STATE_POLL)
 #define BNX2X_FP_YIELD (BNX2X_FP_STATE_NAPI_YIELD | BNX2X_FP_STATE_POLL_YIELD)
-#define BNX2X_FP_LOCKED        (BNX2X_FP_STATE_NAPI | BNX2X_FP_STATE_POLL)
+#define BNX2X_FP_LOCKED        (BNX2X_FP_OWNED | BNX2X_FP_STATE_DISABLED)
 #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD)
        /* protect state */
        spinlock_t lock;
@@ -613,7 +615,7 @@ static inline bool bnx2x_fp_lock_napi(struct bnx2x_fastpath *fp)
 {
        bool rc = true;
 
-       spin_lock(&fp->lock);
+       spin_lock_bh(&fp->lock);
        if (fp->state & BNX2X_FP_LOCKED) {
                WARN_ON(fp->state & BNX2X_FP_STATE_NAPI);
                fp->state |= BNX2X_FP_STATE_NAPI_YIELD;
@@ -622,7 +624,7 @@ static inline bool bnx2x_fp_lock_napi(struct bnx2x_fastpath *fp)
                /* we don't care if someone yielded */
                fp->state = BNX2X_FP_STATE_NAPI;
        }
-       spin_unlock(&fp->lock);
+       spin_unlock_bh(&fp->lock);
        return rc;
 }
 
@@ -631,14 +633,16 @@ static inline bool bnx2x_fp_unlock_napi(struct bnx2x_fastpath *fp)
 {
        bool rc = false;
 
-       spin_lock(&fp->lock);
+       spin_lock_bh(&fp->lock);
        WARN_ON(fp->state &
                (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_NAPI_YIELD));
 
        if (fp->state & BNX2X_FP_STATE_POLL_YIELD)
                rc = true;
-       fp->state = BNX2X_FP_STATE_IDLE;
-       spin_unlock(&fp->lock);
+
+       /* state ==> idle, unless currently disabled */
+       fp->state &= BNX2X_FP_STATE_DISABLED;
+       spin_unlock_bh(&fp->lock);
        return rc;
 }
 
@@ -669,7 +673,9 @@ static inline bool bnx2x_fp_unlock_poll(struct bnx2x_fastpath *fp)
 
        if (fp->state & BNX2X_FP_STATE_POLL_YIELD)
                rc = true;
-       fp->state = BNX2X_FP_STATE_IDLE;
+
+       /* state ==> idle, unless currently disabled */
+       fp->state &= BNX2X_FP_STATE_DISABLED;
        spin_unlock_bh(&fp->lock);
        return rc;
 }
@@ -677,9 +683,23 @@ static inline bool bnx2x_fp_unlock_poll(struct bnx2x_fastpath *fp)
 /* true if a socket is polling, even if it did not get the lock */
 static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
 {
-       WARN_ON(!(fp->state & BNX2X_FP_LOCKED));
+       WARN_ON(!(fp->state & BNX2X_FP_OWNED));
        return fp->state & BNX2X_FP_USER_PEND;
 }
+
+/* false if fp is currently owned */
+static inline bool bnx2x_fp_ll_disable(struct bnx2x_fastpath *fp)
+{
+       int rc = true;
+
+       spin_lock_bh(&fp->lock);
+       if (fp->state & BNX2X_FP_OWNED)
+               rc = false;
+       fp->state |= BNX2X_FP_STATE_DISABLED;
+       spin_unlock_bh(&fp->lock);
+
+       return rc;
+}
 #else
 static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
 {
@@ -709,6 +729,10 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
 {
        return false;
 }
+static inline bool bnx2x_fp_ll_disable(struct bnx2x_fastpath *fp)
+{
+       return true;
+}
 #endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /* Use 2500 as a mini-jumbo MTU for FCoE */
@@ -1542,6 +1566,7 @@ struct bnx2x {
 #define NO_ISCSI_FLAG                  (1 << 14)
 #define NO_FCOE_FLAG                   (1 << 15)
 #define BC_SUPPORTS_PFC_STATS          (1 << 17)
+#define TX_SWITCHING                   (1 << 18)
 #define BC_SUPPORTS_FCOE_FEATURES      (1 << 19)
 #define USING_SINGLE_MSIX_FLAG         (1 << 20)
 #define BC_SUPPORTS_DCBX_MSG_NON_PMF   (1 << 21)
@@ -2057,7 +2082,6 @@ int bnx2x_del_all_macs(struct bnx2x *bp,
 void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p);
 void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
                    u8 vf_valid, int fw_sb_id, int igu_sb_id);
-u32 bnx2x_get_pretend_reg(struct bnx2x *bp);
 int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
 int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
 int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode);
index 282ebf6..9d7419e 100644 (file)
 #include "bnx2x_init.h"
 #include "bnx2x_sp.h"
 
+static void bnx2x_free_fp_mem_cnic(struct bnx2x *bp);
+static int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp);
+static int bnx2x_alloc_fp_mem(struct bnx2x *bp);
+static int bnx2x_poll(struct napi_struct *napi, int budget);
+
+static void bnx2x_add_all_napi_cnic(struct bnx2x *bp)
+{
+       int i;
+
+       /* Add NAPI objects */
+       for_each_rx_queue_cnic(bp, i) {
+               netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+                              bnx2x_poll, NAPI_POLL_WEIGHT);
+               napi_hash_add(&bnx2x_fp(bp, i, napi));
+       }
+}
+
+static void bnx2x_add_all_napi(struct bnx2x *bp)
+{
+       int i;
+
+       /* Add NAPI objects */
+       for_each_eth_queue(bp, i) {
+               netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
+                              bnx2x_poll, NAPI_POLL_WEIGHT);
+               napi_hash_add(&bnx2x_fp(bp, i, napi));
+       }
+}
+
+static int bnx2x_calc_num_queues(struct bnx2x *bp)
+{
+       return  bnx2x_num_queues ?
+                min_t(int, bnx2x_num_queues, BNX2X_MAX_QUEUES(bp)) :
+                min_t(int, netif_get_num_default_rss_queues(),
+                      BNX2X_MAX_QUEUES(bp));
+}
+
 /**
  * bnx2x_move_fp - move content of the fastpath structure.
  *
@@ -145,7 +182,7 @@ static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta)
        }
 }
 
-int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
+int bnx2x_load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */
 
 /* free skb in the packet ring at pos idx
  * return idx of last bd freed
@@ -160,6 +197,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
        struct sk_buff *skb = tx_buf->skb;
        u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons;
        int nbd;
+       u16 split_bd_len = 0;
 
        /* prefetch skb end pointer to speedup dev_kfree_skb() */
        prefetch(&skb->end);
@@ -167,10 +205,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
        DP(NETIF_MSG_TX_DONE, "fp[%d]: pkt_idx %d  buff @(%p)->skb %p\n",
           txdata->txq_index, idx, tx_buf, skb);
 
-       /* unmap first bd */
        tx_start_bd = &txdata->tx_desc_ring[bd_idx].start_bd;
-       dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
-                        BD_UNMAP_LEN(tx_start_bd), DMA_TO_DEVICE);
 
        nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
 #ifdef BNX2X_STOP_ON_ERROR
@@ -188,12 +223,19 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
        --nbd;
        bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
 
-       /* ...and the TSO split header bd since they have no mapping */
+       /* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */
        if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) {
+               tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd;
+               split_bd_len = BD_UNMAP_LEN(tx_data_bd);
                --nbd;
                bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
        }
 
+       /* unmap first bd */
+       dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
+                        BD_UNMAP_LEN(tx_start_bd) + split_bd_len,
+                        DMA_TO_DEVICE);
+
        /* now free frags */
        while (nbd > 0) {
 
@@ -813,7 +855,7 @@ void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe,
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
 
-int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
+static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 {
        struct bnx2x *bp = fp->bp;
        u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
@@ -1483,7 +1525,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
        }
 }
 
-void bnx2x_free_skbs_cnic(struct bnx2x *bp)
+static void bnx2x_free_skbs_cnic(struct bnx2x *bp)
 {
        bnx2x_free_tx_skbs_cnic(bp);
        bnx2x_free_rx_skbs_cnic(bp);
@@ -1792,26 +1834,22 @@ static void bnx2x_napi_disable_cnic(struct bnx2x *bp)
 {
        int i;
 
-       local_bh_disable();
        for_each_rx_queue_cnic(bp, i) {
                napi_disable(&bnx2x_fp(bp, i, napi));
-               while (!bnx2x_fp_lock_napi(&bp->fp[i]))
-                       mdelay(1);
+               while (!bnx2x_fp_ll_disable(&bp->fp[i]))
+                       usleep_range(1000, 2000);
        }
-       local_bh_enable();
 }
 
 static void bnx2x_napi_disable(struct bnx2x *bp)
 {
        int i;
 
-       local_bh_disable();
        for_each_eth_queue(bp, i) {
                napi_disable(&bnx2x_fp(bp, i, napi));
-               while (!bnx2x_fp_lock_napi(&bp->fp[i]))
-                       mdelay(1);
+               while (!bnx2x_fp_ll_disable(&bp->fp[i]))
+                       usleep_range(1000, 2000);
        }
-       local_bh_enable();
 }
 
 void bnx2x_netif_start(struct bnx2x *bp)
@@ -1834,7 +1872,8 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
                bnx2x_napi_disable_cnic(bp);
 }
 
-u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
+u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
+                      void *accel_priv)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -2302,16 +2341,16 @@ static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port)
        int path = BP_PATH(bp);
 
        DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d]      %d, %d, %d\n",
-          path, load_count[path][0], load_count[path][1],
-          load_count[path][2]);
-       load_count[path][0]++;
-       load_count[path][1 + port]++;
+          path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
+          bnx2x_load_count[path][2]);
+       bnx2x_load_count[path][0]++;
+       bnx2x_load_count[path][1 + port]++;
        DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d]  %d, %d, %d\n",
-          path, load_count[path][0], load_count[path][1],
-          load_count[path][2]);
-       if (load_count[path][0] == 1)
+          path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
+          bnx2x_load_count[path][2]);
+       if (bnx2x_load_count[path][0] == 1)
                return FW_MSG_CODE_DRV_LOAD_COMMON;
-       else if (load_count[path][1 + port] == 1)
+       else if (bnx2x_load_count[path][1 + port] == 1)
                return FW_MSG_CODE_DRV_LOAD_PORT;
        else
                return FW_MSG_CODE_DRV_LOAD_FUNCTION;
@@ -3069,7 +3108,7 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
 /*
  * net_device service functions
  */
-int bnx2x_poll(struct napi_struct *napi, int budget)
+static int bnx2x_poll(struct napi_struct *napi, int budget)
 {
        int work_done = 0;
        u8 cos;
@@ -4196,7 +4235,7 @@ static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index)
        /* end of fastpath */
 }
 
-void bnx2x_free_fp_mem_cnic(struct bnx2x *bp)
+static void bnx2x_free_fp_mem_cnic(struct bnx2x *bp)
 {
        int i;
        for_each_cnic_queue(bp, i)
@@ -4410,7 +4449,7 @@ alloc_mem_err:
        return 0;
 }
 
-int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp)
+static int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp)
 {
        if (!NO_FCOE(bp))
                /* FCoE */
@@ -4423,7 +4462,7 @@ int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp)
        return 0;
 }
 
-int bnx2x_alloc_fp_mem(struct bnx2x *bp)
+static int bnx2x_alloc_fp_mem(struct bnx2x *bp)
 {
        int i;
 
index da8fcaa..17d1689 100644 (file)
 #include "bnx2x_sriov.h"
 
 /* This is used as a replacement for an MCP if it's not present */
-extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
-
-extern int num_queues;
-extern int int_mode;
+extern int bnx2x_load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
+extern int bnx2x_num_queues;
 
 /************************ Macros ********************************/
 #define BNX2X_PCI_FREE(x, y, size) \
@@ -417,35 +415,8 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set);
  * If bp->state is OPEN, should be called with
  * netif_addr_lock_bh()
  */
-void bnx2x_set_rx_mode(struct net_device *dev);
 void bnx2x_set_rx_mode_inner(struct bnx2x *bp);
 
-/**
- * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW.
- *
- * @bp:                driver handle
- *
- * If bp->state is OPEN, should be called with
- * netif_addr_lock_bh().
- */
-int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
-
-/**
- * bnx2x_set_q_rx_mode - configures rx_mode for a single queue.
- *
- * @bp:                        driver handle
- * @cl_id:             client id
- * @rx_mode_flags:     rx mode configuration
- * @rx_accept_flags:   rx accept configuration
- * @tx_accept_flags:   tx accept configuration (tx switch)
- * @ramrod_flags:      ramrod configuration
- */
-int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-                       unsigned long rx_mode_flags,
-                       unsigned long rx_accept_flags,
-                       unsigned long tx_accept_flags,
-                       unsigned long ramrod_flags);
-
 /* Parity errors related */
 void bnx2x_set_pf_load(struct bnx2x *bp);
 bool bnx2x_clear_pf_load(struct bnx2x *bp);
@@ -524,7 +495,8 @@ int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac);
 int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos);
 
 /* select_queue callback */
-u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb);
+u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
+                      void *accel_priv);
 
 static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
                                        struct bnx2x_fastpath *fp,
@@ -564,9 +536,6 @@ int bnx2x_reload_if_running(struct net_device *dev);
 
 int bnx2x_change_mac_addr(struct net_device *dev, void *p);
 
-/* NAPI poll Rx part */
-int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget);
-
 /* NAPI poll Tx part */
 int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata);
 
@@ -577,13 +546,9 @@ int bnx2x_resume(struct pci_dev *pdev);
 /* Release IRQ vectors */
 void bnx2x_free_irq(struct bnx2x *bp);
 
-void bnx2x_free_fp_mem_cnic(struct bnx2x *bp);
 void bnx2x_free_fp_mem(struct bnx2x *bp);
-int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp);
-int bnx2x_alloc_fp_mem(struct bnx2x *bp);
 void bnx2x_init_rx_rings(struct bnx2x *bp);
 void bnx2x_init_rx_rings_cnic(struct bnx2x *bp);
-void bnx2x_free_skbs_cnic(struct bnx2x *bp);
 void bnx2x_free_skbs(struct bnx2x *bp);
 void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw);
 void bnx2x_netif_start(struct bnx2x *bp);
@@ -607,15 +572,6 @@ int bnx2x_enable_msix(struct bnx2x *bp);
 int bnx2x_enable_msi(struct bnx2x *bp);
 
 /**
- * bnx2x_poll - NAPI callback
- *
- * @napi:      napi structure
- * @budget:
- *
- */
-int bnx2x_poll(struct napi_struct *napi, int budget);
-
-/**
  * bnx2x_low_latency_recv - LL callback
  *
  * @napi:      napi structure
@@ -861,30 +817,6 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
        sge->addr_lo = 0;
 }
 
-static inline void bnx2x_add_all_napi_cnic(struct bnx2x *bp)
-{
-       int i;
-
-       /* Add NAPI objects */
-       for_each_rx_queue_cnic(bp, i) {
-               netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
-                              bnx2x_poll, NAPI_POLL_WEIGHT);
-               napi_hash_add(&bnx2x_fp(bp, i, napi));
-       }
-}
-
-static inline void bnx2x_add_all_napi(struct bnx2x *bp)
-{
-       int i;
-
-       /* Add NAPI objects */
-       for_each_eth_queue(bp, i) {
-               netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
-                              bnx2x_poll, NAPI_POLL_WEIGHT);
-               napi_hash_add(&bnx2x_fp(bp, i, napi));
-       }
-}
-
 static inline void bnx2x_del_all_napi_cnic(struct bnx2x *bp)
 {
        int i;
@@ -918,14 +850,6 @@ static inline void bnx2x_disable_msi(struct bnx2x *bp)
        }
 }
 
-static inline int bnx2x_calc_num_queues(struct bnx2x *bp)
-{
-       return  num_queues ?
-                min_t(int, num_queues, BNX2X_MAX_QUEUES(bp)) :
-                min_t(int, netif_get_num_default_rss_queues(),
-                      BNX2X_MAX_QUEUES(bp));
-}
-
 static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp)
 {
        int i, j;
@@ -1172,8 +1096,6 @@ static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp)
                return fp->cl_id;
 }
 
-u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
-
 static inline void bnx2x_init_txdata(struct bnx2x *bp,
                                     struct bnx2x_fp_txdata *txdata, u32 cid,
                                     int txq_index, __le16 *tx_cons_sb,
@@ -1206,47 +1128,6 @@ static inline u8 bnx2x_cnic_igu_sb_id(struct bnx2x *bp)
        return bp->igu_base_sb;
 }
 
-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);
-       bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID(bp);
-       bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID;
-       bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id;
-       bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX;
-       bnx2x_init_txdata(bp, bnx2x_fcoe(bp, txdata_ptr[0]),
-                         fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX,
-                         fp);
-
-       DP(NETIF_MSG_IFUP, "created fcoe tx data (fp index %d)\n", fp->index);
-
-       /* qZone id equals to FW (per path) client id */
-       bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp);
-       /* init shortcut */
-       bnx2x_fcoe(bp, ustorm_rx_prods_offset) =
-               bnx2x_rx_ustorm_prods_offset(fp);
-
-       /* Configure Queue State object */
-       __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
-       __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
-
-       /* No multi-CoS for FCoE L2 client */
-       BUG_ON(fp->max_cos != 1);
-
-       bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id,
-                            &fp->cid, 1, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
-                            bnx2x_sp_mapping(bp, q_rdata), q_type);
-
-       DP(NETIF_MSG_IFUP,
-          "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
-          fp->index, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
-          fp->igu_sb_id);
-}
-
 static inline int bnx2x_clean_tx_queue(struct bnx2x *bp,
                                       struct bnx2x_fp_txdata *txdata)
 {
index 11fc795..9b6b3d7 100644 (file)
@@ -205,6 +205,11 @@ typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy,
                (_bank + (_addr & 0xf)), \
                _val)
 
+static int bnx2x_check_half_open_conn(struct link_params *params,
+                                     struct link_vars *vars, u8 notify);
+static int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
+                                     struct link_params *params);
+
 static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits)
 {
        u32 val = REG_RD(bp, reg);
@@ -1399,57 +1404,6 @@ static void bnx2x_update_pfc_xmac(struct link_params *params,
        udelay(30);
 }
 
-
-static void bnx2x_emac_get_pfc_stat(struct link_params *params,
-                                   u32 pfc_frames_sent[2],
-                                   u32 pfc_frames_received[2])
-{
-       /* Read pfc statistic */
-       struct bnx2x *bp = params->bp;
-       u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
-       u32 val_xon = 0;
-       u32 val_xoff = 0;
-
-       DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n");
-
-       /* PFC received frames */
-       val_xoff = REG_RD(bp, emac_base +
-                               EMAC_REG_RX_PFC_STATS_XOFF_RCVD);
-       val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT;
-       val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD);
-       val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT;
-
-       pfc_frames_received[0] = val_xon + val_xoff;
-
-       /* PFC received sent */
-       val_xoff = REG_RD(bp, emac_base +
-                               EMAC_REG_RX_PFC_STATS_XOFF_SENT);
-       val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT;
-       val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT);
-       val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT;
-
-       pfc_frames_sent[0] = val_xon + val_xoff;
-}
-
-/* Read pfc statistic*/
-void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
-                        u32 pfc_frames_sent[2],
-                        u32 pfc_frames_received[2])
-{
-       /* Read pfc statistic */
-       struct bnx2x *bp = params->bp;
-
-       DP(NETIF_MSG_LINK, "pfc statistic\n");
-
-       if (!vars->link_up)
-               return;
-
-       if (vars->mac_type == MAC_TYPE_EMAC) {
-               DP(NETIF_MSG_LINK, "About to read PFC stats from EMAC\n");
-               bnx2x_emac_get_pfc_stat(params, pfc_frames_sent,
-                                       pfc_frames_received);
-       }
-}
 /******************************************************************/
 /*                     MAC/PBF section                           */
 /******************************************************************/
@@ -8648,8 +8602,8 @@ static void bnx2x_set_limiting_mode(struct link_params *params,
        }
 }
 
-int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
-                              struct link_params *params)
+static int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
+                                     struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 edc_mode;
@@ -13413,9 +13367,9 @@ static u8 bnx2x_analyze_link_error(struct link_params *params,
 *      a fault, for example, due to break in the TX side of fiber.
 *
 ******************************************************************************/
-int bnx2x_check_half_open_conn(struct link_params *params,
-                               struct link_vars *vars,
-                               u8 notify)
+static int bnx2x_check_half_open_conn(struct link_params *params,
+                                     struct link_vars *vars,
+                                     u8 notify)
 {
        struct bnx2x *bp = params->bp;
        u32 lss_status = 0;
index 4df4523..389f5f8 100644 (file)
@@ -533,19 +533,11 @@ int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos);
 int bnx2x_ets_e3b0_config(const struct link_params *params,
                         const struct link_vars *vars,
                         struct bnx2x_ets_params *ets_params);
-/* Read pfc statistic*/
-void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
-                                                u32 pfc_frames_sent[2],
-                                                u32 pfc_frames_received[2]);
+
 void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
                            u32 chip_id, u32 shmem_base, u32 shmem2_base,
                            u8 port);
 
-int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
-                              struct link_params *params);
-
 void bnx2x_period_func(struct link_params *params, struct link_vars *vars);
 
-int bnx2x_check_half_open_conn(struct link_params *params,
-                              struct link_vars *vars, u8 notify);
 #endif /* BNX2X_LINK_H */
index 18498fe..cf17b66 100644 (file)
@@ -94,8 +94,8 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1);
 MODULE_FIRMWARE(FW_FILE_NAME_E1H);
 MODULE_FIRMWARE(FW_FILE_NAME_E2);
 
-int num_queues;
-module_param(num_queues, int, 0);
+int bnx2x_num_queues;
+module_param_named(num_queues, bnx2x_num_queues, int, 0);
 MODULE_PARM_DESC(num_queues,
                 " Set number of queues (default is as a number of CPUs)");
 
@@ -103,7 +103,7 @@ static int disable_tpa;
 module_param(disable_tpa, int, 0);
 MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 
-int int_mode;
+static int int_mode;
 module_param(int_mode, int, 0);
 MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
                                "(1 INT#x; 2 MSI)");
@@ -279,6 +279,12 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
 #define BNX2X_PREV_WAIT_NEEDED 1
 static DEFINE_SEMAPHORE(bnx2x_prev_sem);
 static LIST_HEAD(bnx2x_prev_list);
+
+/* Forward declaration */
+static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
+static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
+static int bnx2x_set_storm_rx_mode(struct bnx2x *bp);
+
 /****************************************************************************
 * General service functions
 ****************************************************************************/
@@ -3001,6 +3007,9 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp,
        if (zero_stats)
                __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags);
 
+       if (bp->flags & TX_SWITCHING)
+               __set_bit(BNX2X_Q_FLG_TX_SWITCH, &flags);
+
        __set_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, &flags);
        __set_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, &flags);
 
@@ -5857,11 +5866,11 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp)
 }
 
 /* called with netif_addr_lock_bh() */
-int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
-                       unsigned long rx_mode_flags,
-                       unsigned long rx_accept_flags,
-                       unsigned long tx_accept_flags,
-                       unsigned long ramrod_flags)
+static int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id,
+                              unsigned long rx_mode_flags,
+                              unsigned long rx_accept_flags,
+                              unsigned long tx_accept_flags,
+                              unsigned long ramrod_flags)
 {
        struct bnx2x_rx_mode_ramrod_params ramrod_param;
        int rc;
@@ -5969,7 +5978,7 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
 }
 
 /* called with netif_addr_lock_bh() */
-int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
+static int bnx2x_set_storm_rx_mode(struct bnx2x *bp)
 {
        unsigned long rx_mode_flags = 0, ramrod_flags = 0;
        unsigned long rx_accept_flags = 0, tx_accept_flags = 0;
@@ -6165,6 +6174,47 @@ static void bnx2x_init_tx_rings(struct bnx2x *bp)
                        bnx2x_init_tx_ring_one(bp->fp[i].txdata_ptr[cos]);
 }
 
+static 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);
+       bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID(bp);
+       bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID;
+       bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id;
+       bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX;
+       bnx2x_init_txdata(bp, bnx2x_fcoe(bp, txdata_ptr[0]),
+                         fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX,
+                         fp);
+
+       DP(NETIF_MSG_IFUP, "created fcoe tx data (fp index %d)\n", fp->index);
+
+       /* qZone id equals to FW (per path) client id */
+       bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp);
+       /* init shortcut */
+       bnx2x_fcoe(bp, ustorm_rx_prods_offset) =
+               bnx2x_rx_ustorm_prods_offset(fp);
+
+       /* Configure Queue State object */
+       __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type);
+       __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type);
+
+       /* No multi-CoS for FCoE L2 client */
+       BUG_ON(fp->max_cos != 1);
+
+       bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id,
+                            &fp->cid, 1, BP_FUNC(bp), bnx2x_sp(bp, q_rdata),
+                            bnx2x_sp_mapping(bp, q_rdata), q_type);
+
+       DP(NETIF_MSG_IFUP,
+          "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n",
+          fp->index, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id,
+          fp->igu_sb_id);
+}
+
 void bnx2x_nic_init_cnic(struct bnx2x *bp)
 {
        if (!NO_FCOE(bp))
@@ -8737,16 +8787,16 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
                int path = BP_PATH(bp);
 
                DP(NETIF_MSG_IFDOWN, "NO MCP - load counts[%d]      %d, %d, %d\n",
-                  path, load_count[path][0], load_count[path][1],
-                  load_count[path][2]);
-               load_count[path][0]--;
-               load_count[path][1 + port]--;
+                  path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
+                  bnx2x_load_count[path][2]);
+               bnx2x_load_count[path][0]--;
+               bnx2x_load_count[path][1 + port]--;
                DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts[%d]  %d, %d, %d\n",
-                  path, load_count[path][0], load_count[path][1],
-                  load_count[path][2]);
-               if (load_count[path][0] == 0)
+                  path, bnx2x_load_count[path][0], bnx2x_load_count[path][1],
+                  bnx2x_load_count[path][2]);
+               if (bnx2x_load_count[path][0] == 0)
                        reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON;
-               else if (load_count[path][1 + port] == 0)
+               else if (bnx2x_load_count[path][1 + port] == 0)
                        reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT;
                else
                        reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION;
@@ -9772,7 +9822,7 @@ period_task_exit:
  * Init service functions
  */
 
-u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
+static u32 bnx2x_get_pretend_reg(struct bnx2x *bp)
 {
        u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0;
        u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base;
@@ -12005,7 +12055,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp)
 }
 
 /* If bp->state is OPEN, should be called with netif_addr_lock_bh() */
-void bnx2x_set_rx_mode(struct net_device *dev)
+static void bnx2x_set_rx_mode(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -12783,8 +12833,6 @@ static int set_is_vf(int chip_id)
        }
 }
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
-
 static int bnx2x_init_one(struct pci_dev *pdev,
                                    const struct pci_device_id *ent)
 {
@@ -13859,7 +13907,7 @@ static int bnx2x_unregister_cnic(struct net_device *dev)
        return 0;
 }
 
-struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
+static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
 {
        struct bnx2x *bp = netdev_priv(dev);
        struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
@@ -13909,7 +13957,7 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
        return cp;
 }
 
-u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
+static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
 {
        struct bnx2x *bp = fp->bp;
        u32 offset = BAR_USTRORM_INTMEM;
index 98cccd4..0fb6ff2 100644 (file)
@@ -355,23 +355,6 @@ static bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o)
 
        return vp->get(vp, 1);
 }
-
-static bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
-{
-       struct bnx2x_credit_pool_obj *mp = o->macs_pool;
-       struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
-
-       if (!mp->get(mp, 1))
-               return false;
-
-       if (!vp->get(vp, 1)) {
-               mp->put(mp, 1);
-               return false;
-       }
-
-       return true;
-}
-
 static bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset)
 {
        struct bnx2x_credit_pool_obj *mp = o->macs_pool;
@@ -400,22 +383,6 @@ static bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o)
        return vp->put(vp, 1);
 }
 
-static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o)
-{
-       struct bnx2x_credit_pool_obj *mp = o->macs_pool;
-       struct bnx2x_credit_pool_obj *vp = o->vlans_pool;
-
-       if (!mp->put(mp, 1))
-               return false;
-
-       if (!vp->put(vp, 1)) {
-               mp->get(mp, 1);
-               return false;
-       }
-
-       return true;
-}
-
 /**
  * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock
  *
@@ -507,22 +474,6 @@ static void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
        }
 }
 
-/**
- * bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock
- *
- * @bp:                        device handle
- * @o:                 vlan_mac object
- *
- * @details Notice if a pending execution exists, it would perform it -
- *          possibly releasing and reclaiming the execution queue lock.
- */
-void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
-                                  struct bnx2x_vlan_mac_obj *o)
-{
-       spin_lock_bh(&o->exe_queue.lock);
-       __bnx2x_vlan_mac_h_write_unlock(bp, o);
-       spin_unlock_bh(&o->exe_queue.lock);
-}
 
 /**
  * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock
@@ -685,25 +636,6 @@ static int bnx2x_check_vlan_add(struct bnx2x *bp,
        return 0;
 }
 
-static int bnx2x_check_vlan_mac_add(struct bnx2x *bp,
-                                   struct bnx2x_vlan_mac_obj *o,
-                                  union bnx2x_classification_ramrod_data *data)
-{
-       struct bnx2x_vlan_mac_registry_elem *pos;
-
-       DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for ADD command\n",
-          data->vlan_mac.mac, data->vlan_mac.vlan);
-
-       list_for_each_entry(pos, &o->head, link)
-               if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
-                   ether_addr_equal_unaligned(data->vlan_mac.mac, pos->u.vlan_mac.mac) &&
-                   (data->vlan_mac.is_inner_mac ==
-                    pos->u.vlan_mac.is_inner_mac))
-                       return -EEXIST;
-
-       return 0;
-}
-
 /* check_del() callbacks */
 static struct bnx2x_vlan_mac_registry_elem *
        bnx2x_check_mac_del(struct bnx2x *bp,
@@ -738,26 +670,6 @@ static struct bnx2x_vlan_mac_registry_elem *
        return NULL;
 }
 
-static struct bnx2x_vlan_mac_registry_elem *
-       bnx2x_check_vlan_mac_del(struct bnx2x *bp,
-                                struct bnx2x_vlan_mac_obj *o,
-                                union bnx2x_classification_ramrod_data *data)
-{
-       struct bnx2x_vlan_mac_registry_elem *pos;
-
-       DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for DEL command\n",
-          data->vlan_mac.mac, data->vlan_mac.vlan);
-
-       list_for_each_entry(pos, &o->head, link)
-               if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) &&
-                   ether_addr_equal_unaligned(data->vlan_mac.mac, pos->u.vlan_mac.mac) &&
-                   (data->vlan_mac.is_inner_mac ==
-                    pos->u.vlan_mac.is_inner_mac))
-                       return pos;
-
-       return NULL;
-}
-
 /* check_move() callback */
 static bool bnx2x_check_move(struct bnx2x *bp,
                             struct bnx2x_vlan_mac_obj *src_o,
@@ -809,8 +721,8 @@ static inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o)
        return rx_tx_flag;
 }
 
-void bnx2x_set_mac_in_nig(struct bnx2x *bp,
-                         bool add, unsigned char *dev_addr, int index)
+static void bnx2x_set_mac_in_nig(struct bnx2x *bp,
+                                bool add, unsigned char *dev_addr, int index)
 {
        u32 wb_data[2];
        u32 reg_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM :
@@ -1124,97 +1036,6 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp,
                                        rule_cnt);
 }
 
-static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
-                                     struct bnx2x_vlan_mac_obj *o,
-                                     struct bnx2x_exeq_elem *elem,
-                                     int rule_idx, int cam_offset)
-{
-       struct bnx2x_raw_obj *raw = &o->raw;
-       struct eth_classify_rules_ramrod_data *data =
-               (struct eth_classify_rules_ramrod_data *)(raw->rdata);
-       int rule_cnt = rule_idx + 1;
-       union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx];
-       enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd;
-       bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false;
-       u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
-       u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
-
-       /* Reset the ramrod data buffer for the first rule */
-       if (rule_idx == 0)
-               memset(data, 0, sizeof(*data));
-
-       /* Set a rule header */
-       bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR,
-                                     &rule_entry->pair.header);
-
-       /* Set VLAN and MAC themselves */
-       rule_entry->pair.vlan = cpu_to_le16(vlan);
-       bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
-                             &rule_entry->pair.mac_mid,
-                             &rule_entry->pair.mac_lsb, mac);
-       rule_entry->pair.inner_mac =
-               cpu_to_le16(elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac);
-       /* MOVE: Add a rule that will add this MAC to the target Queue */
-       if (cmd == BNX2X_VLAN_MAC_MOVE) {
-               rule_entry++;
-               rule_cnt++;
-
-               /* Setup ramrod data */
-               bnx2x_vlan_mac_set_cmd_hdr_e2(bp,
-                                       elem->cmd_data.vlan_mac.target_obj,
-                                             true, CLASSIFY_RULE_OPCODE_PAIR,
-                                             &rule_entry->pair.header);
-
-               /* Set a VLAN itself */
-               rule_entry->pair.vlan = cpu_to_le16(vlan);
-               bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
-                                     &rule_entry->pair.mac_mid,
-                                     &rule_entry->pair.mac_lsb, mac);
-               rule_entry->pair.inner_mac =
-                       cpu_to_le16(elem->cmd_data.vlan_mac.u.
-                                               vlan_mac.is_inner_mac);
-       }
-
-       /* Set the ramrod data header */
-       /* TODO: take this to the higher level in order to prevent multiple
-                writing */
-       bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header,
-                                       rule_cnt);
-}
-
-/**
- * bnx2x_set_one_vlan_mac_e1h -
- *
- * @bp:                device handle
- * @o:         bnx2x_vlan_mac_obj
- * @elem:      bnx2x_exeq_elem
- * @rule_idx:  rule_idx
- * @cam_offset:        cam_offset
- */
-static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp,
-                                      struct bnx2x_vlan_mac_obj *o,
-                                      struct bnx2x_exeq_elem *elem,
-                                      int rule_idx, int cam_offset)
-{
-       struct bnx2x_raw_obj *raw = &o->raw;
-       struct mac_configuration_cmd *config =
-               (struct mac_configuration_cmd *)(raw->rdata);
-       /* 57710 and 57711 do not support MOVE command,
-        * so it's either ADD or DEL
-        */
-       bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
-               true : false;
-
-       /* Reset the ramrod data buffer */
-       memset(config, 0, sizeof(*config));
-
-       bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING,
-                                    cam_offset, add,
-                                    elem->cmd_data.vlan_mac.u.vlan_mac.mac,
-                                    elem->cmd_data.vlan_mac.u.vlan_mac.vlan,
-                                    ETH_VLAN_FILTER_CLASSIFY, config);
-}
-
 /**
  * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element
  *
@@ -1314,24 +1135,6 @@ static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan(
        return NULL;
 }
 
-static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac(
-       struct bnx2x_exe_queue_obj *o,
-       struct bnx2x_exeq_elem *elem)
-{
-       struct bnx2x_exeq_elem *pos;
-       struct bnx2x_vlan_mac_ramrod_data *data =
-               &elem->cmd_data.vlan_mac.u.vlan_mac;
-
-       /* Check pending for execution commands */
-       list_for_each_entry(pos, &o->exe_queue, link)
-               if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data,
-                             sizeof(*data)) &&
-                   (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd))
-                       return pos;
-
-       return NULL;
-}
-
 /**
  * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed
  *
@@ -2239,69 +2042,6 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp,
        }
 }
 
-void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
-                            struct bnx2x_vlan_mac_obj *vlan_mac_obj,
-                            u8 cl_id, u32 cid, u8 func_id, void *rdata,
-                            dma_addr_t rdata_mapping, int state,
-                            unsigned long *pstate, bnx2x_obj_type type,
-                            struct bnx2x_credit_pool_obj *macs_pool,
-                            struct bnx2x_credit_pool_obj *vlans_pool)
-{
-       union bnx2x_qable_obj *qable_obj =
-               (union bnx2x_qable_obj *)vlan_mac_obj;
-
-       bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata,
-                                  rdata_mapping, state, pstate, type,
-                                  macs_pool, vlans_pool);
-
-       /* CAM pool handling */
-       vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac;
-       vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac;
-       /* CAM offset is relevant for 57710 and 57711 chips only which have a
-        * single CAM for both MACs and VLAN-MAC pairs. So the offset
-        * will be taken from MACs' pool object only.
-        */
-       vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac;
-       vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac;
-
-       if (CHIP_IS_E1(bp)) {
-               BNX2X_ERR("Do not support chips others than E2\n");
-               BUG();
-       } else if (CHIP_IS_E1H(bp)) {
-               vlan_mac_obj->set_one_rule      = bnx2x_set_one_vlan_mac_e1h;
-               vlan_mac_obj->check_del         = bnx2x_check_vlan_mac_del;
-               vlan_mac_obj->check_add         = bnx2x_check_vlan_mac_add;
-               vlan_mac_obj->check_move        = bnx2x_check_move_always_err;
-               vlan_mac_obj->ramrod_cmd        = RAMROD_CMD_ID_ETH_SET_MAC;
-
-               /* Exe Queue */
-               bnx2x_exe_queue_init(bp,
-                                    &vlan_mac_obj->exe_queue, 1, qable_obj,
-                                    bnx2x_validate_vlan_mac,
-                                    bnx2x_remove_vlan_mac,
-                                    bnx2x_optimize_vlan_mac,
-                                    bnx2x_execute_vlan_mac,
-                                    bnx2x_exeq_get_vlan_mac);
-       } else {
-               vlan_mac_obj->set_one_rule      = bnx2x_set_one_vlan_mac_e2;
-               vlan_mac_obj->check_del         = bnx2x_check_vlan_mac_del;
-               vlan_mac_obj->check_add         = bnx2x_check_vlan_mac_add;
-               vlan_mac_obj->check_move        = bnx2x_check_move;
-               vlan_mac_obj->ramrod_cmd        =
-                       RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES;
-
-               /* Exe Queue */
-               bnx2x_exe_queue_init(bp,
-                                    &vlan_mac_obj->exe_queue,
-                                    CLASSIFY_RULES_COUNT,
-                                    qable_obj, bnx2x_validate_vlan_mac,
-                                    bnx2x_remove_vlan_mac,
-                                    bnx2x_optimize_vlan_mac,
-                                    bnx2x_execute_vlan_mac,
-                                    bnx2x_exeq_get_vlan_mac);
-       }
-}
-
 /* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */
 static inline void __storm_memset_mac_filters(struct bnx2x *bp,
                        struct tstorm_eth_mac_filter_config *mac_filters,
@@ -4988,6 +4728,13 @@ static void bnx2x_q_fill_update_data(struct bnx2x *bp,
                test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, &params->update_flags);
        data->silent_vlan_value = cpu_to_le16(params->silent_removal_value);
        data->silent_vlan_mask = cpu_to_le16(params->silent_removal_mask);
+
+       /* tx switching */
+       data->tx_switching_flg =
+               test_bit(BNX2X_Q_UPDATE_TX_SWITCHING, &params->update_flags);
+       data->tx_switching_change_flg =
+               test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
+                        &params->update_flags);
 }
 
 static inline int bnx2x_q_send_update(struct bnx2x *bp,
index 6a53c15..00d7f21 100644 (file)
@@ -448,9 +448,6 @@ enum {
        BNX2X_LLH_CAM_MAX_PF_LINE = NIG_REG_LLH1_FUNC_MEM_SIZE / 2
 };
 
-void bnx2x_set_mac_in_nig(struct bnx2x *bp,
-                         bool add, unsigned char *dev_addr, int index);
-
 /** RX_MODE verbs:DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */
 
 /* RX_MODE ramrod special flags: set in rx_mode_flags field in
@@ -770,7 +767,9 @@ enum {
        BNX2X_Q_UPDATE_DEF_VLAN_EN,
        BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG,
        BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG,
-       BNX2X_Q_UPDATE_SILENT_VLAN_REM
+       BNX2X_Q_UPDATE_SILENT_VLAN_REM,
+       BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
+       BNX2X_Q_UPDATE_TX_SWITCHING
 };
 
 /* Allowed Queue states */
@@ -1307,22 +1306,12 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp,
                         unsigned long *pstate, bnx2x_obj_type type,
                         struct bnx2x_credit_pool_obj *vlans_pool);
 
-void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
-                            struct bnx2x_vlan_mac_obj *vlan_mac_obj,
-                            u8 cl_id, u32 cid, u8 func_id, void *rdata,
-                            dma_addr_t rdata_mapping, int state,
-                            unsigned long *pstate, bnx2x_obj_type type,
-                            struct bnx2x_credit_pool_obj *macs_pool,
-                            struct bnx2x_credit_pool_obj *vlans_pool);
-
 int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp,
                                        struct bnx2x_vlan_mac_obj *o);
 void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp,
                                  struct bnx2x_vlan_mac_obj *o);
 int bnx2x_vlan_mac_h_write_lock(struct bnx2x *bp,
                                struct bnx2x_vlan_mac_obj *o);
-void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp,
-                                         struct bnx2x_vlan_mac_obj *o);
 int bnx2x_config_vlan_mac(struct bnx2x *bp,
                           struct bnx2x_vlan_mac_ramrod_params *p);
 
index 31ab924..d0e246b 100644 (file)
@@ -799,10 +799,10 @@ int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
        return -ENOMEM;
 }
 
-int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
-                           struct bnx2x_virtf *vf,
-                           struct bnx2x_vfop_cmd *cmd,
-                           int qid, u16 vid, bool add)
+static int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
+                                  struct bnx2x_virtf *vf,
+                                  struct bnx2x_vfop_cmd *cmd,
+                                  int qid, u16 vid, bool add)
 {
        struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
        int rc;
@@ -3130,6 +3130,60 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
           vf->abs_vfid, vf->op_current);
 }
 
+static int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable)
+{
+       struct bnx2x_queue_state_params q_params;
+       u32 prev_flags;
+       int i, rc;
+
+       /* Verify changes are needed and record current Tx switching state */
+       prev_flags = bp->flags;
+       if (enable)
+               bp->flags |= TX_SWITCHING;
+       else
+               bp->flags &= ~TX_SWITCHING;
+       if (prev_flags == bp->flags)
+               return 0;
+
+       /* Verify state enables the sending of queue ramrods */
+       if ((bp->state != BNX2X_STATE_OPEN) ||
+           (bnx2x_get_q_logical_state(bp,
+                                     &bnx2x_sp_obj(bp, &bp->fp[0]).q_obj) !=
+            BNX2X_Q_LOGICAL_STATE_ACTIVE))
+               return 0;
+
+       /* send q. update ramrod to configure Tx switching */
+       memset(&q_params, 0, sizeof(q_params));
+       __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
+       q_params.cmd = BNX2X_Q_CMD_UPDATE;
+       __set_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG,
+                 &q_params.params.update.update_flags);
+       if (enable)
+               __set_bit(BNX2X_Q_UPDATE_TX_SWITCHING,
+                         &q_params.params.update.update_flags);
+       else
+               __clear_bit(BNX2X_Q_UPDATE_TX_SWITCHING,
+                           &q_params.params.update.update_flags);
+
+       /* send the ramrod on all the queues of the PF */
+       for_each_eth_queue(bp, i) {
+               struct bnx2x_fastpath *fp = &bp->fp[i];
+
+               /* Set the appropriate Queue object */
+               q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj;
+
+               /* Update the Queue state */
+               rc = bnx2x_queue_state_change(bp, &q_params);
+               if (rc) {
+                       BNX2X_ERR("Failed to configure Tx switching\n");
+                       return rc;
+               }
+       }
+
+       DP(BNX2X_MSG_IOV, "%s Tx Switching\n", enable ? "Enabled" : "Disabled");
+       return 0;
+}
+
 int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
 {
        struct bnx2x *bp = netdev_priv(pci_get_drvdata(dev));
@@ -3157,12 +3211,14 @@ int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
 
        bp->requested_nr_virtfn = num_vfs_param;
        if (num_vfs_param == 0) {
+               bnx2x_set_pf_tx_switching(bp, false);
                pci_disable_sriov(dev);
                return 0;
        } else {
                return bnx2x_enable_sriov(bp);
        }
 }
+
 #define IGU_ENTRY_SIZE 4
 
 int bnx2x_enable_sriov(struct bnx2x *bp)
@@ -3240,6 +3296,11 @@ int bnx2x_enable_sriov(struct bnx2x *bp)
         */
        DP(BNX2X_MSG_IOV, "about to call enable sriov\n");
        bnx2x_disable_sriov(bp);
+
+       rc = bnx2x_set_pf_tx_switching(bp, true);
+       if (rc)
+               return rc;
+
        rc = pci_enable_sriov(bp->pdev, req_vfs);
        if (rc) {
                BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
index d72ab7e..d9fcca1 100644 (file)
@@ -665,11 +665,6 @@ int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
                            struct bnx2x_vfop_filters *macs,
                            int qid, bool drv_only);
 
-int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
-                           struct bnx2x_virtf *vf,
-                           struct bnx2x_vfop_cmd *cmd,
-                           int qid, u16 vid, bool add);
-
 int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
                             struct bnx2x_virtf *vf,
                             struct bnx2x_vfop_cmd *cmd,
@@ -727,13 +722,6 @@ void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid);
 /* Handles an FLR (or VF_DISABLE) notification form the MCP */
 void bnx2x_vf_handle_flr_event(struct bnx2x *bp);
 
-void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
-                  u16 length);
-void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
-                    u16 type, u16 length);
-void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv);
-void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list);
-
 bool bnx2x_tlv_supported(u16 tlvtype);
 
 u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
@@ -750,7 +738,6 @@ int bnx2x_vfpf_init(struct bnx2x *bp);
 void bnx2x_vfpf_close_vf(struct bnx2x *bp);
 int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                       bool is_leading);
-int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
 int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set);
 int bnx2x_vfpf_config_rss(struct bnx2x *bp,
                          struct bnx2x_config_rss_params *params);
@@ -814,7 +801,6 @@ static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
 static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
 static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
 static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp, bool is_leading) {return 0; }
-static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
 static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr,
                                        u8 vf_qid, bool set) {return 0; }
 static inline int bnx2x_vfpf_config_rss(struct bnx2x *bp,
index 1b1ad31..3fa6c2a 100644 (file)
 #include "bnx2x_cmn.h"
 #include <linux/crc32.h>
 
+static int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
+
 /* place a given tlv on the tlv buffer at a given offset */
-void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
-                  u16 length)
+static void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list,
+                         u16 offset, u16 type, u16 length)
 {
        struct channel_tlv *tl =
                (struct channel_tlv *)(tlvs_list + offset);
@@ -33,8 +35,8 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type,
 }
 
 /* Clear the mailbox and init the header of the first tlv */
-void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
-                    u16 type, u16 length)
+static void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
+                           u16 type, u16 length)
 {
        mutex_lock(&bp->vf2pf_mutex);
 
@@ -52,7 +54,8 @@ void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv,
 }
 
 /* releases the mailbox */
-void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv)
+static void bnx2x_vfpf_finalize(struct bnx2x *bp,
+                               struct vfpf_first_tlv *first_tlv)
 {
        DP(BNX2X_MSG_IOV, "done sending [%d] tlv over vf pf channel\n",
           first_tlv->tl.type);
@@ -85,7 +88,7 @@ static void *bnx2x_search_tlv_list(struct bnx2x *bp, void *tlvs_list,
 }
 
 /* list the types and lengths of the tlvs on the buffer */
-void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
+static void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list)
 {
        int i = 1;
        struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list;
@@ -633,7 +636,7 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        return rc;
 }
 
-int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
+static int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
 {
        struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op;
        struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
index cb05be9..81e8402 100644 (file)
@@ -423,7 +423,7 @@ u64 cxgb4_select_ntuple(struct net_device *dev,
         * in the Compressed Filter Tuple.
         */
        if (tp->vlan_shift >= 0 && l2t->vlan != VLAN_NONE)
-               ntuple |= (F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift;
+               ntuple |= (u64)(F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift;
 
        if (tp->port_shift >= 0)
                ntuple |= (u64)l2t->lport << tp->port_shift;
index 4ccaf9a..8d09615 100644 (file)
@@ -34,7 +34,7 @@
 #include "be_hw.h"
 #include "be_roce.h"
 
-#define DRV_VER                        "4.9.224.0u"
+#define DRV_VER                        "10.0.600.0u"
 #define DRV_NAME               "be2net"
 #define BE_NAME                        "Emulex BladeEngine2"
 #define BE3_NAME               "Emulex BladeEngine3"
@@ -42,7 +42,7 @@
 #define OC_NAME_BE             OC_NAME "(be3)"
 #define OC_NAME_LANCER         OC_NAME "(Lancer)"
 #define OC_NAME_SH             OC_NAME "(Skyhawk)"
-#define DRV_DESC               "Emulex OneConnect 10Gbps NIC Driver"
+#define DRV_DESC               "Emulex OneConnect NIC Driver"
 
 #define BE_VENDOR_ID           0x19a2
 #define EMULEX_VENDOR_ID       0x10df
@@ -283,7 +283,6 @@ struct be_rx_compl_info {
        u32 rss_hash;
        u16 vlan_tag;
        u16 pkt_size;
-       u16 rxq_idx;
        u16 port;
        u8 vlanf;
        u8 num_rcvd;
@@ -493,7 +492,7 @@ struct be_adapter {
        u16 pvid;
        struct phy_info phy;
        u8 wol_cap;
-       bool wol;
+       bool wol_en;
        u32 uc_macs;            /* Count of secondary UC MAC programmed */
        u16 asic_rev;
        u16 qnq_vid;
index 94c35c8..48076a6 100644 (file)
@@ -1101,23 +1101,22 @@ static int be_cmd_mccq_ext_create(struct be_adapter *adapter,
                        OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req), wrb, NULL);
 
        req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
-       if (lancer_chip(adapter)) {
-               req->hdr.version = 1;
-               req->cq_id = cpu_to_le16(cq->id);
-
-               AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt,
-                                               be_encoded_q_len(mccq->len));
-               AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1);
-               AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id,
-                                                               ctxt, cq->id);
-               AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid,
-                                                                ctxt, 1);
-
-       } else {
+       if (BEx_chip(adapter)) {
                AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
                AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
                                                be_encoded_q_len(mccq->len));
                AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);
+       } else {
+               req->hdr.version = 1;
+               req->cq_id = cpu_to_le16(cq->id);
+
+               AMAP_SET_BITS(struct amap_mcc_context_v1, ring_size, ctxt,
+                             be_encoded_q_len(mccq->len));
+               AMAP_SET_BITS(struct amap_mcc_context_v1, valid, ctxt, 1);
+               AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_id,
+                             ctxt, cq->id);
+               AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_valid,
+                             ctxt, 1);
        }
 
        /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
@@ -1187,7 +1186,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
        int status;
 
        status = be_cmd_mccq_ext_create(adapter, mccq, cq);
-       if (status && !lancer_chip(adapter)) {
+       if (status && BEx_chip(adapter)) {
                dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 "
                        "or newer to avoid conflicting priorities between NIC "
                        "and FCoE traffic");
@@ -2692,6 +2691,13 @@ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
                struct be_cmd_resp_get_fn_privileges *resp =
                                                embedded_payload(wrb);
                *privilege = le32_to_cpu(resp->privilege_mask);
+
+               /* In UMC mode FW does not return right privileges.
+                * Override with correct privilege equivalent to PF.
+                */
+               if (BEx_chip(adapter) && be_is_mc(adapter) &&
+                   be_physfn(adapter))
+                       *privilege = MAX_PRIVILEGES;
        }
 
 err:
@@ -2736,7 +2742,8 @@ err:
  *               If pmac_id is returned, pmac_id_valid is returned as true
  */
 int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
-                            bool *pmac_id_valid, u32 *pmac_id, u8 domain)
+                            bool *pmac_id_valid, u32 *pmac_id, u32 if_handle,
+                            u8 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_get_mac_list *req;
@@ -2774,7 +2781,7 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
        req->mac_type = MAC_ADDRESS_TYPE_NETWORK;
        if (*pmac_id_valid) {
                req->mac_id = cpu_to_le32(*pmac_id);
-               req->iface_id = cpu_to_le16(adapter->if_handle);
+               req->iface_id = cpu_to_le16(if_handle);
                req->perm_override = 0;
        } else {
                req->perm_override = 1;
@@ -2827,17 +2834,21 @@ out:
        return status;
 }
 
-int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac)
+int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac,
+                         u32 if_handle, bool active, u32 domain)
 {
-       bool active = true;
 
+       if (!active)
+               be_cmd_get_mac_from_list(adapter, mac, &active, &curr_pmac_id,
+                                        if_handle, domain);
        if (BEx_chip(adapter))
                return be_cmd_mac_addr_query(adapter, mac, false,
-                                            adapter->if_handle, curr_pmac_id);
+                                            if_handle, curr_pmac_id);
        else
                /* Fetch the MAC address using pmac_id */
                return be_cmd_get_mac_from_list(adapter, mac, &active,
-                                               &curr_pmac_id, 0);
+                                               &curr_pmac_id,
+                                               if_handle, domain);
 }
 
 int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac)
@@ -2856,7 +2867,7 @@ int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac)
                                                       adapter->if_handle, 0);
        } else {
                status = be_cmd_get_mac_from_list(adapter, mac, &pmac_valid,
-                                                 NULL, 0);
+                                                 NULL, adapter->if_handle, 0);
        }
 
        return status;
@@ -2917,7 +2928,8 @@ int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom)
        int status;
 
        status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac,
-                                         &pmac_id, dom);
+                                         &pmac_id, if_id, dom);
+
        if (!status && active_mac)
                be_cmd_pmac_del(adapter, if_id, pmac_id, dom);
 
@@ -2997,7 +3009,7 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid,
                      ctxt, intf_id);
        AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1);
 
-       if (!BEx_chip(adapter)) {
+       if (!BEx_chip(adapter) && mode) {
                AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id,
                              ctxt, adapter->hba_port_num);
                AMAP_SET_BITS(struct amap_get_hsw_req_context, pport, ctxt, 1);
@@ -3028,14 +3040,16 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_acpi_wol_magic_config_v1 *req;
-       int status;
-       int payload_len = sizeof(*req);
+       int status = 0;
        struct be_dma_mem cmd;
 
        if (!be_cmd_allowed(adapter, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG,
                            CMD_SUBSYSTEM_ETH))
                return -EPERM;
 
+       if (be_is_wol_excluded(adapter))
+               return status;
+
        if (mutex_lock_interruptible(&adapter->mbox_lock))
                return -1;
 
@@ -3060,7 +3074,7 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
 
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
                               OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG,
-                              payload_len, wrb, &cmd);
+                              sizeof(*req), wrb, &cmd);
 
        req->hdr.version = 1;
        req->query_options = BE_GET_WOL_CAP;
@@ -3070,13 +3084,9 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
                struct be_cmd_resp_acpi_wol_magic_config_v1 *resp;
                resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *) cmd.va;
 
-               /* the command could succeed misleadingly on old f/w
-                * which is not aware of the V1 version. fake an error. */
-               if (resp->hdr.response_length < payload_len) {
-                       status = -1;
-                       goto err;
-               }
                adapter->wol_cap = resp->wol_settings;
+               if (adapter->wol_cap & BE_WOL_CAP)
+                       adapter->wol_en = true;
        }
 err:
        mutex_unlock(&adapter->mbox_lock);
@@ -3085,6 +3095,76 @@ err:
        return status;
 
 }
+
+int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level)
+{
+       struct be_dma_mem extfat_cmd;
+       struct be_fat_conf_params *cfgs;
+       int status;
+       int i, j;
+
+       memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
+       extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
+       extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
+                                            &extfat_cmd.dma);
+       if (!extfat_cmd.va)
+               return -ENOMEM;
+
+       status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd);
+       if (status)
+               goto err;
+
+       cfgs = (struct be_fat_conf_params *)
+                       (extfat_cmd.va + sizeof(struct be_cmd_resp_hdr));
+       for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) {
+               u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes);
+               for (j = 0; j < num_modes; j++) {
+                       if (cfgs->module[i].trace_lvl[j].mode == MODE_UART)
+                               cfgs->module[i].trace_lvl[j].dbg_lvl =
+                                                       cpu_to_le32(level);
+               }
+       }
+
+       status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, cfgs);
+err:
+       pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
+                           extfat_cmd.dma);
+       return status;
+}
+
+int be_cmd_get_fw_log_level(struct be_adapter *adapter)
+{
+       struct be_dma_mem extfat_cmd;
+       struct be_fat_conf_params *cfgs;
+       int status, j;
+       int level = 0;
+
+       memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
+       extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
+       extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
+                                            &extfat_cmd.dma);
+
+       if (!extfat_cmd.va) {
+               dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n",
+                       __func__);
+               goto err;
+       }
+
+       status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd);
+       if (!status) {
+               cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
+                                               sizeof(struct be_cmd_resp_hdr));
+               for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) {
+                       if (cfgs->module[0].trace_lvl[j].mode == MODE_UART)
+                               level = cfgs->module[0].trace_lvl[j].dbg_lvl;
+               }
+       }
+       pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
+                           extfat_cmd.dma);
+err:
+       return level;
+}
+
 int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter,
                                   struct be_dma_mem *cmd)
 {
@@ -3609,6 +3689,40 @@ int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable)
        return status;
 }
 
+/* Uses MBOX */
+int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile_id)
+{
+       struct be_cmd_req_get_active_profile *req;
+       struct be_mcc_wrb *wrb;
+       int status;
+
+       if (mutex_lock_interruptible(&adapter->mbox_lock))
+               return -1;
+
+       wrb = wrb_from_mbox(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                              OPCODE_COMMON_GET_ACTIVE_PROFILE, sizeof(*req),
+                              wrb, NULL);
+
+       status = be_mbox_notify_wait(adapter);
+       if (!status) {
+               struct be_cmd_resp_get_active_profile *resp =
+                                                       embedded_payload(wrb);
+               *profile_id = le16_to_cpu(resp->active_profile_id);
+       }
+
+err:
+       mutex_unlock(&adapter->mbox_lock);
+       return status;
+}
+
 int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
                        int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
 {
index 0075686..fc4e076 100644 (file)
@@ -216,6 +216,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_FUNC_CONFIG                  160
 #define OPCODE_COMMON_GET_PROFILE_CONFIG               164
 #define OPCODE_COMMON_SET_PROFILE_CONFIG               165
+#define OPCODE_COMMON_GET_ACTIVE_PROFILE               167
 #define OPCODE_COMMON_SET_HSW_CONFIG                   153
 #define OPCODE_COMMON_GET_FN_PRIVILEGES                        170
 #define OPCODE_COMMON_READ_OBJECT                      171
@@ -452,7 +453,7 @@ struct amap_mcc_context_be {
        u8 rsvd2[32];
 } __packed;
 
-struct amap_mcc_context_lancer {
+struct amap_mcc_context_v1 {
        u8 async_cq_id[16];
        u8 ring_size[4];
        u8 rsvd0[12];
@@ -476,7 +477,7 @@ struct be_cmd_req_mcc_ext_create {
        u16 num_pages;
        u16 cq_id;
        u32 async_event_bitmap[1];
-       u8 context[sizeof(struct amap_mcc_context_be) / 8];
+       u8 context[sizeof(struct amap_mcc_context_v1) / 8];
        struct phys_addr pages[8];
 } __packed;
 
@@ -1097,6 +1098,14 @@ struct be_cmd_resp_query_fw_cfg {
        u32 function_caps;
 };
 
+/* Is BE in a multi-channel mode */
+static inline bool be_is_mc(struct be_adapter *adapter)
+{
+       return adapter->function_mode & FLEX10_MODE ||
+               adapter->function_mode & VNIC_MODE ||
+               adapter->function_mode & UMC_ENABLED;
+}
+
 /******************** RSS Config ****************************************/
 /* RSS type            Input parameters used to compute RX hash
  * RSS_ENABLE_IPV4     SRC IPv4, DST IPv4
@@ -1917,6 +1926,17 @@ struct be_cmd_resp_set_profile_config {
        struct be_cmd_resp_hdr hdr;
 };
 
+struct be_cmd_req_get_active_profile {
+       struct be_cmd_req_hdr hdr;
+       u32 rsvd;
+} __packed;
+
+struct be_cmd_resp_get_active_profile {
+       struct be_cmd_resp_hdr hdr;
+       u16 active_profile_id;
+       u16 next_profile_id;
+} __packed;
+
 struct be_cmd_enable_disable_vf {
        struct be_cmd_req_hdr hdr;
        u8 enable;
@@ -2037,8 +2057,10 @@ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege,
 int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges,
                             u32 vf_num);
 int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac,
-                            bool *pmac_id_active, u32 *pmac_id, u8 domain);
-int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id, u8 *mac);
+                            bool *pmac_id_active, u32 *pmac_id,
+                            u32 if_handle, u8 domain);
+int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id, u8 *mac,
+                         u32 if_handle, bool active, u32 domain);
 int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac);
 int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, u8 mac_count,
                        u32 domain);
@@ -2048,6 +2070,8 @@ int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, u32 domain,
 int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, u32 domain,
                          u16 intf_id, u8 *mode);
 int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter);
+int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level);
+int be_cmd_get_fw_log_level(struct be_adapter *adapter);
 int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter,
                                   struct be_dma_mem *cmd);
 int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter,
@@ -2063,6 +2087,7 @@ int be_cmd_get_func_config(struct be_adapter *adapter,
 int be_cmd_get_profile_config(struct be_adapter *adapter,
                              struct be_resources *res, u8 domain);
 int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps, u8 domain);
+int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile);
 int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
                     int vf_num);
 int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
index 0833003..05be007 100644 (file)
@@ -713,12 +713,13 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
-       if (be_is_wol_supported(adapter)) {
+       if (adapter->wol_cap & BE_WOL_CAP) {
                wol->supported |= WAKE_MAGIC;
-               if (adapter->wol)
+               if (adapter->wol_en)
                        wol->wolopts |= WAKE_MAGIC;
-       } else
+       } else {
                wol->wolopts = 0;
+       }
        memset(&wol->sopass, 0, sizeof(wol->sopass));
 }
 
@@ -730,15 +731,15 @@ be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EOPNOTSUPP;
 
-       if (!be_is_wol_supported(adapter)) {
+       if (!(adapter->wol_cap & BE_WOL_CAP)) {
                dev_warn(&adapter->pdev->dev, "WOL not supported\n");
                return -EOPNOTSUPP;
        }
 
        if (wol->wolopts & WAKE_MAGIC)
-               adapter->wol = true;
+               adapter->wol_en = true;
        else
-               adapter->wol = false;
+               adapter->wol_en = false;
 
        return 0;
 }
@@ -904,73 +905,21 @@ static u32 be_get_msg_level(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
-       if (lancer_chip(adapter)) {
-               dev_err(&adapter->pdev->dev, "Operation not supported\n");
-               return -EOPNOTSUPP;
-       }
-
        return adapter->msg_enable;
 }
 
-static void be_set_fw_log_level(struct be_adapter *adapter, u32 level)
-{
-       struct be_dma_mem extfat_cmd;
-       struct be_fat_conf_params *cfgs;
-       int status;
-       int i, j;
-
-       memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
-       extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
-       extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
-                                            &extfat_cmd.dma);
-       if (!extfat_cmd.va) {
-               dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n",
-                       __func__);
-               goto err;
-       }
-       status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd);
-       if (!status) {
-               cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
-                                       sizeof(struct be_cmd_resp_hdr));
-               for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) {
-                       u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes);
-                       for (j = 0; j < num_modes; j++) {
-                               if (cfgs->module[i].trace_lvl[j].mode ==
-                                                               MODE_UART)
-                                       cfgs->module[i].trace_lvl[j].dbg_lvl =
-                                                       cpu_to_le32(level);
-                       }
-               }
-               status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd,
-                                                       cfgs);
-               if (status)
-                       dev_err(&adapter->pdev->dev,
-                               "Message level set failed\n");
-       } else {
-               dev_err(&adapter->pdev->dev, "Message level get failed\n");
-       }
-
-       pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
-                           extfat_cmd.dma);
-err:
-       return;
-}
-
 static void be_set_msg_level(struct net_device *netdev, u32 level)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
-       if (lancer_chip(adapter)) {
-               dev_err(&adapter->pdev->dev, "Operation not supported\n");
-               return;
-       }
-
        if (adapter->msg_enable == level)
                return;
 
        if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW))
-               be_set_fw_log_level(adapter, level & NETIF_MSG_HW ?
-                                   FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL);
+               if (BEx_chip(adapter))
+                       be_cmd_set_fw_log_level(adapter, level & NETIF_MSG_HW ?
+                                               FW_LOG_LEVEL_DEFAULT :
+                                               FW_LOG_LEVEL_FATAL);
        adapter->msg_enable = level;
 
        return;
index 3acf137..6d22d6f 100644 (file)
@@ -121,12 +121,6 @@ static const char * const ue_status_hi_desc[] = {
        "Unknown"
 };
 
-/* Is BE in a multi-channel mode */
-static inline bool be_is_mc(struct be_adapter *adapter) {
-       return (adapter->function_mode & FLEX10_MODE ||
-               adapter->function_mode & VNIC_MODE ||
-               adapter->function_mode & UMC_ENABLED);
-}
 
 static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
 {
@@ -258,6 +252,12 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
+       /* Proceed further only if, User provided MAC is different
+        * from active MAC
+        */
+       if (ether_addr_equal(addr->sa_data, netdev->dev_addr))
+               return 0;
+
        /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT
         * privilege or if PF did not provision the new MAC address.
         * On BE3, this cmd will always fail if the VF doesn't have the
@@ -280,7 +280,8 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        /* Decide if the new MAC is successfully activated only after
         * querying the FW
         */
-       status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac);
+       status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac,
+                                      adapter->if_handle, true, 0);
        if (status)
                goto err;
 
@@ -1442,12 +1443,12 @@ static inline bool csum_passed(struct be_rx_compl_info *rxcp)
                                (rxcp->ip_csum || rxcp->ipv6);
 }
 
-static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo,
-                                               u16 frag_idx)
+static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
 {
        struct be_adapter *adapter = rxo->adapter;
        struct be_rx_page_info *rx_page_info;
        struct be_queue_info *rxq = &rxo->q;
+       u16 frag_idx = rxq->tail;
 
        rx_page_info = &rxo->page_info_tbl[frag_idx];
        BUG_ON(!rx_page_info->page);
@@ -1459,6 +1460,7 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo,
                rx_page_info->last_page_user = false;
        }
 
+       queue_tail_inc(rxq);
        atomic_dec(&rxq->used);
        return rx_page_info;
 }
@@ -1467,15 +1469,13 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo,
 static void be_rx_compl_discard(struct be_rx_obj *rxo,
                                struct be_rx_compl_info *rxcp)
 {
-       struct be_queue_info *rxq = &rxo->q;
        struct be_rx_page_info *page_info;
        u16 i, num_rcvd = rxcp->num_rcvd;
 
        for (i = 0; i < num_rcvd; i++) {
-               page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
+               page_info = get_rx_page_info(rxo);
                put_page(page_info->page);
                memset(page_info, 0, sizeof(*page_info));
-               index_inc(&rxcp->rxq_idx, rxq->len);
        }
 }
 
@@ -1486,13 +1486,12 @@ static void be_rx_compl_discard(struct be_rx_obj *rxo,
 static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb,
                             struct be_rx_compl_info *rxcp)
 {
-       struct be_queue_info *rxq = &rxo->q;
        struct be_rx_page_info *page_info;
        u16 i, j;
        u16 hdr_len, curr_frag_len, remaining;
        u8 *start;
 
-       page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
+       page_info = get_rx_page_info(rxo);
        start = page_address(page_info->page) + page_info->page_offset;
        prefetch(start);
 
@@ -1526,10 +1525,9 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb,
        }
 
        /* More frags present for this completion */
-       index_inc(&rxcp->rxq_idx, rxq->len);
        remaining = rxcp->pkt_size - curr_frag_len;
        for (i = 1, j = 0; i < rxcp->num_rcvd; i++) {
-               page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
+               page_info = get_rx_page_info(rxo);
                curr_frag_len = min(remaining, rx_frag_size);
 
                /* Coalesce all frags from the same physical page in one slot */
@@ -1550,7 +1548,6 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb,
                skb->data_len += curr_frag_len;
                skb->truesize += rx_frag_size;
                remaining -= curr_frag_len;
-               index_inc(&rxcp->rxq_idx, rxq->len);
                page_info->page = NULL;
        }
        BUG_ON(j > MAX_SKB_FRAGS);
@@ -1598,7 +1595,6 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
        struct be_adapter *adapter = rxo->adapter;
        struct be_rx_page_info *page_info;
        struct sk_buff *skb = NULL;
-       struct be_queue_info *rxq = &rxo->q;
        u16 remaining, curr_frag_len;
        u16 i, j;
 
@@ -1610,7 +1606,7 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
 
        remaining = rxcp->pkt_size;
        for (i = 0, j = -1; i < rxcp->num_rcvd; i++) {
-               page_info = get_rx_page_info(rxo, rxcp->rxq_idx);
+               page_info = get_rx_page_info(rxo);
 
                curr_frag_len = min(remaining, rx_frag_size);
 
@@ -1628,7 +1624,6 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
                skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len);
                skb->truesize += rx_frag_size;
                remaining -= curr_frag_len;
-               index_inc(&rxcp->rxq_idx, rxq->len);
                memset(page_info, 0, sizeof(*page_info));
        }
        BUG_ON(j > MAX_SKB_FRAGS);
@@ -1663,8 +1658,6 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl);
        rxcp->ipv6 =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl);
-       rxcp->rxq_idx =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, fragndx, compl);
        rxcp->num_rcvd =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
        rxcp->pkt_type =
@@ -1695,8 +1688,6 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl);
        rxcp->ipv6 =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl);
-       rxcp->rxq_idx =
-               AMAP_GET_BITS(struct amap_eth_rx_compl_v0, fragndx, compl);
        rxcp->num_rcvd =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
        rxcp->pkt_type =
@@ -1914,7 +1905,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
        struct be_rx_compl_info *rxcp;
        struct be_adapter *adapter = rxo->adapter;
        int flush_wait = 0;
-       u16 tail;
 
        /* Consume pending rx completions.
         * Wait for the flush completion (identified by zero num_rcvd)
@@ -1947,9 +1937,8 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
        be_cq_notify(adapter, rx_cq->id, false, 0);
 
        /* Then free posted rx buffers that were not used */
-       tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
-       for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) {
-               page_info = get_rx_page_info(rxo, tail);
+       while (atomic_read(&rxq->used) > 0) {
+               page_info = get_rx_page_info(rxo);
                put_page(page_info->page);
                memset(page_info, 0, sizeof(*page_info));
        }
@@ -2884,14 +2873,11 @@ static int be_vfs_mac_query(struct be_adapter *adapter)
        int status, vf;
        u8 mac[ETH_ALEN];
        struct be_vf_cfg *vf_cfg;
-       bool active = false;
 
        for_all_vfs(adapter, vf_cfg, vf) {
-               be_cmd_get_mac_from_list(adapter, mac, &active,
-                                        &vf_cfg->pmac_id, 0);
-
-               status = be_cmd_mac_addr_query(adapter, mac, false,
-                                              vf_cfg->if_handle, 0);
+               status = be_cmd_get_active_mac(adapter, vf_cfg->pmac_id,
+                                              mac, vf_cfg->if_handle,
+                                              false, vf+1);
                if (status)
                        return status;
                memcpy(vf_cfg->mac_addr, mac, ETH_ALEN);
@@ -3233,6 +3219,7 @@ static int be_get_resources(struct be_adapter *adapter)
 /* Routine to query per function resource limits */
 static int be_get_config(struct be_adapter *adapter)
 {
+       u16 profile_id;
        int status;
 
        status = be_cmd_query_fw_cfg(adapter, &adapter->port_num,
@@ -3242,6 +3229,13 @@ static int be_get_config(struct be_adapter *adapter)
        if (status)
                return status;
 
+        if (be_physfn(adapter)) {
+               status = be_cmd_get_active_profile(adapter, &profile_id);
+               if (!status)
+                       dev_info(&adapter->pdev->dev,
+                                "Using profile 0x%x\n", profile_id);
+       }
+
        status = be_get_resources(adapter);
        if (status)
                return status;
@@ -3396,11 +3390,6 @@ static int be_setup(struct be_adapter *adapter)
                goto err;
 
        be_cmd_get_fn_privileges(adapter, &adapter->cmd_privileges, 0);
-       /* In UMC mode FW does not return right privileges.
-        * Override with correct privilege equivalent to PF.
-        */
-       if (be_is_mc(adapter))
-               adapter->cmd_privileges = MAX_PRIVILEGES;
 
        status = be_mac_setup(adapter);
        if (status)
@@ -3419,6 +3408,8 @@ static int be_setup(struct be_adapter *adapter)
 
        be_set_rx_mode(adapter->netdev);
 
+       be_cmd_get_acpi_wol_cap(adapter);
+
        be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc);
 
        if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc)
@@ -4288,74 +4279,22 @@ static void be_remove(struct pci_dev *pdev)
        free_netdev(adapter->netdev);
 }
 
-bool be_is_wol_supported(struct be_adapter *adapter)
-{
-       return ((adapter->wol_cap & BE_WOL_CAP) &&
-               !be_is_wol_excluded(adapter)) ? true : false;
-}
-
-u32 be_get_fw_log_level(struct be_adapter *adapter)
-{
-       struct be_dma_mem extfat_cmd;
-       struct be_fat_conf_params *cfgs;
-       int status;
-       u32 level = 0;
-       int j;
-
-       if (lancer_chip(adapter))
-               return 0;
-
-       memset(&extfat_cmd, 0, sizeof(struct be_dma_mem));
-       extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps);
-       extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size,
-                                            &extfat_cmd.dma);
-
-       if (!extfat_cmd.va) {
-               dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n",
-                       __func__);
-               goto err;
-       }
-
-       status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd);
-       if (!status) {
-               cfgs = (struct be_fat_conf_params *)(extfat_cmd.va +
-                                               sizeof(struct be_cmd_resp_hdr));
-               for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) {
-                       if (cfgs->module[0].trace_lvl[j].mode == MODE_UART)
-                               level = cfgs->module[0].trace_lvl[j].dbg_lvl;
-               }
-       }
-       pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va,
-                           extfat_cmd.dma);
-err:
-       return level;
-}
-
 static int be_get_initial_config(struct be_adapter *adapter)
 {
-       int status;
-       u32 level;
+       int status, level;
 
        status = be_cmd_get_cntl_attributes(adapter);
        if (status)
                return status;
 
-       status = be_cmd_get_acpi_wol_cap(adapter);
-       if (status) {
-               /* in case of a failure to get wol capabillities
-                * check the exclusion list to determine WOL capability */
-               if (!be_is_wol_excluded(adapter))
-                       adapter->wol_cap |= BE_WOL_CAP;
-       }
-
-       if (be_is_wol_supported(adapter))
-               adapter->wol = true;
-
        /* Must be a power of 2 or else MODULO will BUG_ON */
        adapter->be_get_temp_freq = 64;
 
-       level = be_get_fw_log_level(adapter);
-       adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0;
+       if (BEx_chip(adapter)) {
+               level = be_cmd_get_fw_log_level(adapter);
+               adapter->msg_enable =
+                       level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0;
+       }
 
        adapter->cfg_num_qs = netif_get_num_default_rss_queues();
        return 0;
@@ -4618,7 +4557,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
        struct be_adapter *adapter = pci_get_drvdata(pdev);
        struct net_device *netdev =  adapter->netdev;
 
-       if (adapter->wol)
+       if (adapter->wol_en)
                be_setup_wol(adapter, true);
 
        be_intr_set(adapter, false);
@@ -4674,7 +4613,7 @@ static int be_resume(struct pci_dev *pdev)
                              msecs_to_jiffies(1000));
        netif_device_attach(netdev);
 
-       if (adapter->wol)
+       if (adapter->wol_en)
                be_setup_wol(adapter, false);
 
        return 0;
index d3d7ede..5900dba 100644 (file)
@@ -889,11 +889,9 @@ static int gfar_set_hash_opts(struct gfar_private *priv,
 
 static int gfar_check_filer_hardware(struct gfar_private *priv)
 {
-       struct gfar __iomem *regs = NULL;
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 i;
 
-       regs = priv->gfargrp[0].regs;
-
        /* Check if we are in FIFO mode */
        i = gfar_read(&regs->ecntrl);
        i &= ECNTRL_FIFM;
@@ -927,7 +925,7 @@ static int gfar_check_filer_hardware(struct gfar_private *priv)
        /* Sets the properties for arbitrary filer rule
         * to the first 4 Layer 4 Bytes
         */
-       regs->rbifx = 0xC0C1C2C3;
+       gfar_write(&regs->rbifx, 0xC0C1C2C3);
        return 0;
 }
 
@@ -1055,10 +1053,18 @@ static void gfar_set_basic_ip(struct ethtool_tcpip4_spec *value,
                              struct ethtool_tcpip4_spec *mask,
                              struct filer_table *tab)
 {
-       gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab);
-       gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab);
-       gfar_set_attribute(value->pdst, mask->pdst, RQFCR_PID_DPT, tab);
-       gfar_set_attribute(value->psrc, mask->psrc, RQFCR_PID_SPT, tab);
+       gfar_set_attribute(be32_to_cpu(value->ip4src),
+                          be32_to_cpu(mask->ip4src),
+                          RQFCR_PID_SIA, tab);
+       gfar_set_attribute(be32_to_cpu(value->ip4dst),
+                          be32_to_cpu(mask->ip4dst),
+                          RQFCR_PID_DIA, tab);
+       gfar_set_attribute(be16_to_cpu(value->pdst),
+                          be16_to_cpu(mask->pdst),
+                          RQFCR_PID_DPT, tab);
+       gfar_set_attribute(be16_to_cpu(value->psrc),
+                          be16_to_cpu(mask->psrc),
+                          RQFCR_PID_SPT, tab);
        gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab);
 }
 
@@ -1067,12 +1073,17 @@ static void gfar_set_user_ip(struct ethtool_usrip4_spec *value,
                             struct ethtool_usrip4_spec *mask,
                             struct filer_table *tab)
 {
-       gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab);
-       gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab);
+       gfar_set_attribute(be32_to_cpu(value->ip4src),
+                          be32_to_cpu(mask->ip4src),
+                          RQFCR_PID_SIA, tab);
+       gfar_set_attribute(be32_to_cpu(value->ip4dst),
+                          be32_to_cpu(mask->ip4dst),
+                          RQFCR_PID_DIA, tab);
        gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab);
        gfar_set_attribute(value->proto, mask->proto, RQFCR_PID_L4P, tab);
-       gfar_set_attribute(value->l4_4_bytes, mask->l4_4_bytes, RQFCR_PID_ARB,
-                          tab);
+       gfar_set_attribute(be32_to_cpu(value->l4_4_bytes),
+                          be32_to_cpu(mask->l4_4_bytes),
+                          RQFCR_PID_ARB, tab);
 
 }
 
@@ -1139,7 +1150,41 @@ static void gfar_set_ether(struct ethhdr *value, struct ethhdr *mask,
                }
        }
 
-       gfar_set_attribute(value->h_proto, mask->h_proto, RQFCR_PID_ETY, tab);
+       gfar_set_attribute(be16_to_cpu(value->h_proto),
+                          be16_to_cpu(mask->h_proto),
+                          RQFCR_PID_ETY, tab);
+}
+
+static inline u32 vlan_tci_vid(struct ethtool_rx_flow_spec *rule)
+{
+       return be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_VID_MASK;
+}
+
+static inline u32 vlan_tci_vidm(struct ethtool_rx_flow_spec *rule)
+{
+       return be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_VID_MASK;
+}
+
+static inline u32 vlan_tci_cfi(struct ethtool_rx_flow_spec *rule)
+{
+       return be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_CFI_MASK;
+}
+
+static inline u32 vlan_tci_cfim(struct ethtool_rx_flow_spec *rule)
+{
+       return be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_CFI_MASK;
+}
+
+static inline u32 vlan_tci_prio(struct ethtool_rx_flow_spec *rule)
+{
+       return (be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_PRIO_MASK) >>
+               VLAN_PRIO_SHIFT;
+}
+
+static inline u32 vlan_tci_priom(struct ethtool_rx_flow_spec *rule)
+{
+       return (be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_PRIO_MASK) >>
+               VLAN_PRIO_SHIFT;
 }
 
 /* Convert a rule to binary filter format of gianfar */
@@ -1153,22 +1198,21 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule,
        u32 old_index = tab->index;
 
        /* Check if vlan is wanted */
-       if ((rule->flow_type & FLOW_EXT) && (rule->m_ext.vlan_tci != 0xFFFF)) {
+       if ((rule->flow_type & FLOW_EXT) &&
+           (rule->m_ext.vlan_tci != cpu_to_be16(0xFFFF))) {
                if (!rule->m_ext.vlan_tci)
-                       rule->m_ext.vlan_tci = 0xFFFF;
+                       rule->m_ext.vlan_tci = cpu_to_be16(0xFFFF);
 
                vlan = RQFPR_VLN;
                vlan_mask = RQFPR_VLN;
 
                /* Separate the fields */
-               id = rule->h_ext.vlan_tci & VLAN_VID_MASK;
-               id_mask = rule->m_ext.vlan_tci & VLAN_VID_MASK;
-               cfi = rule->h_ext.vlan_tci & VLAN_CFI_MASK;
-               cfi_mask = rule->m_ext.vlan_tci & VLAN_CFI_MASK;
-               prio = (rule->h_ext.vlan_tci & VLAN_PRIO_MASK) >>
-                      VLAN_PRIO_SHIFT;
-               prio_mask = (rule->m_ext.vlan_tci & VLAN_PRIO_MASK) >>
-                           VLAN_PRIO_SHIFT;
+               id = vlan_tci_vid(rule);
+               id_mask = vlan_tci_vidm(rule);
+               cfi = vlan_tci_cfi(rule);
+               cfi_mask = vlan_tci_cfim(rule);
+               prio = vlan_tci_prio(rule);
+               prio_mask = vlan_tci_priom(rule);
 
                if (cfi == VLAN_TAG_PRESENT && cfi_mask == VLAN_TAG_PRESENT) {
                        vlan |= RQFPR_CFI;
@@ -1666,10 +1710,10 @@ static void gfar_invert_masks(struct ethtool_rx_flow_spec *flow)
        for (i = 0; i < sizeof(flow->m_u); i++)
                flow->m_u.hdata[i] ^= 0xFF;
 
-       flow->m_ext.vlan_etype ^= 0xFFFF;
-       flow->m_ext.vlan_tci ^= 0xFFFF;
-       flow->m_ext.data[0] ^= ~0;
-       flow->m_ext.data[1] ^= ~0;
+       flow->m_ext.vlan_etype ^= cpu_to_be16(0xFFFF);
+       flow->m_ext.vlan_tci ^= cpu_to_be16(0xFFFF);
+       flow->m_ext.data[0] ^= cpu_to_be32(~0);
+       flow->m_ext.data[1] ^= cpu_to_be32(~0);
 }
 
 static int gfar_add_cls(struct gfar_private *priv,
index e006a09..6ba2fd4 100644 (file)
@@ -134,7 +134,7 @@ struct gianfar_ptp_registers {
 #define REG_SIZE       sizeof(struct gianfar_ptp_registers)
 
 struct etsects {
-       struct gianfar_ptp_registers *regs;
+       struct gianfar_ptp_registers __iomem *regs;
        spinlock_t lock; /* protects regs */
        struct ptp_clock *clock;
        struct ptp_clock_info caps;
index 9fb2eb8..333bb54 100644 (file)
@@ -243,6 +243,7 @@ config IXGBEVF
 
 config I40E
        tristate "Intel(R) Ethernet Controller XL710 Family support"
+       select PTP_1588_CLOCK
        depends on PCI
        ---help---
          This driver supports Intel(R) Ethernet Controller XL710 Family of
index 6ec1a79..e4d2e27 100644 (file)
@@ -40,4 +40,5 @@ i40e-objs := i40e_main.o \
        i40e_debugfs.o  \
        i40e_diag.o     \
        i40e_txrx.o     \
+       i40e_ptp.o      \
        i40e_virtchnl_pf.o
diff --git a/drivers/net/ethernet/intel/i40e/Module.symvers b/drivers/net/ethernet/intel/i40e/Module.symvers
new file mode 100644 (file)
index 0000000..e69de29
index 4d4cdbf..91b0052 100644 (file)
@@ -50,6 +50,9 @@
 #include <net/ip6_checksum.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
 #include "i40e_type.h"
 #include "i40e_prototype.h"
 #include "i40e_virtchnl.h"
@@ -88,8 +91,7 @@
 
 /* The values in here are decimal coded as hex as is the case in the NVM map*/
 #define I40E_CURRENT_NVM_VERSION_HI 0x2
-#define I40E_CURRENT_NVM_VERSION_LO 0x1
-
+#define I40E_CURRENT_NVM_VERSION_LO 0x30
 
 /* magic for getting defines into strings */
 #define STRINGIFY(foo)  #foo
@@ -242,6 +244,7 @@ struct i40e_pf {
 #define I40E_FLAG_DCB_ENABLED                  (u64)(1 << 20)
 #define I40E_FLAG_FDIR_ENABLED                 (u64)(1 << 21)
 #define I40E_FLAG_FDIR_ATR_ENABLED             (u64)(1 << 22)
+#define I40E_FLAG_PTP                          (u64)(1 << 25)
 #define I40E_FLAG_MFP_ENABLED                  (u64)(1 << 26)
 #ifdef CONFIG_I40E_VXLAN
 #define I40E_FLAG_VXLAN_FILTER_SYNC            (u64)(1 << 27)
@@ -302,6 +305,20 @@ struct i40e_pf {
        u32     fcoe_hmc_filt_num;
        u32     fcoe_hmc_cntx_num;
        struct i40e_filter_control_settings filter_settings;
+
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info ptp_caps;
+       struct sk_buff *ptp_tx_skb;
+       struct work_struct ptp_tx_work;
+       struct hwtstamp_config tstamp_config;
+       unsigned long ptp_tx_start;
+       unsigned long last_rx_ptp_check;
+       spinlock_t tmreg_lock; /* Used to protect the device time registers. */
+       u64 ptp_base_adj;
+       u32 tx_hwtstamp_timeouts;
+       u32 rx_hwtstamp_cleared;
+       bool ptp_tx;
+       bool ptp_rx;
 };
 
 struct i40e_mac_filter {
@@ -566,4 +583,12 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
                                      bool is_vf, bool is_netdev);
 void i40e_vlan_stripping_enable(struct i40e_vsi *vsi);
 
+void i40e_ptp_rx_hang(struct i40e_vsi *vsi);
+void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf);
+void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index);
+void i40e_ptp_set_increment(struct i40e_pf *pf);
+int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr);
+int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr);
+void i40e_ptp_init(struct i40e_pf *pf);
+void i40e_ptp_stop(struct i40e_pf *pf);
 #endif /* _I40E_H_ */
index c75aa2d..a50e6b3 100644 (file)
@@ -128,7 +128,7 @@ static void i40e_free_adminq_arq(struct i40e_hw *hw)
 
 /**
  *  i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  **/
 static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw)
 {
@@ -195,7 +195,7 @@ unwind_alloc_arq_bufs:
 
 /**
  *  i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  **/
 static i40e_status i40e_alloc_asq_bufs(struct i40e_hw *hw)
 {
@@ -235,7 +235,7 @@ unwind_alloc_asq_bufs:
 
 /**
  *  i40e_free_arq_bufs - Free receive queue buffer info elements
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  **/
 static void i40e_free_arq_bufs(struct i40e_hw *hw)
 {
@@ -254,7 +254,7 @@ static void i40e_free_arq_bufs(struct i40e_hw *hw)
 
 /**
  *  i40e_free_asq_bufs - Free send queue buffer info elements
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  **/
 static void i40e_free_asq_bufs(struct i40e_hw *hw)
 {
@@ -277,7 +277,7 @@ static void i40e_free_asq_bufs(struct i40e_hw *hw)
 
 /**
  *  i40e_config_asq_regs - configure ASQ registers
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  *  Configure base address and length registers for the transmit queue
  **/
@@ -304,7 +304,7 @@ static void i40e_config_asq_regs(struct i40e_hw *hw)
 
 /**
  *  i40e_config_arq_regs - ARQ register configuration
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  * Configure base address and length registers for the receive (event queue)
  **/
@@ -334,7 +334,7 @@ static void i40e_config_arq_regs(struct i40e_hw *hw)
 
 /**
  *  i40e_init_asq - main initialization routine for ASQ
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  *  This is the main initialization routine for the Admin Send Queue
  *  Prior to calling this function, drivers *MUST* set the following fields
@@ -391,7 +391,7 @@ init_adminq_exit:
 
 /**
  *  i40e_init_arq - initialize ARQ
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  *  The main initialization routine for the Admin Receive (Event) Queue.
  *  Prior to calling this function, drivers *MUST* set the following fields
@@ -448,7 +448,7 @@ init_adminq_exit:
 
 /**
  *  i40e_shutdown_asq - shutdown the ASQ
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  *  The main shutdown routine for the Admin Send Queue
  **/
@@ -479,7 +479,7 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw)
 
 /**
  *  i40e_shutdown_arq - shutdown ARQ
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  *  The main shutdown routine for the Admin Receive Queue
  **/
@@ -510,7 +510,7 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw)
 
 /**
  *  i40e_init_adminq - main initialization routine for Admin Queue
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  *
  *  Prior to calling this function, drivers *MUST* set the following fields
  *  in the hw->aq structure:
@@ -607,7 +607,7 @@ init_adminq_exit:
 
 /**
  *  i40e_shutdown_adminq - shutdown routine for the Admin Queue
- *  @hw:     pointer to the hardware structure
+ *  @hw: pointer to the hardware structure
  **/
 i40e_status i40e_shutdown_adminq(struct i40e_hw *hw)
 {
@@ -626,7 +626,7 @@ i40e_status i40e_shutdown_adminq(struct i40e_hw *hw)
 
 /**
  *  i40e_clean_asq - cleans Admin send queue
- *  @asq: pointer to the adminq send ring
+ *  @hw: pointer to the hardware structure
  *
  *  returns the number of free desc
  **/
@@ -922,7 +922,7 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
                           "AQRX: Event received with error 0x%X.\n",
                           hw->aq.arq_last_status);
        } else {
-               memcpy(&e->desc, desc, sizeof(struct i40e_aq_desc));
+               e->desc = *desc;
                datalen = le16_to_cpu(desc->datalen);
                e->msg_size = min(datalen, e->msg_size);
                if (e->msg_buf != NULL && (e->msg_size != 0))
index c009eb4..be61a47 100644 (file)
@@ -1195,8 +1195,8 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
                } v4;
                struct {
                        u8 data[16];
-                       } v6;
-               } ipaddr;
+               } v6;
+       } ipaddr;
        __le16 flags;
 #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT                 0
 #define I40E_AQC_ADD_CLOUD_FILTER_MASK                  (0x3F << \
index 807312b..aedc71b 100644 (file)
@@ -74,7 +74,8 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
 /**
  * i40e_debug_aq
  * @hw: debug mask related to admin queue
- * @cap: pointer to adminq command descriptor
+ * @mask: debug mask
+ * @desc: pointer to admin queue descriptor
  * @buffer: pointer to command buffer
  *
  * Dumps debug log about adminq command with descriptor contents.
@@ -161,7 +162,6 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw,
        return status;
 }
 
-
 /**
  * i40e_init_shared_code - Initialize the shared code
  * @hw: pointer to hardware structure
@@ -599,8 +599,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
                goto aq_get_link_info_exit;
 
        /* save off old link status information */
-       memcpy(&hw->phy.link_info_old, hw_link_info,
-              sizeof(struct i40e_link_status));
+       hw->phy.link_info_old = *hw_link_info;
 
        /* update link status */
        hw_link_info->phy_type = (enum i40e_aq_phy_type)resp->phy_type;
@@ -630,7 +629,7 @@ aq_get_link_info_exit:
 /**
  * i40e_aq_add_vsi
  * @hw: pointer to the hw struct
- * @vsi: pointer to a vsi context struct
+ * @vsi_ctx: pointer to a vsi context struct
  * @cmd_details: pointer to command details structure or NULL
  *
  * Add a VSI context to the hardware.
@@ -682,7 +681,8 @@ aq_add_vsi_exit:
  * @cmd_details: pointer to command details structure or NULL
  **/
 i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
-                               u16 seid, bool set, struct i40e_asq_cmd_details *cmd_details)
+                               u16 seid, bool set,
+                               struct i40e_asq_cmd_details *cmd_details)
 {
        struct i40e_aq_desc desc;
        struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
@@ -776,7 +776,7 @@ i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
 /**
  * i40e_get_vsi_params - get VSI configuration info
  * @hw: pointer to the hw struct
- * @vsi: pointer to a vsi context struct
+ * @vsi_ctx: pointer to a vsi context struct
  * @cmd_details: pointer to command details structure or NULL
  **/
 i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
@@ -818,7 +818,7 @@ aq_get_vsi_params_exit:
 /**
  * i40e_aq_update_vsi_params
  * @hw: pointer to the hw struct
- * @vsi: pointer to a vsi context struct
+ * @vsi_ctx: pointer to a vsi context struct
  * @cmd_details: pointer to command details structure or NULL
  *
  * Update a VSI context.
@@ -921,7 +921,6 @@ i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw,
 /**
  * i40e_aq_send_driver_version
  * @hw: pointer to the hw struct
- * @event: driver event: driver ok, start or stop
  * @dv: driver's major, minor version
  * @cmd_details: pointer to command details structure or NULL
  *
@@ -1039,10 +1038,10 @@ i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
  * @hw: pointer to the hw struct
  * @veb_seid: the SEID of the VEB to query
  * @switch_id: the uplink switch id
- * @floating_veb: set to true if the VEB is floating
+ * @floating: set to true if the VEB is floating
  * @statistic_index: index of the stats counter block for this VEB
  * @vebs_used: number of VEB's used by function
- * @vebs_unallocated: total VEB's not reserved by any function
+ * @vebs_free: total VEB's not reserved by any function
  * @cmd_details: pointer to command details structure or NULL
  *
  * This retrieves the parameters for a particular VEB, specified by
@@ -1179,6 +1178,8 @@ i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
  * i40e_aq_send_msg_to_vf
  * @hw: pointer to the hardware structure
  * @vfid: vf id to send msg
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
  * @msg: pointer to the msg buffer
  * @msglen: msg length
  * @cmd_details: pointer to command details
@@ -1723,6 +1724,7 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
  * @udp_port: the UDP port to add
  * @header_len: length of the tunneling header length in DWords
  * @protocol_index: protocol index type
+ * @filter_index: pointer to filter index
  * @cmd_details: pointer to command details structure or NULL
  **/
 i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
index 0220b18..36a5cc8 100644 (file)
@@ -1083,7 +1083,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                vsi = i40e_dbg_find_vsi(pf, vsi_seid);
                if (!vsi) {
                        dev_info(&pf->pdev->dev,
-                                "add relay: vsi VSI %d not found\n", vsi_seid);
+                                "add relay: VSI %d not found\n", vsi_seid);
                        goto command_write_done;
                }
 
index b886ee5..7b87d51 100644 (file)
@@ -108,6 +108,8 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("rx_oversize", stats.rx_oversize),
        I40E_PF_STAT("rx_jabber", stats.rx_jabber),
        I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
+       I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+       I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
 };
 
 #define I40E_QUEUE_STATS_LEN(n) \
@@ -748,7 +750,36 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset,
 static int i40e_get_ts_info(struct net_device *dev,
                            struct ethtool_ts_info *info)
 {
-       return ethtool_op_get_ts_info(dev, info);
+       struct i40e_pf *pf = i40e_netdev_to_pf(dev);
+
+       info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+                               SOF_TIMESTAMPING_RX_SOFTWARE |
+                               SOF_TIMESTAMPING_SOFTWARE |
+                               SOF_TIMESTAMPING_TX_HARDWARE |
+                               SOF_TIMESTAMPING_RX_HARDWARE |
+                               SOF_TIMESTAMPING_RAW_HARDWARE;
+
+       if (pf->ptp_clock)
+               info->phc_index = ptp_clock_index(pf->ptp_clock);
+       else
+               info->phc_index = -1;
+
+       info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+       info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+                          (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+                          (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+                          (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
+
+       return 0;
 }
 
 static int i40e_link_test(struct net_device *netdev, u64 *data)
@@ -1634,7 +1665,7 @@ static int i40e_set_channels(struct net_device *dev,
         * class queue mapping
         */
        new_count = i40e_reconfig_rss_queues(pf, count);
-       if (new_count > 1)
+       if (new_count > 0)
                return 0;
        else
                return -EINVAL;
index 76dfef3..bf2d4cc 100644 (file)
@@ -89,11 +89,9 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw,
                        sd_entry->u.pd_table.pd_entry =
                                (struct i40e_hmc_pd_entry *)
                                sd_entry->u.pd_table.pd_entry_virt_mem.va;
-                       memcpy(&sd_entry->u.pd_table.pd_page_addr, &mem,
-                              sizeof(struct i40e_dma_mem));
+                       sd_entry->u.pd_table.pd_page_addr = mem;
                } else {
-                       memcpy(&sd_entry->u.bp.addr, &mem,
-                              sizeof(struct i40e_dma_mem));
+                       sd_entry->u.bp.addr = mem;
                        sd_entry->u.bp.sd_pd_index = sd_index;
                }
                /* initialize the sd entry */
@@ -164,7 +162,7 @@ i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw,
                if (ret_code)
                        goto exit;
 
-               memcpy(&pd_entry->bp.addr, &mem, sizeof(struct i40e_dma_mem));
+               pd_entry->bp.addr = mem;
                pd_entry->bp.sd_pd_index = pd_index;
                pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED;
                /* Set page address and valid bit */
index 72bf30a..0cd4701 100644 (file)
@@ -116,7 +116,6 @@ struct i40e_hmc_info {
  * @hw: pointer to our hw struct
  * @pa: pointer to physical address
  * @sd_index: segment descriptor index
- * @hmc_fn_id: hmc function id
  * @type: if sd entry is direct or paged
  **/
 #define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type)                   \
@@ -138,7 +137,6 @@ struct i40e_hmc_info {
  * I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware
  * @hw: pointer to our hw struct
  * @sd_index: segment descriptor index
- * @hmc_fn_id: hmc function id
  * @type: if sd entry is direct or paged
  **/
 #define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type)                     \
@@ -159,7 +157,6 @@ struct i40e_hmc_info {
  * @hw: pointer to our hw struct
  * @sd_idx: segment descriptor index
  * @pd_idx: page descriptor index
- * @hmc_fn_id: hmc function id
  **/
 #define I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx)                  \
        wr32((hw), I40E_PFHMC_PDINV,                                    \
index 101ed41..d5d98fe 100644 (file)
@@ -485,8 +485,7 @@ i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw,
                /* Make one big object, a single SD */
                info.count = 1;
                ret_code = i40e_create_lan_hmc_object(hw, &info);
-               if ((ret_code) &&
-                   (model == I40E_HMC_MODEL_DIRECT_PREFERRED))
+               if (ret_code && (model == I40E_HMC_MODEL_DIRECT_PREFERRED))
                        goto try_type_paged;
                else if (ret_code)
                        goto configure_lan_hmc_out;
index 1b792ee..7bfa789 100644 (file)
@@ -38,7 +38,7 @@ static const char i40e_driver_string[] =
 
 #define DRV_VERSION_MAJOR 0
 #define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 25
+#define DRV_VERSION_BUILD 30
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -356,7 +356,6 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
        struct rtnl_link_stats64 *vsi_stats = i40e_get_vsi_stats_struct(vsi);
        int i;
 
-
        if (test_bit(__I40E_DOWN, &vsi->state))
                return stats;
 
@@ -1698,6 +1697,27 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
 }
 
 /**
+ * i40e_ioctl - Access the hwtstamp interface
+ * @netdev: network interface device structure
+ * @ifr: interface request data
+ * @cmd: ioctl command
+ **/
+int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+
+       switch (cmd) {
+       case SIOCGHWTSTAMP:
+               return i40e_ptp_get_ts_config(pf, ifr);
+       case SIOCSHWTSTAMP:
+               return i40e_ptp_set_ts_config(pf, ifr);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/**
  * i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI
  * @vsi: the vsi being adjusted
  **/
@@ -1824,7 +1844,10 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
                                return -ENOMEM;
                        }
                }
+       }
 
+       /* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */
+       if (vid > 0 && !vsi->info.pvid) {
                list_for_each_entry(f, &vsi->mac_filter_list, list) {
                        if (i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY,
                                             is_vf, is_netdev)) {
@@ -2150,7 +2173,8 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
        tx_ctx.base = (ring->dma / 128);
        tx_ctx.qlen = ring->count;
        tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED |
-                       I40E_FLAG_FDIR_ATR_ENABLED));
+                                              I40E_FLAG_FDIR_ATR_ENABLED));
+       tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP);
 
        /* As part of VSI creation/update, FW allocates certain
         * Tx arbitration queue sets for each TC enabled for
@@ -2184,7 +2208,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
        }
 
        /* Now associate this queue with this PCI function */
-       qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+       if (vsi->type == I40E_VSI_VMDQ2)
+               qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
+       else
+               qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
        qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
                    I40E_QTX_CTL_PF_INDX_MASK);
        wr32(hw, I40E_QTX_CTL(pf_q), qtx_ctl);
@@ -2488,6 +2515,7 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw)
              I40E_PFINT_ICR0_ENA_GRST_MASK          |
              I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK |
              I40E_PFINT_ICR0_ENA_GPIO_MASK          |
+             I40E_PFINT_ICR0_ENA_TIMESYNC_MASK      |
              I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK  |
              I40E_PFINT_ICR0_ENA_HMC_ERR_MASK       |
              I40E_PFINT_ICR0_ENA_VFLR_MASK          |
@@ -2831,6 +2859,18 @@ static irqreturn_t i40e_intr(int irq, void *data)
                dev_info(&pf->pdev->dev, "HMC error interrupt\n");
        }
 
+       if (icr0 & I40E_PFINT_ICR0_TIMESYNC_MASK) {
+               u32 prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_0);
+
+               if (prttsyn_stat & I40E_PRTTSYN_STAT_0_TXTIME_MASK) {
+                       ena_mask &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
+                       i40e_ptp_tx_hwtstamp(pf);
+                       prttsyn_stat &= ~I40E_PRTTSYN_STAT_0_TXTIME_MASK;
+               }
+
+               wr32(hw, I40E_PRTTSYN_STAT_0, prttsyn_stat);
+       }
+
        /* If a critical error is pending we have no choice but to reset the
         * device.
         * Report and mask out any remaining unexpected interrupts.
@@ -3008,11 +3048,13 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
                        continue;
 
                /* turn on/off the queue */
-               if (enable)
+               if (enable) {
+                       wr32(hw, I40E_QTX_HEAD(pf_q), 0);
                        tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK |
                                  I40E_QTX_ENA_QENA_STAT_MASK;
-               else
+               } else {
                        tx_reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
+               }
 
                wr32(hw, I40E_QTX_ENA(pf_q), tx_reg);
 
@@ -3113,7 +3155,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
  **/
 int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request)
 {
-       int ret;
+       int ret = 0;
 
        /* do rx first for enable and last for disable */
        if (request) {
@@ -3122,10 +3164,9 @@ int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request)
                        return ret;
                ret = i40e_vsi_control_tx(vsi, request);
        } else {
-               ret = i40e_vsi_control_tx(vsi, request);
-               if (ret)
-                       return ret;
-               ret = i40e_vsi_control_rx(vsi, request);
+               /* Ignore return value, we need to shutdown whatever we can */
+               i40e_vsi_control_tx(vsi, request);
+               i40e_vsi_control_rx(vsi, request);
        }
 
        return ret;
@@ -3564,7 +3605,7 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
 
        /* Get the VSI level BW configuration per TC */
        aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config,
-                                                 NULL);
+                                                 NULL);
        if (aq_ret) {
                dev_info(&pf->pdev->dev,
                         "couldn't get pf vsi ets bw config, err %d, aq_err %d\n",
@@ -4303,6 +4344,9 @@ static void i40e_link_event(struct i40e_pf *pf)
 
        if (pf->vf)
                i40e_vc_notify_link_state(pf);
+
+       if (pf->flags & I40E_FLAG_PTP)
+               i40e_ptp_set_increment(pf);
 }
 
 /**
@@ -4384,6 +4428,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
        for (i = 0; i < I40E_MAX_VEB; i++)
                if (pf->veb[i])
                        i40e_update_veb_stats(pf->veb[i]);
+
+       i40e_ptp_rx_hang(pf->vsi[pf->lan_vsi]);
 }
 
 /**
@@ -6032,6 +6078,7 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = i40e_set_mac,
        .ndo_change_mtu         = i40e_change_mtu,
+       .ndo_do_ioctl           = i40e_ioctl,
        .ndo_tx_timeout         = i40e_tx_timeout,
        .ndo_vlan_rx_add_vid    = i40e_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = i40e_vlan_rx_kill_vid,
@@ -7298,6 +7345,8 @@ no_autoneg:
                                         ~I40E_PRTDCB_MFLCN_RFCE_MASK);
 
 fc_complete:
+       i40e_ptp_init(pf);
+
        return ret;
 }
 
@@ -7611,6 +7660,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_pf_reset;
        }
 
+       i40e_clear_pxe_mode(hw);
        err = i40e_get_capabilities(pf);
        if (err)
                goto err_adminq_setup;
@@ -7801,6 +7851,8 @@ static void i40e_remove(struct pci_dev *pdev)
 
        i40e_dbg_pf_exit(pf);
 
+       i40e_ptp_stop(pf);
+
        if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
                i40e_free_vfs(pf);
                pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
index 37d66c8..e12bf07 100644 (file)
@@ -244,6 +244,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
 /**
  *  i40e_calc_nvm_checksum - Calculates and returns the checksum
  *  @hw: pointer to hardware structure
+ *  @checksum: pointer to the checksum
  *
  *  This function calculate SW Checksum that covers the whole 64kB shadow RAM
  *  except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
index c7c3d82..f8c53a6 100644 (file)
@@ -93,9 +93,9 @@ i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
                                u16 vsi_id, bool set_filter,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
-                               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
-                               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
                                struct i40e_vsi_context *vsi_ctx,
                                struct i40e_asq_cmd_details *cmd_details);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
new file mode 100644 (file)
index 0000000..e33ec6c
--- /dev/null
@@ -0,0 +1,662 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e.h"
+#include <linux/export.h>
+#include <linux/ptp_classify.h>
+
+/* The XL710 timesync is very much like Intel's 82599 design when it comes to
+ * the fundamental clock design. However, the clock operations are much simpler
+ * in the XL710 because the device supports a full 64 bits of nanoseconds.
+ * Because the field is so wide, we can forgo the cycle counter and just
+ * operate with the nanosecond field directly without fear of overflow.
+ *
+ * Much like the 82599, the update period is dependent upon the link speed:
+ * At 40Gb link or no link, the period is 1.6ns.
+ * At 10Gb link, the period is multiplied by 2. (3.2ns)
+ * At 1Gb link, the period is multiplied by 20. (32ns)
+ * 1588 functionality is not supported at 100Mbps.
+ */
+#define I40E_PTP_40GB_INCVAL 0x0199999999ULL
+#define I40E_PTP_10GB_INCVAL 0x0333333333ULL
+#define I40E_PTP_1GB_INCVAL  0x2000000000ULL
+
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1  (0x1 << \
+                                       I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2  (0x2 << \
+                                       I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
+#define I40E_PTP_TX_TIMEOUT  (HZ * 15)
+
+/**
+ * i40e_ptp_read - Read the PHC time from the device
+ * @pf: Board private structure
+ * @ts: timespec structure to hold the current time value
+ *
+ * This function reads the PRTTSYN_TIME registers and stores them in a
+ * timespec. However, since the registers are 64 bits of nanoseconds, we must
+ * convert the result to a timespec before we can return.
+ **/
+static void i40e_ptp_read(struct i40e_pf *pf, struct timespec *ts)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u32 hi, lo;
+       u64 ns;
+
+       /* The timer latches on the lowest register read. */
+       lo = rd32(hw, I40E_PRTTSYN_TIME_L);
+       hi = rd32(hw, I40E_PRTTSYN_TIME_H);
+
+       ns = (((u64)hi) << 32) | lo;
+
+       *ts = ns_to_timespec(ns);
+}
+
+/**
+ * i40e_ptp_write - Write the PHC time to the device
+ * @pf: Board private structure
+ * @ts: timespec structure that holds the new time value
+ *
+ * This function writes the PRTTSYN_TIME registers with the user value. Since
+ * we receive a timespec from the stack, we must convert that timespec into
+ * nanoseconds before programming the registers.
+ **/
+static void i40e_ptp_write(struct i40e_pf *pf, const struct timespec *ts)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u64 ns = timespec_to_ns(ts);
+
+       /* The timer will not update until the high register is written, so
+        * write the low register first.
+        */
+       wr32(hw, I40E_PRTTSYN_TIME_L, ns & 0xFFFFFFFF);
+       wr32(hw, I40E_PRTTSYN_TIME_H, ns >> 32);
+}
+
+/**
+ * i40e_ptp_convert_to_hwtstamp - Convert device clock to system time
+ * @hwtstamps: Timestamp structure to update
+ * @timestamp: Timestamp from the hardware
+ *
+ * We need to convert the NIC clock value into a hwtstamp which can be used by
+ * the upper level timestamping functions. Since the timestamp is simply a 64-
+ * bit nanosecond value, we can call ns_to_ktime directly to handle this.
+ **/
+static void i40e_ptp_convert_to_hwtstamp(struct skb_shared_hwtstamps *hwtstamps,
+                                        u64 timestamp)
+{
+       memset(hwtstamps, 0, sizeof(*hwtstamps));
+
+       hwtstamps->hwtstamp = ns_to_ktime(timestamp);
+}
+
+/**
+ * i40e_ptp_adjfreq - Adjust the PHC frequency
+ * @ptp: The PTP clock structure
+ * @ppb: Parts per billion adjustment from the base
+ *
+ * Adjust the frequency of the PHC by the indicated parts per billion from the
+ * base frequency.
+ **/
+static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
+       struct i40e_hw *hw = &pf->hw;
+       u64 adj, freq, diff;
+       int neg_adj = 0;
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+
+       smp_mb(); /* Force any pending update before accessing. */
+       adj = ACCESS_ONCE(pf->ptp_base_adj);
+
+       freq = adj;
+       freq *= ppb;
+       diff = div_u64(freq, 1000000000ULL);
+
+       if (neg_adj)
+               adj -= diff;
+       else
+               adj += diff;
+
+       wr32(hw, I40E_PRTTSYN_INC_L, adj & 0xFFFFFFFF);
+       wr32(hw, I40E_PRTTSYN_INC_H, adj >> 32);
+
+       return 0;
+}
+
+/**
+ * i40e_ptp_adjtime - Adjust the PHC time
+ * @ptp: The PTP clock structure
+ * @delta: Offset in nanoseconds to adjust the PHC time by
+ *
+ * Adjust the frequency of the PHC by the indicated parts per billion from the
+ * base frequency.
+ **/
+static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
+       struct timespec now, then = ns_to_timespec(delta);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pf->tmreg_lock, flags);
+
+       i40e_ptp_read(pf, &now);
+       now = timespec_add(now, then);
+       i40e_ptp_write(pf, (const struct timespec *)&now);
+
+       spin_unlock_irqrestore(&pf->tmreg_lock, flags);
+
+       return 0;
+}
+
+/**
+ * i40e_ptp_gettime - Get the time of the PHC
+ * @ptp: The PTP clock structure
+ * @ts: timespec structure to hold the current time value
+ *
+ * Read the device clock and return the correct value on ns, after converting it
+ * into a timespec struct.
+ **/
+static int i40e_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pf->tmreg_lock, flags);
+       i40e_ptp_read(pf, ts);
+       spin_unlock_irqrestore(&pf->tmreg_lock, flags);
+
+       return 0;
+}
+
+/**
+ * i40e_ptp_settime - Set the time of the PHC
+ * @ptp: The PTP clock structure
+ * @ts: timespec structure that holds the new time value
+ *
+ * Set the device clock to the user input value. The conversion from timespec
+ * to ns happens in the write function.
+ **/
+static int i40e_ptp_settime(struct ptp_clock_info *ptp,
+                           const struct timespec *ts)
+{
+       struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pf->tmreg_lock, flags);
+       i40e_ptp_write(pf, ts);
+       spin_unlock_irqrestore(&pf->tmreg_lock, flags);
+
+       return 0;
+}
+
+/**
+ * i40e_ptp_tx_work
+ * @work: pointer to work struct
+ *
+ * This work function polls the PRTTSYN_STAT_0.TXTIME bit to determine when a
+ * Tx timestamp event has occurred, in order to pass the Tx timestamp value up
+ * the stack in the skb.
+ */
+static void i40e_ptp_tx_work(struct work_struct *work)
+{
+       struct i40e_pf *pf = container_of(work, struct i40e_pf,
+                                         ptp_tx_work);
+       struct i40e_hw *hw = &pf->hw;
+       u32 prttsyn_stat_0;
+
+       if (!pf->ptp_tx_skb)
+               return;
+
+       if (time_is_before_jiffies(pf->ptp_tx_start +
+                                  I40E_PTP_TX_TIMEOUT)) {
+               dev_kfree_skb_any(pf->ptp_tx_skb);
+               pf->ptp_tx_skb = NULL;
+               pf->tx_hwtstamp_timeouts++;
+               dev_warn(&pf->pdev->dev, "clearing Tx timestamp hang");
+               return;
+       }
+
+       prttsyn_stat_0 = rd32(hw, I40E_PRTTSYN_STAT_0);
+       if (prttsyn_stat_0 & I40E_PRTTSYN_STAT_0_TXTIME_MASK)
+               i40e_ptp_tx_hwtstamp(pf);
+       else
+               schedule_work(&pf->ptp_tx_work);
+}
+
+/**
+ * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem
+ * @ptp: The PTP clock structure
+ * @rq: The requested feature to change
+ * @on: Enable/disable flag
+ *
+ * The XL710 does not support any of the ancillary features of the PHC
+ * subsystem, so this function may just return.
+ **/
+static int i40e_ptp_enable(struct ptp_clock_info *ptp,
+                          struct ptp_clock_request *rq, int on)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung
+ * @vsi: The VSI with the rings relevant to 1588
+ *
+ * This watchdog task is scheduled to detect error case where hardware has
+ * dropped an Rx packet that was timestamped when the ring is full. The
+ * particular error is rare but leaves the device in a state unable to timestamp
+ * any future packets.
+ **/
+void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_ring *rx_ring;
+       unsigned long rx_event;
+       u32 prttsyn_stat;
+       int n;
+
+       if (pf->flags & I40E_FLAG_PTP)
+               return;
+
+       prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1);
+
+       /* Unless all four receive timestamp registers are latched, we are not
+        * concerned about a possible PTP Rx hang, so just update the timeout
+        * counter and exit.
+        */
+       if (!(prttsyn_stat & ((I40E_PRTTSYN_STAT_1_RXT0_MASK <<
+                              I40E_PRTTSYN_STAT_1_RXT0_SHIFT) |
+                             (I40E_PRTTSYN_STAT_1_RXT1_MASK <<
+                              I40E_PRTTSYN_STAT_1_RXT1_SHIFT) |
+                             (I40E_PRTTSYN_STAT_1_RXT2_MASK <<
+                              I40E_PRTTSYN_STAT_1_RXT2_SHIFT) |
+                             (I40E_PRTTSYN_STAT_1_RXT3_MASK <<
+                              I40E_PRTTSYN_STAT_1_RXT3_SHIFT)))) {
+               pf->last_rx_ptp_check = jiffies;
+               return;
+       }
+
+       /* Determine the most recent watchdog or rx_timestamp event. */
+       rx_event = pf->last_rx_ptp_check;
+       for (n = 0; n < vsi->num_queue_pairs; n++) {
+               rx_ring = vsi->rx_rings[n];
+               if (time_after(rx_ring->last_rx_timestamp, rx_event))
+                       rx_event = rx_ring->last_rx_timestamp;
+       }
+
+       /* Only need to read the high RXSTMP register to clear the lock */
+       if (time_is_before_jiffies(rx_event + 5 * HZ)) {
+               rd32(hw, I40E_PRTTSYN_RXTIME_H(0));
+               rd32(hw, I40E_PRTTSYN_RXTIME_H(1));
+               rd32(hw, I40E_PRTTSYN_RXTIME_H(2));
+               rd32(hw, I40E_PRTTSYN_RXTIME_H(3));
+               pf->last_rx_ptp_check = jiffies;
+               pf->rx_hwtstamp_cleared++;
+               dev_warn(&vsi->back->pdev->dev,
+                        "%s: clearing Rx timestamp hang",
+                        __func__);
+       }
+}
+
+/**
+ * i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp
+ * @pf: Board private structure
+ *
+ * Read the value of the Tx timestamp from the registers, convert it into a
+ * value consumable by the stack, and store that result into the shhwtstamps
+ * struct before returning it up the stack.
+ **/
+void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct i40e_hw *hw = &pf->hw;
+       u32 hi, lo;
+       u64 ns;
+
+       lo = rd32(hw, I40E_PRTTSYN_TXTIME_L);
+       hi = rd32(hw, I40E_PRTTSYN_TXTIME_H);
+
+       ns = (((u64)hi) << 32) | lo;
+
+       i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns);
+       skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps);
+       dev_kfree_skb_any(pf->ptp_tx_skb);
+       pf->ptp_tx_skb = NULL;
+}
+
+/**
+ * i40e_ptp_rx_hwtstamp - Utility function which checks for an Rx timestamp
+ * @pf: Board private structure
+ * @skb: Particular skb to send timestamp with
+ * @index: Index into the receive timestamp registers for the timestamp
+ *
+ * The XL710 receives a notification in the receive descriptor with an offset
+ * into the set of RXTIME registers where the timestamp is for that skb. This
+ * function goes and fetches the receive timestamp from that offset, if a valid
+ * one exists. The RXTIME registers are in ns, so we must convert the result
+ * first.
+ **/
+void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index)
+{
+       u32 prttsyn_stat, hi, lo;
+       struct i40e_hw *hw;
+       u64 ns;
+
+       /* Since we cannot turn off the Rx timestamp logic if the device is
+        * doing Tx timestamping, check if Rx timestamping is configured.
+        */
+       if (!pf->ptp_rx)
+               return;
+
+       hw = &pf->hw;
+
+       prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1);
+
+       if (!(prttsyn_stat & (1 << index)))
+               return;
+
+       lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index));
+       hi = rd32(hw, I40E_PRTTSYN_RXTIME_H(index));
+
+       ns = (((u64)hi) << 32) | lo;
+
+       i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns);
+}
+
+/**
+ * i40e_ptp_set_increment - Utility function to update clock increment rate
+ * @pf: Board private structure
+ *
+ * During a link change, the DMA frequency that drives the 1588 logic will
+ * change. In order to keep the PRTTSYN_TIME registers in units of nanoseconds,
+ * we must update the increment value per clock tick.
+ **/
+void i40e_ptp_set_increment(struct i40e_pf *pf)
+{
+       struct i40e_link_status *hw_link_info;
+       struct i40e_hw *hw = &pf->hw;
+       u64 incval;
+
+       hw_link_info = &hw->phy.link_info;
+
+       i40e_aq_get_link_info(&pf->hw, true, NULL, NULL);
+
+       switch (hw_link_info->link_speed) {
+       case I40E_LINK_SPEED_10GB:
+               incval = I40E_PTP_10GB_INCVAL;
+               break;
+       case I40E_LINK_SPEED_1GB:
+               incval = I40E_PTP_1GB_INCVAL;
+               break;
+       case I40E_LINK_SPEED_100MB:
+               dev_warn(&pf->pdev->dev,
+                        "%s: 1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n",
+                        __func__);
+               incval = 0;
+               break;
+       case I40E_LINK_SPEED_40GB:
+       default:
+               incval = I40E_PTP_40GB_INCVAL;
+               break;
+       }
+
+       /* Write the new increment value into the increment register. The
+        * hardware will not update the clock until both registers have been
+        * written.
+        */
+       wr32(hw, I40E_PRTTSYN_INC_L, incval & 0xFFFFFFFF);
+       wr32(hw, I40E_PRTTSYN_INC_H, incval >> 32);
+
+       /* Update the base adjustement value. */
+       ACCESS_ONCE(pf->ptp_base_adj) = incval;
+       smp_mb(); /* Force the above update. */
+}
+
+/**
+ * i40e_ptp_get_ts_config - ioctl interface to read the HW timestamping
+ * @pf: Board private structure
+ * @ifreq: ioctl data
+ *
+ * Obtain the current hardware timestamping settigs as requested. To do this,
+ * keep a shadow copy of the timestamp settings rather than attempting to
+ * deconstruct it from the registers.
+ **/
+int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
+{
+       struct hwtstamp_config *config = &pf->tstamp_config;
+
+       return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
+               -EFAULT : 0;
+}
+
+/**
+ * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping
+ * @pf: Board private structure
+ * @ifreq: ioctl data
+ *
+ * Respond to the user filter requests and make the appropriate hardware
+ * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping
+ * logic, so keep track in software of whether to indicate these timestamps
+ * or not.
+ *
+ * It is permissible to "upgrade" the user request to a broader filter, as long
+ * as the user receives the timestamps they care about and the user is notified
+ * the filter has been broadened.
+ **/
+int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
+{
+       struct i40e_hw *hw = &pf->hw;
+       struct hwtstamp_config *config = &pf->tstamp_config;
+       u32 pf_id, tsyntype, regval;
+
+       if (copy_from_user(config, ifr->ifr_data, sizeof(*config)))
+               return -EFAULT;
+
+       /* Reserved for future extensions. */
+       if (config->flags)
+               return -EINVAL;
+
+       /* Confirm that 1588 is supported on this PF. */
+       pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >>
+               I40E_PRTTSYN_CTL0_PF_ID_SHIFT;
+       if (hw->pf_id != pf_id)
+               return -EINVAL;
+
+       switch (config->tx_type) {
+       case HWTSTAMP_TX_OFF:
+               pf->ptp_tx = false;
+               break;
+       case HWTSTAMP_TX_ON:
+               pf->ptp_tx = true;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (config->rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               pf->ptp_rx = false;
+               tsyntype = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+               pf->ptp_rx = true;
+               tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK |
+                          I40E_PRTTSYN_CTL1_TSYNTYPE_V1 |
+                          I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
+               config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+               pf->ptp_rx = true;
+               tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK |
+                          I40E_PRTTSYN_CTL1_TSYNTYPE_V2 |
+                          I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
+               config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+               break;
+       case HWTSTAMP_FILTER_ALL:
+       default:
+               return -ERANGE;
+       }
+
+       /* Clear out all 1588-related registers to clear and unlatch them. */
+       rd32(hw, I40E_PRTTSYN_STAT_0);
+       rd32(hw, I40E_PRTTSYN_TXTIME_H);
+       rd32(hw, I40E_PRTTSYN_RXTIME_H(0));
+       rd32(hw, I40E_PRTTSYN_RXTIME_H(1));
+       rd32(hw, I40E_PRTTSYN_RXTIME_H(2));
+       rd32(hw, I40E_PRTTSYN_RXTIME_H(3));
+
+       /* Enable/disable the Tx timestamp interrupt based on user input. */
+       regval = rd32(hw, I40E_PRTTSYN_CTL0);
+       if (pf->ptp_tx)
+               regval |= I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK;
+       else
+               regval &= ~I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK;
+       wr32(hw, I40E_PRTTSYN_CTL0, regval);
+
+       regval = rd32(hw, I40E_PFINT_ICR0_ENA);
+       if (pf->ptp_tx)
+               regval |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
+       else
+               regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
+       wr32(hw, I40E_PFINT_ICR0_ENA, regval);
+
+       /* There is no simple on/off switch for Rx. To "disable" Rx support,
+        * ignore any received timestamps, rather than turn off the clock.
+        */
+       if (pf->ptp_rx) {
+               regval = rd32(hw, I40E_PRTTSYN_CTL1);
+               /* clear everything but the enable bit */
+               regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK;
+               /* now enable bits for desired Rx timestamps */
+               regval |= tsyntype;
+               wr32(hw, I40E_PRTTSYN_CTL1, regval);
+       }
+
+       return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
+               -EFAULT : 0;
+}
+
+/**
+ * i40e_ptp_init - Initialize the 1588 support and register the PHC
+ * @pf: Board private structure
+ *
+ * This function registers the device clock as a PHC. If it is successful, it
+ * starts the clock in the hardware.
+ **/
+void i40e_ptp_init(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev;
+
+       strncpy(pf->ptp_caps.name, "i40e", sizeof(pf->ptp_caps.name));
+       pf->ptp_caps.owner = THIS_MODULE;
+       pf->ptp_caps.max_adj = 999999999;
+       pf->ptp_caps.n_ext_ts = 0;
+       pf->ptp_caps.pps = 0;
+       pf->ptp_caps.adjfreq = i40e_ptp_adjfreq;
+       pf->ptp_caps.adjtime = i40e_ptp_adjtime;
+       pf->ptp_caps.gettime = i40e_ptp_gettime;
+       pf->ptp_caps.settime = i40e_ptp_settime;
+       pf->ptp_caps.enable = i40e_ptp_enable;
+
+       /* Attempt to register the clock before enabling the hardware. */
+       pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev);
+       if (IS_ERR(pf->ptp_clock)) {
+               pf->ptp_clock = NULL;
+               dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n",
+                       __func__);
+       } else {
+               struct timespec ts;
+               u32 regval;
+
+               spin_lock_init(&pf->tmreg_lock);
+               INIT_WORK(&pf->ptp_tx_work, i40e_ptp_tx_work);
+
+               dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__,
+                        netdev->name);
+               pf->flags |= I40E_FLAG_PTP;
+
+               /* Ensure the clocks are running. */
+               regval = rd32(hw, I40E_PRTTSYN_CTL0);
+               regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK;
+               wr32(hw, I40E_PRTTSYN_CTL0, regval);
+               regval = rd32(hw, I40E_PRTTSYN_CTL1);
+               regval |= I40E_PRTTSYN_CTL1_TSYNENA_MASK;
+               wr32(hw, I40E_PRTTSYN_CTL1, regval);
+
+               /* Set the increment value per clock tick. */
+               i40e_ptp_set_increment(pf);
+
+               /* reset the tstamp_config */
+               memset(&pf->tstamp_config, 0, sizeof(pf->tstamp_config));
+
+               /* Set the clock value. */
+               ts = ktime_to_timespec(ktime_get_real());
+               i40e_ptp_settime(&pf->ptp_caps, &ts);
+       }
+}
+
+/**
+ * i40e_ptp_stop - Disable the driver/hardware support and unregister the PHC
+ * @pf: Board private structure
+ *
+ * This function handles the cleanup work required from the initialization by
+ * clearing out the important information and unregistering the PHC.
+ **/
+void i40e_ptp_stop(struct i40e_pf *pf)
+{
+       pf->flags &= ~I40E_FLAG_PTP;
+       pf->ptp_tx = false;
+       pf->ptp_rx = false;
+
+       cancel_work_sync(&pf->ptp_tx_work);
+       if (pf->ptp_tx_skb) {
+               dev_kfree_skb_any(pf->ptp_tx_skb);
+               pf->ptp_tx_skb = NULL;
+       }
+
+       if (pf->ptp_clock) {
+               ptp_clock_unregister(pf->ptp_clock);
+               pf->ptp_clock = NULL;
+               dev_info(&pf->pdev->dev, "%s: removed PHC on %s\n", __func__,
+                        pf->vsi[pf->lan_vsi]->netdev->name);
+       }
+}
index 43d88dd..f57a8f8 100644 (file)
@@ -892,6 +892,10 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
              rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
                return;
 
+       /* likely incorrect csum if alternate IP extention headers found */
+       if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
+               return;
+
        /* IP or L4 or outmost IP checksum error */
        if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
                        (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) |
@@ -973,8 +977,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 
        rx_desc = I40E_RX_DESC(rx_ring, i);
        qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
-       rx_status = (qword & I40E_RXD_QW1_STATUS_MASK)
-                               >> I40E_RXD_QW1_STATUS_SHIFT;
+       rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
+                   I40E_RXD_QW1_STATUS_SHIFT;
 
        while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {
                union i40e_rx_desc *next_rxd;
@@ -1084,6 +1088,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                }
 
                skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+               if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
+                       i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
+                                          I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
+                                          I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT);
+                       rx_ring->last_rx_timestamp = jiffies;
+               }
+
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
                total_rx_packets++;
@@ -1422,6 +1433,46 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
 }
 
 /**
+ * i40e_tsyn - set up the tsyn context descriptor
+ * @tx_ring:  ptr to the ring to send
+ * @skb:      ptr to the skb we're sending
+ * @tx_flags: the collected send information
+ *
+ * Returns 0 if no Tx timestamp can happen and 1 if the timestamp will happen
+ **/
+static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
+                    u32 tx_flags, u64 *cd_type_cmd_tso_mss)
+{
+       struct i40e_pf *pf;
+
+       if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)))
+               return 0;
+
+       /* Tx timestamps cannot be sampled when doing TSO */
+       if (tx_flags & I40E_TX_FLAGS_TSO)
+               return 0;
+
+       /* only timestamp the outbound packet if the user has requested it and
+        * we are not already transmitting a packet to be timestamped
+        */
+       pf = i40e_netdev_to_pf(tx_ring->netdev);
+       if (pf->ptp_tx && !pf->ptp_tx_skb) {
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               pf->ptp_tx_skb = skb_get(skb);
+       } else {
+               return 0;
+       }
+
+       *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN <<
+                               I40E_TXD_CTX_QW1_CMD_SHIFT;
+
+       pf->ptp_tx_start = jiffies;
+       schedule_work(&pf->ptp_tx_work);
+
+       return 1;
+}
+
+/**
  * i40e_tx_enable_csum - Enable Tx checksum offloads
  * @skb: send buffer
  * @tx_flags: Tx flags currently set
@@ -1797,6 +1848,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
        __be16 protocol;
        u32 td_cmd = 0;
        u8 hdr_len = 0;
+       int tsyn;
        int tso;
        if (0 == i40e_xmit_descriptor_count(skb, tx_ring))
                return NETDEV_TX_BUSY;
@@ -1827,6 +1879,11 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
 
        skb_tx_timestamp(skb);
 
+       tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss);
+
+       if (tsyn)
+               tx_flags |= I40E_TX_FLAGS_TSYN;
+
        /* always enable CRC insertion offload */
        td_cmd |= I40E_TX_DESC_CMD_ICRC;
 
index 6f8506c..d534969 100644 (file)
@@ -29,9 +29,8 @@
 
 /* Interrupt Throttling and Rate Limiting (storm control) Goodies */
 
-#define I40E_MAX_ITR               0x07FF
-#define I40E_MIN_ITR               0x0001
-#define I40E_ITR_USEC_RESOLUTION   2
+#define I40E_MAX_ITR               0x0FF0  /* reg uses 2 usec resolution */
+#define I40E_MIN_ITR               0x0004  /* reg uses 2 usec resolution */
 #define I40E_MAX_IRATE             0x03F
 #define I40E_MIN_IRATE             0x001
 #define I40E_IRATE_USEC_RESOLUTION 4
@@ -137,6 +136,7 @@ enum i40e_dyn_idx_t {
 #define I40E_TX_FLAGS_IPV6             (u32)(1 << 5)
 #define I40E_TX_FLAGS_FCCRC            (u32)(1 << 6)
 #define I40E_TX_FLAGS_FSO              (u32)(1 << 7)
+#define I40E_TX_FLAGS_TSYN             (u32)(1 << 8)
 #define I40E_TX_FLAGS_VLAN_MASK                0xffff0000
 #define I40E_TX_FLAGS_VLAN_PRIO_MASK   0xe0000000
 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT  29
@@ -249,6 +249,8 @@ struct i40e_ring {
        u8 atr_sample_rate;
        u8 atr_count;
 
+       unsigned long last_rx_timestamp;
+
        bool ring_active;               /* is ring online or not */
 
        /* stats structs */
index 12473ad..ccfc52d 100644 (file)
 /* Max default timeout in ms, */
 #define I40E_MAX_NVM_TIMEOUT           18000
 
-/* Check whether address is multicast.  This is little-endian specific check.*/
-#define I40E_IS_MULTICAST(address)     \
-       (bool)(((u8 *)(address))[0] & ((u8)0x01))
-
-/* Check whether an address is broadcast. */
-#define I40E_IS_BROADCAST(address)     \
-       ((((u8 *)(address))[0] == ((u8)0xff)) && \
-       (((u8 *)(address))[1] == ((u8)0xff)))
-
 /* Switch from mc to the 2usec global time (this is the GTIME resolution) */
 #define I40E_MS_TO_GTIME(time)         (((time) * 1000) / 2)
 
@@ -84,6 +75,7 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
 
 /* bitfields for Tx queue mapping in QTX_CTL */
 #define I40E_QTX_CTL_VF_QUEUE  0x0
+#define I40E_QTX_CTL_VM_QUEUE  0x1
 #define I40E_QTX_CTL_PF_QUEUE  0x2
 
 /* debug masks - set these bits in hw->debug_mask to control output */
@@ -508,7 +500,9 @@ enum i40e_rx_desc_status_bits {
        I40E_RX_DESC_STATUS_FLM_SHIFT           = 11,
        I40E_RX_DESC_STATUS_FLTSTAT_SHIFT       = 12, /* 2 BITS */
        I40E_RX_DESC_STATUS_LPBK_SHIFT          = 14,
-       I40E_RX_DESC_STATUS_UDP_0_SHIFT         = 16
+       I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT     = 15,
+       I40E_RX_DESC_STATUS_RESERVED_SHIFT      = 16, /* 2 BITS */
+       I40E_RX_DESC_STATUS_UDP_0_SHIFT         = 18
 };
 
 #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT   I40E_RX_DESC_STATUS_TSYNINDX_SHIFT
index 51a4f61..44bb359 100644 (file)
@@ -386,8 +386,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
                vf->lan_vsi_index = vsi->idx;
                vf->lan_vsi_id = vsi->id;
                dev_info(&pf->pdev->dev,
-                        "LAN VSI index %d, VSI id %d\n",
-                        vsi->idx, vsi->id);
+                        "VF %d assigned LAN VSI index %d, VSI id %d\n",
+                        vf->vf_id, vsi->idx, vsi->id);
                /* If the port VLAN has been configured and then the
                 * VF driver was removed then the VSI port VLAN
                 * configuration was destroyed.  Check if there is
@@ -1525,9 +1525,13 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
        }
 
        for (i = 0; i < al->num_elements; i++) {
-               ret = i40e_check_vf_permission(vf, al->list[i].addr);
-               if (ret)
+               if (is_broadcast_ether_addr(al->list[i].addr) ||
+                   is_zero_ether_addr(al->list[i].addr)) {
+                       dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n",
+                               al->list[i].addr);
+                       ret = I40E_ERR_INVALID_MAC_ADDR;
                        goto error_param;
+               }
        }
        vsi = pf->vsi[vsi_id];
 
@@ -1788,7 +1792,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
                        local_vf_id, v_opcode, msglen);
                return ret;
        }
-       wr32(hw, I40E_VFGEN_RSTAT1(local_vf_id), I40E_VFR_VFACTIVE);
+
        switch (v_opcode) {
        case I40E_VIRTCHNL_OP_VERSION:
                ret = i40e_vc_get_version_msg(vf);
@@ -2072,6 +2076,20 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
                goto error_pvid;
        }
 
+       if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi))
+               dev_err(&pf->pdev->dev,
+                       "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n",
+                       vf_id);
+
+       /* Check for condition where there was already a port VLAN ID
+        * filter set and now it is being deleted by setting it to zero.
+        * Before deleting all the old VLAN filters we must add new ones
+        * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our
+        * MAC addresses deleted.
+        */
+       if (!(vlan_id || qos) && vsi->info.pvid)
+               ret = i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY);
+
        if (vsi->info.pvid) {
                /* kill old VLAN */
                ret = i40e_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) &
@@ -2100,6 +2118,10 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
                                 vsi->back->hw.aq.asq_last_status);
                        goto error_pvid;
                }
+               /* Kill non-vlan MAC filters - ignore error return since
+                * there might not be any non-vlan MAC filters.
+                */
+               i40e_vsi_kill_vlan(vsi, I40E_VLAN_ANY);
        }
 
        if (ret) {
index 8f2b3b2..ffdb01d 100644 (file)
@@ -21,6 +21,8 @@
  *
  ******************************************************************************/
 
+#include <linux/prefetch.h>
+
 #include "i40evf.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
index 49531cd..3a4373f 100644 (file)
@@ -585,6 +585,11 @@ static inline u16 ixgbe_desc_unused(struct ixgbe_ring *ring)
        return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
 }
 
+static inline void ixgbe_write_tail(struct ixgbe_ring *ring, u32 value)
+{
+       writel(value, ring->tail);
+}
+
 #define IXGBE_RX_DESC(R, i)        \
        (&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
 #define IXGBE_TX_DESC(R, i)        \
@@ -742,6 +747,7 @@ struct ixgbe_adapter {
 #ifdef IXGBE_FCOE
        struct ixgbe_fcoe fcoe;
 #endif /* IXGBE_FCOE */
+       u8 __iomem *io_addr; /* Mainly for iounmap use */
        u32 wol;
 
        u16 bd_number;
@@ -798,6 +804,7 @@ enum ixgbe_state_t {
        __IXGBE_TESTING,
        __IXGBE_RESETTING,
        __IXGBE_DOWN,
+       __IXGBE_REMOVING,
        __IXGBE_SERVICE_SCHED,
        __IXGBE_IN_SFP_INIT,
        __IXGBE_PTP_RUNNING,
index d259dc7..f2e3919 100644 (file)
@@ -124,24 +124,65 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
 s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
 
-#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+#define IXGBE_FAILED_READ_REG 0xffffffffU
 
-#ifndef writeq
-#define writeq(val, addr) writel((u32) (val), addr); \
-    writel((u32) (val >> 32), (addr + 4));
-#endif
+static inline bool ixgbe_removed(void __iomem *addr)
+{
+       return unlikely(!addr);
+}
 
-#define IXGBE_WRITE_REG64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
+void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg);
 
-#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
+static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
+{
+       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
 
-#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
-    writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
+       if (ixgbe_removed(reg_addr))
+               return;
+       writel(value, reg_addr + reg);
+}
+#define IXGBE_WRITE_REG(a, reg, value) ixgbe_write_reg((a), (reg), (value))
 
-#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
-    readl((a)->hw_addr + (reg) + ((offset) << 2)))
+#ifndef writeq
+#define writeq writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+       writel((u32)val, addr);
+       writel((u32)(val >> 32), addr + 4);
+}
+#endif
 
-#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
+static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value)
+{
+       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+
+       if (ixgbe_removed(reg_addr))
+               return;
+       writeq(value, reg_addr + reg);
+}
+#define IXGBE_WRITE_REG64(a, reg, value) ixgbe_write_reg64((a), (reg), (value))
+
+static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
+{
+       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u32 value;
+
+       if (ixgbe_removed(reg_addr))
+               return IXGBE_FAILED_READ_REG;
+       value = readl(reg_addr + reg);
+       if (unlikely(value == IXGBE_FAILED_READ_REG))
+               ixgbe_check_remove(hw, reg);
+       return value;
+}
+#define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg))
+
+#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \
+               ixgbe_write_reg((a), (reg) + ((offset) << 2), (value))
+
+#define IXGBE_READ_REG_ARRAY(a, reg, offset) \
+               ixgbe_read_reg((a), (reg) + ((offset) << 2))
+
+#define IXGBE_WRITE_FLUSH(a) ixgbe_read_reg((a), IXGBE_STATUS)
 
 #define ixgbe_hw_to_netdev(hw) (((struct ixgbe_adapter *)(hw)->back)->netdev)
 
index 4e7c9b0..0433070 100644 (file)
@@ -1342,61 +1342,61 @@ static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
        static const u32 test_pattern[] = {
                0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               *data = 1;
+               return 1;
+       }
        for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
-               before = readl(adapter->hw.hw_addr + reg);
-               writel((test_pattern[pat] & write),
-                      (adapter->hw.hw_addr + reg));
-               val = readl(adapter->hw.hw_addr + reg);
+               before = ixgbe_read_reg(&adapter->hw, reg);
+               ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write);
+               val = ixgbe_read_reg(&adapter->hw, reg);
                if (val != (test_pattern[pat] & write & mask)) {
                        e_err(drv, "pattern test reg %04X failed: got "
                              "0x%08X expected 0x%08X\n",
                              reg, val, (test_pattern[pat] & write & mask));
                        *data = reg;
-                       writel(before, adapter->hw.hw_addr + reg);
-                       return 1;
+                       ixgbe_write_reg(&adapter->hw, reg, before);
+                       return true;
                }
-               writel(before, adapter->hw.hw_addr + reg);
+               ixgbe_write_reg(&adapter->hw, reg, before);
        }
-       return 0;
+       return false;
 }
 
 static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
                              u32 mask, u32 write)
 {
        u32 val, before;
-       before = readl(adapter->hw.hw_addr + reg);
-       writel((write & mask), (adapter->hw.hw_addr + reg));
-       val = readl(adapter->hw.hw_addr + reg);
+
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               *data = 1;
+               return 1;
+       }
+       before = ixgbe_read_reg(&adapter->hw, reg);
+       ixgbe_write_reg(&adapter->hw, reg, write & mask);
+       val = ixgbe_read_reg(&adapter->hw, reg);
        if ((write & mask) != (val & mask)) {
                e_err(drv, "set/check reg %04X test failed: got 0x%08X "
                      "expected 0x%08X\n", reg, (val & mask), (write & mask));
                *data = reg;
-               writel(before, (adapter->hw.hw_addr + reg));
-               return 1;
+               ixgbe_write_reg(&adapter->hw, reg, before);
+               return true;
        }
-       writel(before, (adapter->hw.hw_addr + reg));
-       return 0;
+       ixgbe_write_reg(&adapter->hw, reg, before);
+       return false;
 }
 
-#define REG_PATTERN_TEST(reg, mask, write)                                   \
-       do {                                                                  \
-               if (reg_pattern_test(adapter, data, reg, mask, write))        \
-                       return 1;                                             \
-       } while (0)                                                           \
-
-
-#define REG_SET_AND_CHECK(reg, mask, write)                                  \
-       do {                                                                  \
-               if (reg_set_and_check(adapter, data, reg, mask, write))       \
-                       return 1;                                             \
-       } while (0)                                                           \
-
 static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
 {
        const struct ixgbe_reg_test *test;
        u32 value, before, after;
        u32 i, toggle;
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               e_err(drv, "Adapter removed - register test blocked\n");
+               *data = 1;
+               return 1;
+       }
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_82598EB:
                toggle = 0x7FFFF3FF;
@@ -1419,10 +1419,10 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
         * tests.  Some bits are read-only, some toggle, and some
         * are writeable on newer MACs.
         */
-       before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS);
-       value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle);
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
-       after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
+       before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS);
+       value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle);
+       ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle);
+       after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle;
        if (value != after) {
                e_err(drv, "failed STATUS register test got: 0x%08X "
                      "expected: 0x%08X\n", after, value);
@@ -1430,7 +1430,7 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
                return 1;
        }
        /* restore previous status */
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before);
+       ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before);
 
        /*
         * Perform the remainder of the register test, looping through
@@ -1438,38 +1438,47 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
         */
        while (test->reg) {
                for (i = 0; i < test->array_len; i++) {
+                       bool b = false;
+
                        switch (test->test_type) {
                        case PATTERN_TEST:
-                               REG_PATTERN_TEST(test->reg + (i * 0x40),
-                                                test->mask,
-                                                test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + (i * 0x40),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        case SET_READ_TEST:
-                               REG_SET_AND_CHECK(test->reg + (i * 0x40),
-                                                 test->mask,
-                                                 test->write);
+                               b = reg_set_and_check(adapter, data,
+                                                     test->reg + (i * 0x40),
+                                                     test->mask,
+                                                     test->write);
                                break;
                        case WRITE_NO_TEST:
-                               writel(test->write,
-                                      (adapter->hw.hw_addr + test->reg)
-                                      + (i * 0x40));
+                               ixgbe_write_reg(&adapter->hw,
+                                               test->reg + (i * 0x40),
+                                               test->write);
                                break;
                        case TABLE32_TEST:
-                               REG_PATTERN_TEST(test->reg + (i * 4),
-                                                test->mask,
-                                                test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + (i * 4),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        case TABLE64_TEST_LO:
-                               REG_PATTERN_TEST(test->reg + (i * 8),
-                                                test->mask,
-                                                test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + (i * 8),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        case TABLE64_TEST_HI:
-                               REG_PATTERN_TEST((test->reg + 4) + (i * 8),
-                                                test->mask,
-                                                test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    (test->reg + 4) + (i * 8),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        }
+                       if (b)
+                               return 1;
                }
                test++;
        }
@@ -1954,6 +1963,15 @@ static void ixgbe_diag_test(struct net_device *netdev,
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        bool if_running = netif_running(netdev);
 
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               e_err(hw, "Adapter removed - test blocked\n");
+               data[0] = 1;
+               data[1] = 1;
+               data[2] = 1;
+               data[3] = 1;
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
        set_bit(__IXGBE_TESTING, &adapter->state);
        if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
                struct ixgbe_hw *hw = &adapter->hw;
index cc06854..3ca59d2 100644 (file)
@@ -278,10 +278,41 @@ static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter,
 static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
 {
        if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
+           !test_bit(__IXGBE_REMOVING, &adapter->state) &&
            !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
                schedule_work(&adapter->service_task);
 }
 
+static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+
+       if (!hw->hw_addr)
+               return;
+       hw->hw_addr = NULL;
+       e_dev_err("Adapter removed\n");
+       ixgbe_service_event_schedule(adapter);
+}
+
+void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
+{
+       u32 value;
+
+       /* The following check not only optimizes a bit by not
+        * performing a read on the status register when the
+        * register just read was a status register read that
+        * returned IXGBE_FAILED_READ_REG. It also blocks any
+        * potential recursion.
+        */
+       if (reg == IXGBE_STATUS) {
+               ixgbe_remove_adapter(hw);
+               return;
+       }
+       value = ixgbe_read_reg(hw, IXGBE_STATUS);
+       if (value == IXGBE_FAILED_READ_REG)
+               ixgbe_remove_adapter(hw);
+}
+
 static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
 {
        BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
@@ -1314,7 +1345,7 @@ static inline void ixgbe_release_rx_desc(struct ixgbe_ring *rx_ring, u32 val)
         * such as IA-64).
         */
        wmb();
-       writel(val, rx_ring->tail);
+       ixgbe_write_tail(rx_ring, val);
 }
 
 static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
@@ -2969,7 +3000,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
                        ring->count * sizeof(union ixgbe_adv_tx_desc));
        IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0);
        IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
-       ring->tail = hw->hw_addr + IXGBE_TDT(reg_idx);
+       ring->tail = adapter->io_addr + IXGBE_TDT(reg_idx);
 
        /*
         * set WTHRESH to encourage burst writeback, it should not be set
@@ -3308,6 +3339,8 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
        u32 rxdctl;
        u8 reg_idx = ring->reg_idx;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        /* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */
        if (hw->mac.type == ixgbe_mac_82598EB &&
            !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP))
@@ -3332,6 +3365,8 @@ void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter,
        u32 rxdctl;
        u8 reg_idx = ring->reg_idx;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
        rxdctl &= ~IXGBE_RXDCTL_ENABLE;
 
@@ -3372,7 +3407,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
                        ring->count * sizeof(union ixgbe_adv_rx_desc));
        IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
        IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
-       ring->tail = hw->hw_addr + IXGBE_RDT(reg_idx);
+       ring->tail = adapter->io_addr + IXGBE_RDT(reg_idx);
 
        ixgbe_configure_srrctl(adapter, ring);
        ixgbe_configure_rscctl(adapter, ring);
@@ -4572,6 +4607,7 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
        if (hw->mac.ops.enable_tx_laser)
                hw->mac.ops.enable_tx_laser(hw);
 
+       smp_mb__before_clear_bit();
        clear_bit(__IXGBE_DOWN, &adapter->state);
        ixgbe_napi_enable_all(adapter);
 
@@ -4656,6 +4692,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
        struct ixgbe_hw *hw = &adapter->hw;
        int err;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
        /* lock SFP init bit to prevent race conditions with the watchdog */
        while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
                usleep_range(1000, 2000);
@@ -4783,7 +4821,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        int i;
 
        /* signal that we are down to the interrupt handler */
-       set_bit(__IXGBE_DOWN, &adapter->state);
+       if (test_and_set_bit(__IXGBE_DOWN, &adapter->state))
+               return; /* do nothing if already down */
 
        /* disable receives */
        rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
@@ -5874,8 +5913,9 @@ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter)
        u64 eics = 0;
        int i;
 
-       /* If we're down or resetting, just bail */
+       /* If we're down, removing or resetting, just bail */
        if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+           test_bit(__IXGBE_REMOVING, &adapter->state) ||
            test_bit(__IXGBE_RESETTING, &adapter->state))
                return;
 
@@ -6122,8 +6162,9 @@ static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
  **/
 static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter)
 {
-       /* if interface is down do nothing */
+       /* if interface is down, removing or resetting, do nothing */
        if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+           test_bit(__IXGBE_REMOVING, &adapter->state) ||
            test_bit(__IXGBE_RESETTING, &adapter->state))
                return;
 
@@ -6341,8 +6382,9 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
 
        adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED;
 
-       /* If we're already down or resetting, just bail */
+       /* If we're already down, removing or resetting, just bail */
        if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+           test_bit(__IXGBE_REMOVING, &adapter->state) ||
            test_bit(__IXGBE_RESETTING, &adapter->state))
                return;
 
@@ -6362,6 +6404,15 @@ static void ixgbe_service_task(struct work_struct *work)
        struct ixgbe_adapter *adapter = container_of(work,
                                                     struct ixgbe_adapter,
                                                     service_task);
+       if (ixgbe_removed(adapter->hw.hw_addr)) {
+               if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       rtnl_lock();
+                       ixgbe_down(adapter);
+                       rtnl_unlock();
+               }
+               ixgbe_service_event_complete(adapter);
+               return;
+       }
        ixgbe_reset_subtask(adapter);
        ixgbe_sfp_detection_subtask(adapter);
        ixgbe_sfp_link_config_subtask(adapter);
@@ -6693,7 +6744,7 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
        tx_ring->next_to_use = i;
 
        /* notify HW of packet */
-       writel(i, tx_ring->tail);
+       ixgbe_write_tail(tx_ring, i);
 
        return;
 dma_error:
@@ -6827,12 +6878,20 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
        return __ixgbe_maybe_stop_tx(tx_ring, size);
 }
 
-#ifdef IXGBE_FCOE
-static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
+                             void *accel_priv)
 {
+       struct ixgbe_fwd_adapter *fwd_adapter = accel_priv;
+#ifdef IXGBE_FCOE
        struct ixgbe_adapter *adapter;
        struct ixgbe_ring_feature *f;
        int txq;
+#endif
+
+       if (fwd_adapter)
+               return skb->queue_mapping + fwd_adapter->tx_base_queue;
+
+#ifdef IXGBE_FCOE
 
        /*
         * only execute the code below if protocol is FCoE
@@ -6858,9 +6917,11 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
                txq -= f->indices;
 
        return txq + f->offset;
+#else
+       return __netdev_pick_tx(dev, skb);
+#endif
 }
 
-#endif
 netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                          struct ixgbe_adapter *adapter,
                          struct ixgbe_ring *tx_ring)
@@ -7629,27 +7690,11 @@ static void ixgbe_fwd_del(struct net_device *pdev, void *priv)
        kfree(fwd_adapter);
 }
 
-static netdev_tx_t ixgbe_fwd_xmit(struct sk_buff *skb,
-                                 struct net_device *dev,
-                                 void *priv)
-{
-       struct ixgbe_fwd_adapter *fwd_adapter = priv;
-       unsigned int queue;
-       struct ixgbe_ring *tx_ring;
-
-       queue = skb->queue_mapping + fwd_adapter->tx_base_queue;
-       tx_ring = fwd_adapter->real_adapter->tx_ring[queue];
-
-       return __ixgbe_xmit_frame(skb, dev, tx_ring);
-}
-
 static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_open               = ixgbe_open,
        .ndo_stop               = ixgbe_close,
        .ndo_start_xmit         = ixgbe_xmit_frame,
-#ifdef IXGBE_FCOE
        .ndo_select_queue       = ixgbe_select_queue,
-#endif
        .ndo_set_rx_mode        = ixgbe_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = ixgbe_set_mac,
@@ -7689,7 +7734,6 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_bridge_getlink     = ixgbe_ndo_bridge_getlink,
        .ndo_dfwd_add_station   = ixgbe_fwd_add,
        .ndo_dfwd_del_station   = ixgbe_fwd_del,
-       .ndo_dfwd_start_xmit    = ixgbe_fwd_xmit,
 };
 
 /**
@@ -7881,6 +7925,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
                              pci_resource_len(pdev, 0));
+       adapter->io_addr = hw->hw_addr;
        if (!hw->hw_addr) {
                err = -EIO;
                goto err_ioremap;
@@ -8189,7 +8234,7 @@ err_register:
 err_sw_init:
        ixgbe_disable_sriov(adapter);
        adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
-       iounmap(hw->hw_addr);
+       iounmap(adapter->io_addr);
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
@@ -8217,7 +8262,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
 
        ixgbe_dbg_adapter_exit(adapter);
 
-       set_bit(__IXGBE_DOWN, &adapter->state);
+       set_bit(__IXGBE_REMOVING, &adapter->state);
        cancel_work_sync(&adapter->service_task);
 
 
@@ -8256,7 +8301,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
        kfree(adapter->ixgbe_ieee_ets);
 
 #endif
-       iounmap(adapter->hw.hw_addr);
+       iounmap(adapter->io_addr);
        pci_release_selected_regions(pdev, pci_select_bars(pdev,
                                     IORESOURCE_MEM));
 
index d4a64e6..cc3101a 100644 (file)
@@ -27,8 +27,7 @@
 
 #include <linux/pci.h>
 #include <linux/delay.h>
-#include "ixgbe_type.h"
-#include "ixgbe_common.h"
+#include "ixgbe.h"
 #include "ixgbe_mbx.h"
 
 /**
index 39217e5..132557c 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 
-#include "ixgbe_common.h"
+#include "ixgbe.h"
 #include "ixgbe_phy.h"
 
 static void ixgbe_i2c_start(struct ixgbe_hw *hw);
index 359f6e6..0558c71 100644 (file)
@@ -631,11 +631,14 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
 
 static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
 {
+       struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ];
        struct ixgbe_hw *hw = &adapter->hw;
        unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
        u32 reg, reg_offset, vf_shift;
        u32 msgbuf[4] = {0, 0, 0, 0};
        u8 *addr = (u8 *)(&msgbuf[1]);
+       u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask);
+       int i;
 
        e_info(probe, "VF Reset msg received from vf %d\n", vf);
 
@@ -654,6 +657,17 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
        reg |= 1 << vf_shift;
        IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg);
 
+       /* force drop enable for all VF Rx queues */
+       for (i = vf * q_per_pool; i < ((vf + 1) * q_per_pool); i++) {
+               /* flush previous write */
+               IXGBE_WRITE_FLUSH(hw);
+
+               /* indicate to hardware that we want to set drop enable */
+               reg = IXGBE_QDE_WRITE | IXGBE_QDE_ENABLE;
+               reg |= i <<  IXGBE_QDE_IDX_SHIFT;
+               IXGBE_WRITE_REG(hw, IXGBE_QDE, reg);
+       }
+
        /* enable receive for vf */
        reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset));
        reg |= 1 << vf_shift;
@@ -684,6 +698,15 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
        reg |= (1 << vf_shift);
        IXGBE_WRITE_REG(hw, IXGBE_VMECM(reg_offset), reg);
 
+       /*
+        * Reset the VFs TDWBAL and TDWBAH registers
+        * which are not cleared by an FLR
+        */
+       for (i = 0; i < q_per_pool; i++) {
+               IXGBE_WRITE_REG(hw, IXGBE_PVFTDWBAHn(q_per_pool, vf, i), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_PVFTDWBALn(q_per_pool, vf, i), 0);
+       }
+
        /* reply to reset with ack and vf mac address */
        msgbuf[0] = IXGBE_VF_RESET;
        if (!is_zero_ether_addr(vf_mac)) {
index 7c19e96..0d39cfc 100644 (file)
@@ -1980,9 +1980,10 @@ enum {
 #define IXGBE_FWSM_TS_ENABLED  0x1
 
 /* Queue Drop Enable */
-#define IXGBE_QDE_ENABLE     0x00000001
-#define IXGBE_QDE_IDX_MASK   0x00007F00
-#define IXGBE_QDE_IDX_SHIFT           8
+#define IXGBE_QDE_ENABLE       0x00000001
+#define IXGBE_QDE_IDX_MASK     0x00007F00
+#define IXGBE_QDE_IDX_SHIFT    8
+#define IXGBE_QDE_WRITE                0x00010000
 
 #define IXGBE_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
 #define IXGBE_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
@@ -2173,6 +2174,14 @@ enum {
 #define IXGBE_MBVFICR(_i)              (0x00710 + ((_i) * 4))
 #define IXGBE_VFLRE(_i)                ((((_i) & 1) ? 0x001C0 : 0x00600))
 #define IXGBE_VFLREC(_i)               (0x00700 + ((_i) * 4))
+/* Translated register #defines */
+#define IXGBE_PVFTDWBAL(P)     (0x06038 + (0x40 * (P)))
+#define IXGBE_PVFTDWBAH(P)     (0x0603C + (0x40 * (P)))
+
+#define IXGBE_PVFTDWBALn(q_per_pool, vf_number, vf_q_index) \
+               (IXGBE_PVFTDWBAL((q_per_pool)*(vf_number) + (vf_q_index)))
+#define IXGBE_PVFTDWBAHn(q_per_pool, vf_number, vf_q_index) \
+               (IXGBE_PVFTDWBAH((q_per_pool)*(vf_number) + (vf_q_index)))
 
 enum ixgbe_fdir_pballoc_type {
        IXGBE_FDIR_PBALLOC_NONE = 0,
index 974a007..8f9266c 100644 (file)
@@ -618,7 +618,8 @@ ltq_etop_set_multicast_list(struct net_device *dev)
 }
 
 static u16
-ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb)
+ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb,
+                     void *accel_priv)
 {
        /* we are currently only using the first queue */
        return 0;
index a49e81b..6300fd2 100644 (file)
@@ -33,6 +33,7 @@ config MV643XX_ETH
 
 config MVMDIO
        tristate "Marvell MDIO interface support"
+       depends on HAS_IOMEM
        select PHYLIB
        ---help---
          This driver supports the MDIO interface found in the network
index 3b66f26..890922c 100644 (file)
@@ -724,7 +724,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                                 * - not an IP fragment
                                 * - no LLS polling in progress
                                 */
-                               if (!mlx4_en_cq_ll_polling(cq) &&
+                               if (!mlx4_en_cq_busy_polling(cq) &&
                                    (dev->features & NETIF_F_GRO)) {
                                        struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
                                        if (!gro_skb)
@@ -816,8 +816,10 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
 
                skb_mark_napi_id(skb, &cq->napi);
 
-               /* Push it up the stack */
-               netif_receive_skb(skb);
+               if (!mlx4_en_cq_busy_polling(cq))
+                       napi_gro_receive(&cq->napi, skb);
+               else
+                       netif_receive_skb(skb);
 
 next:
                for (nr = 0; nr < priv->num_frags; nr++)
index 160e86d..8e8a7eb 100644 (file)
@@ -628,7 +628,8 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
        }
 }
 
-u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
+u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
+                        void *accel_priv)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        u16 rings_p_up = priv->num_tx_rings_p_up;
index 2f1e200..3af04c3 100644 (file)
@@ -661,7 +661,7 @@ static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
 }
 
 /* true if a socket is polling, even if it did not get the lock */
-static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
+static inline bool mlx4_en_cq_busy_polling(struct mlx4_en_cq *cq)
 {
        WARN_ON(!(cq->state & MLX4_CQ_LOCKED));
        return cq->state & CQ_USER_PEND;
@@ -691,7 +691,7 @@ static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
        return false;
 }
 
-static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
+static inline bool mlx4_en_cq_busy_polling(struct mlx4_en_cq *cq)
 {
        return false;
 }
@@ -722,7 +722,8 @@ int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
 int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
 
 void mlx4_en_tx_irq(struct mlx4_cq *mcq);
-u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb);
+u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
+                        void *accel_priv);
 netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
index 8e9dad7..ce84dc2 100644 (file)
@@ -5853,15 +5853,12 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct dev_info *hw_priv = priv->adapter;
        struct ksz_hw *hw = &hw_priv->hw;
        struct ksz_port *port = &priv->port;
-       int rc;
        int result = 0;
        struct mii_ioctl_data *data = if_mii(ifr);
 
        if (down_interruptible(&priv->proc_sem))
                return -ERESTARTSYS;
 
-       /* assume success */
-       rc = 0;
        switch (cmd) {
        /* Get address of MII PHY in use. */
        case SIOCGMIIPHY:
index 35d4876..1accd95 100644 (file)
@@ -38,8 +38,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 53
-#define QLCNIC_LINUX_VERSIONID  "5.3.53"
+#define _QLCNIC_LINUX_SUBVERSION 54
+#define QLCNIC_LINUX_VERSIONID  "5.3.54"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -970,6 +970,9 @@ struct qlcnic_ipaddr {
 #define QLCNIC_BEACON_EANBLE           0xC
 #define QLCNIC_BEACON_DISABLE          0xD
 
+#define QLCNIC_BEACON_ON               2
+#define QLCNIC_BEACON_OFF              0
+
 #define QLCNIC_MSIX_TBL_SPACE          8192
 #define QLCNIC_PCI_REG_MSIX_TBL        0x44
 #define QLCNIC_MSIX_TBL_PGSIZE         4096
@@ -1079,6 +1082,7 @@ struct qlcnic_adapter {
        u64 dev_rst_time;
        bool drv_mac_learn;
        bool fdb_mac_learn;
+       u8 rx_mac_learn;
        unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
        u8 flash_mfg_id;
        struct qlcnic_npar_info *npars;
@@ -1267,7 +1271,7 @@ struct qlcnic_pci_func_cfg {
        u16     port_num;
        u8      pci_func;
        u8      func_state;
-       u8      def_mac_addr[6];
+       u8      def_mac_addr[ETH_ALEN];
 };
 
 struct qlcnic_npar_func_cfg {
@@ -1640,7 +1644,6 @@ int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
 int qlcnic_reset_npar_config(struct qlcnic_adapter *);
 int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
 void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16);
-int qlcnic_get_beacon_state(struct qlcnic_adapter *, u8 *);
 int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
 int qlcnic_read_mac_addr(struct qlcnic_adapter *);
 int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int);
@@ -1720,6 +1723,7 @@ int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *);
 void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *);
 void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx);
 void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx);
+void qlcnic_update_stats(struct qlcnic_adapter *);
 
 /* Adapter hardware abstraction */
 struct qlcnic_hardware_ops {
@@ -1767,6 +1771,7 @@ struct qlcnic_hardware_ops {
                                               pci_channel_state_t);
        pci_ers_result_t (*io_slot_reset) (struct pci_dev *);
        void (*io_resume) (struct pci_dev *);
+       void (*get_beacon_state)(struct qlcnic_adapter *);
 };
 
 extern struct qlcnic_nic_template qlcnic_vf_ops;
@@ -1993,6 +1998,11 @@ static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
                adapter->ahw->hw_ops->set_mac_filter_count(adapter);
 }
 
+static inline void qlcnic_get_beacon_state(struct qlcnic_adapter *adapter)
+{
+       adapter->ahw->hw_ops->get_beacon_state(adapter);
+}
+
 static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter)
 {
        if (adapter->ahw->hw_ops->read_phys_port_id)
index 03eb2ad..a684d28 100644 (file)
@@ -181,7 +181,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
        .io_error_detected              = qlcnic_83xx_io_error_detected,
        .io_slot_reset                  = qlcnic_83xx_io_slot_reset,
        .io_resume                      = qlcnic_83xx_io_resume,
-
+       .get_beacon_state               = qlcnic_83xx_get_beacon_state,
 };
 
 static struct qlcnic_nic_template qlcnic_83xx_ops = {
@@ -1388,6 +1388,33 @@ out:
        netif_device_attach(netdev);
 }
 
+void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+       struct qlcnic_cmd_args cmd;
+       u8 beacon_state;
+       int err = 0;
+
+       err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_CONFIG);
+       if (!err) {
+               err = qlcnic_issue_cmd(adapter, &cmd);
+               if (!err) {
+                       beacon_state = cmd.rsp.arg[4];
+                       if (beacon_state == QLCNIC_BEACON_DISABLE)
+                               ahw->beacon_state = QLC_83XX_BEACON_OFF;
+                       else if (beacon_state == QLC_83XX_ENABLE_BEACON)
+                               ahw->beacon_state = QLC_83XX_BEACON_ON;
+               }
+       } else {
+               netdev_err(adapter->netdev, "Get beacon state failed, err=%d\n",
+                          err);
+       }
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return;
+}
+
 int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state,
                           u32 beacon)
 {
@@ -1591,7 +1618,9 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter,
                                                 u32 *interface_id)
 {
        if (qlcnic_sriov_pf_check(adapter)) {
+               qlcnic_alloc_lb_filters_mem(adapter);
                qlcnic_pf_set_interface_id_promisc(adapter, interface_id);
+               adapter->rx_mac_learn = 1;
        } else {
                if (!qlcnic_sriov_vf_check(adapter))
                        *interface_id = adapter->recv_ctx->context_id << 16;
@@ -1618,6 +1647,10 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
 
        cmd->type = QLC_83XX_MBX_CMD_NO_WAIT;
        qlcnic_83xx_set_interface_id_promisc(adapter, &temp);
+
+       if (qlcnic_84xx_check(adapter) && qlcnic_sriov_pf_check(adapter))
+               mode = VPORT_MISS_MODE_ACCEPT_ALL;
+
        cmd->req.arg[1] = mode | temp;
        err = qlcnic_issue_cmd(adapter, cmd);
        if (!err)
index 34d2911..4643b15 100644 (file)
@@ -381,6 +381,8 @@ enum qlcnic_83xx_states {
 
 /* LED configuration settings */
 #define QLC_83XX_ENABLE_BEACON         0xe
+#define QLC_83XX_BEACON_ON             1
+#define QLC_83XX_BEACON_OFF            0
 #define QLC_83XX_LED_RATE              0xff
 #define QLC_83XX_LED_ACT               (1 << 10)
 #define QLC_83XX_LED_MOD               (0 << 13)
@@ -559,6 +561,7 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *);
 void qlcnic_83xx_napi_enable(struct qlcnic_adapter *);
 void qlcnic_83xx_napi_disable(struct qlcnic_adapter *);
 int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);
 void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32);
 int qlcnic_ind_rd(struct qlcnic_adapter *, u32);
 int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *);
index 22ae884..abe3924 100644 (file)
@@ -2214,6 +2214,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        int err = 0;
 
+       adapter->rx_mac_learn = 0;
        ahw->msix_supported = !!qlcnic_use_msi_x;
 
        qlcnic_83xx_init_rings(adapter);
index 474320a..23c4fd1 100644 (file)
@@ -224,10 +224,14 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
                return -EIO;
        }
 
-       if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY)
+       if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) {
                adapter->flags |= QLCNIC_ESWITCH_ENABLED;
-       else
+               if (adapter->drv_mac_learn)
+                       adapter->rx_mac_learn = 1;
+       } else {
                adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+               adapter->rx_mac_learn = 0;
+       }
 
        ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
        ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
index 45fa6ef..18ced0f 100644 (file)
@@ -167,27 +167,35 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
 
 #define QLCNIC_TEST_LEN        ARRAY_SIZE(qlcnic_gstrings_test)
 
-static inline int qlcnic_82xx_statistics(void)
+static inline int qlcnic_82xx_statistics(struct qlcnic_adapter *adapter)
 {
-       return ARRAY_SIZE(qlcnic_device_gstrings_stats) +
-              ARRAY_SIZE(qlcnic_83xx_mac_stats_strings);
+       return ARRAY_SIZE(qlcnic_gstrings_stats) +
+              ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
+              QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings;
 }
 
-static inline int qlcnic_83xx_statistics(void)
+static inline int qlcnic_83xx_statistics(struct qlcnic_adapter *adapter)
 {
-       return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
+       return ARRAY_SIZE(qlcnic_gstrings_stats) +
+              ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) +
               ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) +
-              ARRAY_SIZE(qlcnic_83xx_rx_stats_strings);
+              ARRAY_SIZE(qlcnic_83xx_rx_stats_strings) +
+              QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings;
 }
 
 static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter)
 {
-       if (qlcnic_82xx_check(adapter))
-               return qlcnic_82xx_statistics();
-       else if (qlcnic_83xx_check(adapter))
-               return qlcnic_83xx_statistics();
-       else
-               return -1;
+       int len = -1;
+
+       if (qlcnic_82xx_check(adapter)) {
+               len = qlcnic_82xx_statistics(adapter);
+               if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+                       len += ARRAY_SIZE(qlcnic_device_gstrings_stats);
+       } else if (qlcnic_83xx_check(adapter)) {
+               len = qlcnic_83xx_statistics(adapter);
+       }
+
+       return len;
 }
 
 #define        QLCNIC_TX_INTR_NOT_CONFIGURED   0X78563412
@@ -923,18 +931,13 @@ static int qlcnic_eeprom_test(struct net_device *dev)
 
 static int qlcnic_get_sset_count(struct net_device *dev, int sset)
 {
-       int len;
 
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        switch (sset) {
        case ETH_SS_TEST:
                return QLCNIC_TEST_LEN;
        case ETH_SS_STATS:
-               len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN;
-               if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
-                   qlcnic_83xx_check(adapter))
-                       return len;
-               return qlcnic_82xx_statistics();
+               return qlcnic_dev_statistics_len(adapter);
        default:
                return -EOPNOTSUPP;
        }
@@ -1270,7 +1273,7 @@ static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type)
        return data;
 }
 
-static void qlcnic_update_stats(struct qlcnic_adapter *adapter)
+void qlcnic_update_stats(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_host_tx_ring *tx_ring;
        int ring;
index a9a149b..6ca5e57 100644 (file)
@@ -546,8 +546,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
            !adapter->fdb_mac_learn) {
                qlcnic_alloc_lb_filters_mem(adapter);
                adapter->drv_mac_learn = 1;
+               if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+                       adapter->rx_mac_learn = 1;
        } else {
                adapter->drv_mac_learn = 0;
+               adapter->rx_mac_learn = 0;
        }
 
        qlcnic_nic_set_promisc(adapter, mode);
@@ -779,8 +782,8 @@ void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter)
                        "Could not send interrupt coalescing parameters\n");
 }
 
-#define QLCNIC_ENABLE_IPV4_LRO         1
-#define QLCNIC_ENABLE_IPV6_LRO         2
+#define QLCNIC_ENABLE_IPV4_LRO         BIT_0
+#define QLCNIC_ENABLE_IPV6_LRO         (BIT_1 | BIT_9)
 
 int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
 {
@@ -1530,19 +1533,34 @@ int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
        return rv;
 }
 
-int qlcnic_get_beacon_state(struct qlcnic_adapter *adapter, u8 *h_state)
+void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        struct qlcnic_cmd_args cmd;
-       int err;
+       u8 beacon_state;
+       int err = 0;
 
-       err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_STATUS);
-       if (!err) {
-               err = qlcnic_issue_cmd(adapter, &cmd);
-               if (!err)
-                       *h_state = cmd.rsp.arg[1];
+       if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
+               err = qlcnic_alloc_mbx_args(&cmd, adapter,
+                                           QLCNIC_CMD_GET_LED_STATUS);
+               if (!err) {
+                       err = qlcnic_issue_cmd(adapter, &cmd);
+                       if (err) {
+                               netdev_err(adapter->netdev,
+                                          "Failed to get current beacon state, err=%d\n",
+                                          err);
+                       } else {
+                               beacon_state = cmd.rsp.arg[1];
+                               if (beacon_state == QLCNIC_BEACON_DISABLE)
+                                       ahw->beacon_state = QLCNIC_BEACON_OFF;
+                               else if (beacon_state == QLCNIC_BEACON_EANBLE)
+                                       ahw->beacon_state = QLCNIC_BEACON_ON;
+                       }
+               }
+               qlcnic_free_mbx_args(&cmd);
        }
-       qlcnic_free_mbx_args(&cmd);
-       return err;
+
+       return;
 }
 
 void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
index 13303e7..0e739ae 100644 (file)
@@ -169,6 +169,7 @@ int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
 int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
 int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter,
                         struct net_device *netdev);
+void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *);
 void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter,
                               u64 *uaddr, u16 vlan_id);
 void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter);
index 6373f60..2f96744 100644 (file)
@@ -156,9 +156,9 @@ static inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter,
        writel(1, tx_ring->crb_intr_mask);
 }
 
-static inline u8 qlcnic_mac_hash(u64 mac)
+static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan)
 {
-       return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff));
+       return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff));
 }
 
 static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter,
@@ -221,8 +221,11 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
        u8 hindex, op;
        int ret;
 
+       if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff))
+               vlan_id = 0;
+
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-       hindex = qlcnic_mac_hash(src_addr) &
+       hindex = qlcnic_mac_hash(src_addr, vlan_id) &
                 (adapter->fhash.fbucket_size - 1);
 
        if (loopback_pkt) {
@@ -322,31 +325,47 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
                               struct cmd_desc_type0 *first_desc,
                               struct sk_buff *skb)
 {
+       struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data);
+       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+       struct net_device *netdev = adapter->netdev;
+       u16 protocol = ntohs(skb->protocol);
        struct qlcnic_filter *fil, *tmp_fil;
-       struct hlist_node *n;
        struct hlist_head *head;
-       struct net_device *netdev = adapter->netdev;
-       struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+       struct hlist_node *n;
        u64 src_addr = 0;
        u16 vlan_id = 0;
-       u8 hindex;
+       u8 hindex, hval;
 
-       if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
-               return;
+       if (!qlcnic_sriov_pf_check(adapter)) {
+               if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
+                       return;
+       } else {
+               if (protocol == ETH_P_8021Q) {
+                       vh = (struct vlan_ethhdr *)skb->data;
+                       vlan_id = ntohs(vh->h_vlan_TCI);
+               } else if (vlan_tx_tag_present(skb)) {
+                       vlan_id = vlan_tx_tag_get(skb);
+               }
+
+               if (ether_addr_equal(phdr->h_source, adapter->mac_addr) &&
+                   !vlan_id)
+                       return;
+       }
 
        if (adapter->fhash.fnum >= adapter->fhash.fmax) {
                adapter->stats.mac_filter_limit_overrun++;
-               netdev_info(netdev, "Can not add more than %d mac addresses\n",
-                           adapter->fhash.fmax);
+               netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n",
+                           adapter->fhash.fmax, adapter->fhash.fnum);
                return;
        }
 
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
-       hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1);
+       hval = qlcnic_mac_hash(src_addr, vlan_id);
+       hindex = hval & (adapter->fhash.fbucket_size - 1);
        head = &(adapter->fhash.fhead[hindex]);
 
        hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
-               if (ether_addr_equal(tmp_fil->faddr, &src_addr) &&
+               if (ether_addr_equal(tmp_fil->faddr, (u8 *)&src_addr) &&
                    tmp_fil->vlan_id == vlan_id) {
                        if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
                                qlcnic_change_filter(adapter, &src_addr,
@@ -1599,7 +1618,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
        struct sk_buff *skb;
        struct qlcnic_host_rds_ring *rds_ring;
        int index, length, cksum, is_lb_pkt;
-       u16 vid = 0xffff, t_vid;
+       u16 vid = 0xffff;
+       int err;
 
        if (unlikely(ring >= adapter->max_rds_rings))
                return NULL;
@@ -1617,19 +1637,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
        if (!skb)
                return buffer;
 
-       if (adapter->drv_mac_learn &&
-           (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               t_vid = 0;
-               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
-               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
-       }
-
        if (length > rds_ring->skb_size)
                skb_put(skb, rds_ring->skb_size);
        else
                skb_put(skb, length);
 
-       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+       err = qlcnic_check_rx_tagging(adapter, skb, &vid);
+
+       if (adapter->rx_mac_learn) {
+               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0);
+               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid);
+       }
+
+       if (unlikely(err)) {
                adapter->stats.rxdropped++;
                dev_kfree_skb(skb);
                return buffer;
@@ -1664,7 +1684,8 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        int l2_hdr_offset, l4_hdr_offset;
        int index, is_lb_pkt;
        u16 lro_length, length, data_offset, gso_size;
-       u16 vid = 0xffff, t_vid;
+       u16 vid = 0xffff;
+       int err;
 
        if (unlikely(ring > adapter->max_rds_rings))
                return NULL;
@@ -1686,12 +1707,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        if (!skb)
                return buffer;
 
-       if (adapter->drv_mac_learn &&
-           (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
-               t_vid = 0;
-               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
-               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid);
-       }
        if (qlcnic_83xx_is_tstamp(sts_data[1]))
                data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE;
        else
@@ -1700,7 +1715,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        skb_put(skb, lro_length + data_offset);
        skb_pull(skb, l2_hdr_offset);
 
-       if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+       err = qlcnic_check_rx_tagging(adapter, skb, &vid);
+
+       if (adapter->rx_mac_learn) {
+               is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1);
+               qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid);
+       }
+
+       if (unlikely(err)) {
                adapter->stats.rxdropped++;
                dev_kfree_skb(skb);
                return buffer;
index eeec83a..eec7b41 100644 (file)
@@ -546,6 +546,7 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
        .io_error_detected              = qlcnic_82xx_io_error_detected,
        .io_slot_reset                  = qlcnic_82xx_io_slot_reset,
        .io_resume                      = qlcnic_82xx_io_resume,
+       .get_beacon_state               = qlcnic_82xx_get_beacon_state,
 };
 
 static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter)
@@ -2779,6 +2780,9 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct net_device_stats *stats = &netdev->stats;
 
+       if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+               qlcnic_update_stats(adapter);
+
        stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
        stats->tx_packets = adapter->stats.xmitfinished;
        stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
index bf8fca7..f998fdc 100644 (file)
@@ -277,9 +277,7 @@ static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter)
 
 void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
 {
-       struct qlcnic_sriov *sriov = adapter->ahw->sriov;
-
-       if (!sriov)
+       if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state))
                return;
 
        qlcnic_sriov_free_vlans(adapter);
index d14d9a1..09acf15 100644 (file)
@@ -9,9 +9,14 @@
 #include "qlcnic.h"
 #include <linux/types.h>
 
-#define QLCNIC_SRIOV_VF_MAX_MAC 8
+#define QLCNIC_SRIOV_VF_MAX_MAC 7
 #define QLC_VF_MIN_TX_RATE     100
 #define QLC_VF_MAX_TX_RATE     9999
+#define QLC_MAC_OPCODE_MASK    0x7
+#define QLC_MAC_STAR_ADD       6
+#define QLC_MAC_STAR_DEL       7
+#define QLC_VF_FLOOD_BIT       BIT_16
+#define QLC_FLOOD_MODE         0x5
 
 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
 
@@ -344,6 +349,28 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,
        return err;
 }
 
+/* On configuring VF flood bit, PFD will receive traffic from all VFs */
+static int qlcnic_sriov_pf_cfg_flood(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_cmd_args cmd;
+       int err;
+
+       err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO);
+       if (err)
+               return err;
+
+       cmd.req.arg[1] = QLC_FLOOD_MODE | QLC_VF_FLOOD_BIT;
+
+       err = qlcnic_issue_cmd(adapter, &cmd);
+       if (err)
+               dev_err(&adapter->pdev->dev,
+                       "Failed to configure VF Flood bit on PF, err=%d\n",
+                       err);
+
+       qlcnic_free_mbx_args(&cmd);
+       return err;
+}
+
 static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter,
                                       u8 func, u8 enable)
 {
@@ -471,6 +498,12 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter)
        if (err)
                return err;
 
+       if (qlcnic_84xx_check(adapter)) {
+               err = qlcnic_sriov_pf_cfg_flood(adapter);
+               if (err)
+                       goto disable_vlan_filtering;
+       }
+
        err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1);
        if (err)
                goto disable_vlan_filtering;
@@ -1173,6 +1206,13 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
        struct qlcnic_vport *vp = vf->vp;
        u8 op, new_op;
 
+       if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) ||
+           ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) {
+               netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n",
+                          vf->pci_func);
+               return -EINVAL;
+       }
+
        if (!(cmd->req.arg[1] & BIT_8))
                return -EINVAL;
 
index b529667..1c8552f 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 
 #include "qlcnic.h"
@@ -127,6 +126,8 @@ static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter,
        if (kstrtoul(buf, 2, &h_beacon))
                return -EINVAL;
 
+       qlcnic_get_beacon_state(adapter);
+
        if (ahw->beacon_state == h_beacon)
                return len;
 
@@ -158,7 +159,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        int err, drv_sds_rings = adapter->drv_sds_rings;
        u16 beacon;
-       u8 h_beacon_state, b_state, b_rate;
+       u8 b_state, b_rate;
 
        if (len != sizeof(u16))
                return QL_STATUS_INVALID_PARAM;
@@ -168,18 +169,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
        if (err)
                return err;
 
-       if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
-               err = qlcnic_get_beacon_state(adapter, &h_beacon_state);
-               if (err) {
-                       netdev_err(adapter->netdev,
-                                  "Failed to get current beacon state\n");
-               } else {
-                       if (h_beacon_state == QLCNIC_BEACON_DISABLE)
-                               ahw->beacon_state = 0;
-                       else if (h_beacon_state == QLCNIC_BEACON_EANBLE)
-                               ahw->beacon_state = 2;
-               }
-       }
+       qlcnic_get_beacon_state(adapter);
 
        if (ahw->beacon_state == b_state)
                return len;
@@ -927,38 +917,35 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
        u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_pci_func_cfg *pci_cfg;
        struct qlcnic_pci_info *pci_info;
-       size_t pci_info_sz, pci_cfg_sz;
+       size_t pci_cfg_sz;
        int i, ret;
 
        pci_cfg_sz = pci_func_count * sizeof(*pci_cfg);
        if (size != pci_cfg_sz)
                return QL_STATUS_INVALID_PARAM;
 
-       pci_info_sz = pci_func_count * sizeof(*pci_info);
-       pci_info = vmalloc(pci_info_sz);
+       pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL);
        if (!pci_info)
                return -ENOMEM;
 
-       memset(pci_info, 0, pci_info_sz);
-       memset(buf, 0, pci_cfg_sz);
-       pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
-
        ret = qlcnic_get_pci_info(adapter, pci_info);
        if (ret) {
-               vfree(pci_info);
+               kfree(pci_info);
                return ret;
        }
 
+       pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
        for (i = 0; i < pci_func_count; i++) {
                pci_cfg[i].pci_func = pci_info[i].id;
                pci_cfg[i].func_type = pci_info[i].type;
+               pci_cfg[i].func_state = 0;
                pci_cfg[i].port_num = pci_info[i].default_port;
                pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
                pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
                memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
        }
 
-       vfree(pci_info);
+       kfree(pci_info);
        return size;
 }
 
index 8884107..ba1f6c9 100644 (file)
@@ -1513,11 +1513,11 @@ ignore_link:
        if (intr_status & mask) {
                /* Tx error */
                u32 edtrr = sh_eth_read(ndev, EDTRR);
+
                /* dmesg */
-               dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ",
-                       intr_status, mdp->cur_tx);
-               dev_err(&ndev->dev, "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
-                       mdp->dirty_tx, (u32) ndev->state, edtrr);
+               dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
+                       intr_status, mdp->cur_tx, mdp->dirty_tx,
+                       (u32)ndev->state, edtrr);
                /* dirty buffer free */
                sh_eth_txfree(ndev);
 
index 96f79f7..a6a9e1e 100644 (file)
@@ -1894,7 +1894,7 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr,
        SMC_SELECT_BANK(lp, 1);
        val = SMC_GET_BASE(lp);
        val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
-       if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) {
+       if (((unsigned long)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) {
                netdev_warn(dev, "%s: IOADDR %p doesn't match configuration (%x).\n",
                            CARDNAME, ioaddr, val);
        }
index b8e3a4c..ecdc8ab 100644 (file)
@@ -1951,6 +1951,23 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 }
 
+static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
+{
+       struct ethhdr *ehdr;
+       u16 vlanid;
+
+       if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) ==
+           NETIF_F_HW_VLAN_CTAG_RX &&
+           !__vlan_get_tag(skb, &vlanid)) {
+               /* pop the vlan tag */
+               ehdr = (struct ethhdr *)skb->data;
+               memmove(skb->data + VLAN_HLEN, ehdr, ETH_ALEN * 2);
+               skb_pull(skb, VLAN_HLEN);
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid);
+       }
+}
+
+
 /**
  * stmmac_rx_refill: refill used skb preallocated buffers
  * @priv: driver private structure
@@ -2102,6 +2119,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
                                print_pkt(skb->data, frame_len);
                        }
 
+                       stmmac_rx_vlan(priv->dev, skb);
+
                        skb->protocol = eth_type_trans(skb, priv->dev);
 
                        if (unlikely(!coe))
index 4f1d254..2ead877 100644 (file)
@@ -1764,7 +1764,7 @@ static void bdx_tx_cleanup(struct bdx_priv *priv)
        WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
 
        /* We reclaimed resources, so in case the Q is stopped by xmit callback,
-        * we resume the transmition and use tx_lock to synchronize with xmit.*/
+        * we resume the transmission and use tx_lock to synchronize with xmit.*/
        spin_lock(&priv->tx_lock);
        priv->tx_level += tx_level;
        BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
index 570495b..023237a 100644 (file)
@@ -2070,7 +2070,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
 }
 
 /* Return subqueue id on this core (one per core). */
-static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb,
+                                void *accel_priv)
 {
        return smp_processor_id();
 }
index 09ababe..8433de4 100644 (file)
@@ -299,7 +299,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
 
        if (vlan->fwd_priv) {
                skb->dev = vlan->lowerdev;
-               ret = dev_hard_start_xmit(skb, skb->dev, NULL, vlan->fwd_priv);
+               ret = dev_queue_xmit_accel(skb, vlan->fwd_priv);
        } else {
                ret = macvlan_queue_xmit(skb, dev);
        }
@@ -337,6 +337,8 @@ static const struct header_ops macvlan_hard_header_ops = {
        .cache_update   = eth_header_cache_update,
 };
 
+static struct rtnl_link_ops macvlan_link_ops;
+
 static int macvlan_open(struct net_device *dev)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
@@ -352,7 +354,8 @@ static int macvlan_open(struct net_device *dev)
                goto hash_add;
        }
 
-       if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) {
+       if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD &&
+           dev->rtnl_link_ops == &macvlan_link_ops) {
                vlan->fwd_priv =
                      lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev);
 
@@ -361,10 +364,8 @@ static int macvlan_open(struct net_device *dev)
                 */
                if (IS_ERR_OR_NULL(vlan->fwd_priv)) {
                        vlan->fwd_priv = NULL;
-               } else {
-                       dev->features &= ~NETIF_F_LLTX;
+               } else
                        return 0;
-               }
        }
 
        err = -EBUSY;
@@ -698,8 +699,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
        features = netdev_increment_features(vlan->lowerdev->features,
                                             features,
                                             mask);
-       if (!vlan->fwd_priv)
-               features |= NETIF_F_LLTX;
+       features |= NETIF_F_LLTX;
 
        return features;
 }
index 5d81c89..39794c4 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/phy.h>
+#include <linux/mdio.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
 
@@ -50,14 +51,17 @@ static void phy_device_release(struct device *dev)
        kfree(to_phy_device(dev));
 }
 
-static struct phy_driver genphy_driver;
+enum genphy_driver {
+       GENPHY_DRV_1G,
+       GENPHY_DRV_10G,
+       GENPHY_DRV_MAX
+};
+
+static struct phy_driver genphy_driver[GENPHY_DRV_MAX];
 
 static LIST_HEAD(phy_fixup_list);
 static DEFINE_MUTEX(phy_fixup_lock);
 
-static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
-                            u32 flags, phy_interface_t interface);
-
 /**
  * phy_register_fixup - creates a new phy_fixup and adds it to the list
  * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID)
@@ -560,13 +564,13 @@ EXPORT_SYMBOL(phy_init_hw);
  *
  * Description: Called by drivers to attach to a particular PHY
  *     device. The phy_device is found, and properly hooked up
- *     to the phy_driver.  If no driver is attached, then the
- *     genphy_driver is used.  The phy_device is given a ptr to
+ *     to the phy_driver.  If no driver is attached, then a
+ *     generic driver is used.  The phy_device is given a ptr to
  *     the attaching device, and given a callback for link status
  *     change.  The phy_device is returned to the attaching driver.
  */
-static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
-                            u32 flags, phy_interface_t interface)
+int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+                     u32 flags, phy_interface_t interface)
 {
        struct device *d = &phydev->dev;
        int err;
@@ -575,12 +579,10 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
         * exist, and we should use the genphy driver.
         */
        if (NULL == d->driver) {
-               if (phydev->is_c45) {
-                       pr_err("No driver for phy %x\n", phydev->phy_id);
-                       return -ENODEV;
-               }
-
-               d->driver = &genphy_driver.driver;
+               if (phydev->is_c45)
+                       d->driver = &genphy_driver[GENPHY_DRV_10G].driver;
+               else
+                       d->driver = &genphy_driver[GENPHY_DRV_1G].driver;
 
                err = d->driver->probe(d);
                if (err >= 0)
@@ -616,6 +618,7 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
 
        return err;
 }
+EXPORT_SYMBOL(phy_attach_direct);
 
 /**
  * phy_attach - attach a network device to a particular PHY device
@@ -658,6 +661,7 @@ EXPORT_SYMBOL(phy_attach);
  */
 void phy_detach(struct phy_device *phydev)
 {
+       int i;
        phydev->attached_dev->phydev = NULL;
        phydev->attached_dev = NULL;
        phy_suspend(phydev);
@@ -667,8 +671,12 @@ void phy_detach(struct phy_device *phydev)
         * from the generic driver so that there's a chance a
         * real driver could be loaded
         */
-       if (phydev->dev.driver == &genphy_driver.driver)
-               device_release_driver(&phydev->dev);
+       for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) {
+               if (phydev->dev.driver == &genphy_driver[i].driver) {
+                       device_release_driver(&phydev->dev);
+                       break;
+               }
+       }
 }
 EXPORT_SYMBOL(phy_detach);
 
@@ -759,6 +767,12 @@ static int genphy_config_advert(struct phy_device *phydev)
        return changed;
 }
 
+int gen10g_config_advert(struct phy_device *dev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(gen10g_config_advert);
+
 /**
  * genphy_setup_forced - configures/forces speed/duplex from @phydev
  * @phydev: target phy_device struct
@@ -806,6 +820,12 @@ int genphy_restart_aneg(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_restart_aneg);
 
+int gen10g_restart_aneg(struct phy_device *phydev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(gen10g_restart_aneg);
+
 /**
  * genphy_config_aneg - restart auto-negotiation or write BMCR
  * @phydev: target phy_device struct
@@ -847,6 +867,12 @@ int genphy_config_aneg(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_config_aneg);
 
+int gen10g_config_aneg(struct phy_device *phydev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(gen10g_config_aneg);
+
 /**
  * genphy_update_link - update link status in @phydev
  * @phydev: target phy_device struct
@@ -978,6 +1004,34 @@ int genphy_read_status(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_read_status);
 
+int gen10g_read_status(struct phy_device *phydev)
+{
+       int devad, reg;
+       u32 mmd_mask = phydev->c45_ids.devices_in_package;
+
+       phydev->link = 1;
+
+       /* For now just lie and say it's 10G all the time */
+       phydev->speed = SPEED_10000;
+       phydev->duplex = DUPLEX_FULL;
+
+       for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) {
+               if (!(mmd_mask & 1))
+                       continue;
+
+               /* Read twice because link state is latched and a
+                * read moves the current state into the register
+                */
+               phy_read_mmd(phydev, devad, MDIO_STAT1);
+               reg = phy_read_mmd(phydev, devad, MDIO_STAT1);
+               if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
+                       phydev->link = 0;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(gen10g_read_status);
+
 static int genphy_config_init(struct phy_device *phydev)
 {
        int val;
@@ -1023,6 +1077,16 @@ static int genphy_config_init(struct phy_device *phydev)
 
        return 0;
 }
+
+static int gen10g_config_init(struct phy_device *phydev)
+{
+       /* Temporarily just say we support everything */
+       phydev->supported = SUPPORTED_10000baseT_Full;
+       phydev->advertising = SUPPORTED_10000baseT_Full;
+
+       return 0;
+}
+
 int genphy_suspend(struct phy_device *phydev)
 {
        int value;
@@ -1038,6 +1102,12 @@ int genphy_suspend(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_suspend);
 
+int gen10g_suspend(struct phy_device *phydev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(gen10g_suspend);
+
 int genphy_resume(struct phy_device *phydev)
 {
        int value;
@@ -1053,6 +1123,12 @@ int genphy_resume(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_resume);
 
+int gen10g_resume(struct phy_device *phydev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(gen10g_resume);
+
 /**
  * phy_probe - probe and init a PHY device
  * @dev: device to probe and init
@@ -1173,7 +1249,8 @@ void phy_drivers_unregister(struct phy_driver *drv, int n)
 }
 EXPORT_SYMBOL(phy_drivers_unregister);
 
-static struct phy_driver genphy_driver = {
+static struct phy_driver genphy_driver[] = {
+{
        .phy_id         = 0xffffffff,
        .phy_id_mask    = 0xffffffff,
        .name           = "Generic PHY",
@@ -1184,7 +1261,18 @@ static struct phy_driver genphy_driver = {
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
        .driver         = { .owner = THIS_MODULE, },
-};
+}, {
+       .phy_id         = 0xffffffff,
+       .phy_id_mask    = 0xffffffff,
+       .name           = "Generic 10G PHY",
+       .config_init    = gen10g_config_init,
+       .features       = 0,
+       .config_aneg    = gen10g_config_aneg,
+       .read_status    = gen10g_read_status,
+       .suspend        = gen10g_suspend,
+       .resume         = gen10g_resume,
+       .driver         = {.owner = THIS_MODULE, },
+} };
 
 static int __init phy_init(void)
 {
@@ -1194,7 +1282,8 @@ static int __init phy_init(void)
        if (rc)
                return rc;
 
-       rc = phy_driver_register(&genphy_driver);
+       rc = phy_drivers_register(genphy_driver,
+                                 ARRAY_SIZE(genphy_driver));
        if (rc)
                mdio_bus_exit();
 
@@ -1203,7 +1292,8 @@ static int __init phy_init(void)
 
 static void __exit phy_exit(void)
 {
-       phy_driver_unregister(&genphy_driver);
+       phy_drivers_unregister(genphy_driver,
+                              ARRAY_SIZE(genphy_driver));
        mdio_bus_exit();
 }
 
index 736050d..b75ae5b 100644 (file)
@@ -1647,7 +1647,8 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 }
 
-static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb,
+                            void *accel_priv)
 {
        /*
         * This helper function exists to help dev_pick_tx get the correct
index 09f6662..34cca74 100644 (file)
@@ -364,7 +364,8 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
  * different rxq no. here. If we could not get rxhash, then we would
  * hope the rxq no. may help here.
  */
-static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
+                           void *accel_priv)
 {
        struct tun_struct *tun = netdev_priv(dev);
        struct tun_flow_entry *e;
index 47b0f73..6b638a0 100644 (file)
@@ -92,11 +92,12 @@ config USB_RTL8150
          module will be called rtl8150.
 
 config USB_RTL8152
-       tristate "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
+       tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
        select MII
        help
          This option adds support for Realtek RTL8152 based USB 2.0
-         10/100 Ethernet adapters.
+         10/100 Ethernet adapters and RTL8153 based USB 3.0 10/100/1000
+         Ethernet adapters.
 
          To compile this driver as a module, choose M here: the
          module will be called r8152.
index 640406a..7d32be8 100644 (file)
@@ -653,15 +653,6 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
-#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
-/* Samsung USB Ethernet Adapters */
-{
-       USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = 0,
-},
-#endif
-
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index bf7d549..31d13ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2013 Realtek Semiconductor Corp. All rights reserved.
+ *  Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -24,9 +24,9 @@
 #include <linux/ipv6.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v1.03.0 (2013/12/26)"
+#define DRIVER_VERSION "v1.04.0 (2014/01/15)"
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
-#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
+#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 #define MODULENAME "r8152"
 
 #define R8152_PHY_ID           32
@@ -450,6 +450,9 @@ enum rtl8152_flags {
 #define MCU_TYPE_PLA                   0x0100
 #define MCU_TYPE_USB                   0x0000
 
+#define REALTEK_USB_DEVICE(vend, prod) \
+       USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
+
 struct rx_desc {
        __le32 opts1;
 #define RX_LEN_MASK                    0x7fff
@@ -1100,40 +1103,28 @@ static void free_all_mem(struct r8152 *tp)
        int i;
 
        for (i = 0; i < RTL8152_MAX_RX; i++) {
-               if (tp->rx_info[i].urb) {
-                       usb_free_urb(tp->rx_info[i].urb);
-                       tp->rx_info[i].urb = NULL;
-               }
+               usb_free_urb(tp->rx_info[i].urb);
+               tp->rx_info[i].urb = NULL;
 
-               if (tp->rx_info[i].buffer) {
-                       kfree(tp->rx_info[i].buffer);
-                       tp->rx_info[i].buffer = NULL;
-                       tp->rx_info[i].head = NULL;
-               }
+               kfree(tp->rx_info[i].buffer);
+               tp->rx_info[i].buffer = NULL;
+               tp->rx_info[i].head = NULL;
        }
 
        for (i = 0; i < RTL8152_MAX_TX; i++) {
-               if (tp->tx_info[i].urb) {
-                       usb_free_urb(tp->tx_info[i].urb);
-                       tp->tx_info[i].urb = NULL;
-               }
+               usb_free_urb(tp->tx_info[i].urb);
+               tp->tx_info[i].urb = NULL;
 
-               if (tp->tx_info[i].buffer) {
-                       kfree(tp->tx_info[i].buffer);
-                       tp->tx_info[i].buffer = NULL;
-                       tp->tx_info[i].head = NULL;
-               }
+               kfree(tp->tx_info[i].buffer);
+               tp->tx_info[i].buffer = NULL;
+               tp->tx_info[i].head = NULL;
        }
 
-       if (tp->intr_urb) {
-               usb_free_urb(tp->intr_urb);
-               tp->intr_urb = NULL;
-       }
+       usb_free_urb(tp->intr_urb);
+       tp->intr_urb = NULL;
 
-       if (tp->intr_buff) {
-               kfree(tp->intr_buff);
-               tp->intr_buff = NULL;
-       }
+       kfree(tp->intr_buff);
+       tp->intr_buff = NULL;
 }
 
 static int alloc_all_mem(struct r8152 *tp)
@@ -2048,7 +2039,7 @@ static void r8153_first_init(struct r8152 *tp)
        /* TX share fifo free credit full threshold */
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2);
 
-       // rx aggregation
+       /* rx aggregation */
        ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
        ocp_data &= ~RX_AGG_DISABLE;
        ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
@@ -2750,11 +2741,6 @@ static int rtl8152_probe(struct usb_interface *intf,
        struct net_device *netdev;
        int ret;
 
-       if (udev->actconfig->desc.bConfigurationValue != 1) {
-               usb_driver_set_configuration(udev, 1);
-               return -ENODEV;
-       }
-
        netdev = alloc_etherdev(sizeof(struct r8152));
        if (!netdev) {
                dev_err(&intf->dev, "Out of memory\n");
@@ -2835,9 +2821,9 @@ static void rtl8152_disconnect(struct usb_interface *intf)
 
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8152_table[] = {
-       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
-       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
-       {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
+       {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
        {}
 };
 
index 5fd2ca6..f0a8791 100644 (file)
@@ -216,21 +216,13 @@ static const struct usb_device_id products[] = {
 {
        USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
-       .driver_info = 0,
-#else
        .driver_info = (unsigned long) &r8152_info,
-#endif
 },
 
 {
        USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
-       .driver_info = 0,
-#else
        .driver_info = (unsigned long) &r8153_info,
-#endif
 },
 
        { },            /* END */
index 56c175e..4671da7 100644 (file)
@@ -1244,7 +1244,7 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb)
                return -ENOMEM;
 
        urb->num_sgs = num_sgs;
-       sg_init_table(urb->sg, urb->num_sgs);
+       sg_init_table(urb->sg, urb->num_sgs + 1);
 
        sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb));
        total_len += skb_headlen(skb);
index 481f85d..a2dee80 100644 (file)
@@ -741,10 +741,9 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan,
                if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
                        return -EINVAL;
                *ifindex = nla_get_u32(tb[NDA_IFINDEX]);
-               tdev = dev_get_by_index(net, *ifindex);
+               tdev = __dev_get_by_index(net, *ifindex);
                if (!tdev)
                        return -EADDRNOTAVAIL;
-               dev_put(tdev);
        } else {
                *ifindex = 0;
        }
@@ -2656,6 +2655,44 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
        .fill_info      = vxlan_fill_info,
 };
 
+static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
+                                            struct net_device *dev)
+{
+       struct vxlan_dev *vxlan, *next;
+       LIST_HEAD(list_kill);
+
+       list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) {
+               struct vxlan_rdst *dst = &vxlan->default_dst;
+
+               /* In case we created vxlan device with carrier
+                * and we loose the carrier due to module unload
+                * we also need to remove vxlan device. In other
+                * cases, it's not necessary and remote_ifindex
+                * is 0 here, so no matches.
+                */
+               if (dst->remote_ifindex == dev->ifindex)
+                       vxlan_dellink(vxlan->dev, &list_kill);
+       }
+
+       unregister_netdevice_many(&list_kill);
+}
+
+static int vxlan_lowerdev_event(struct notifier_block *unused,
+                               unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
+
+       if (event == NETDEV_UNREGISTER)
+               vxlan_handle_lowerdev_unregister(vn, dev);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block vxlan_notifier_block __read_mostly = {
+       .notifier_call = vxlan_lowerdev_event,
+};
+
 static __net_init int vxlan_init_net(struct net *net)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
@@ -2673,13 +2710,13 @@ static __net_init int vxlan_init_net(struct net *net)
 static __net_exit void vxlan_exit_net(struct net *net)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
-       struct vxlan_dev *vxlan;
-       LIST_HEAD(list);
+       struct vxlan_dev *vxlan, *next;
+       LIST_HEAD(list_kill);
 
        rtnl_lock();
-       list_for_each_entry(vxlan, &vn->vxlan_list, next)
-               unregister_netdevice_queue(vxlan->dev, &list);
-       unregister_netdevice_many(&list);
+       list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next)
+               vxlan_dellink(vxlan->dev, &list_kill);
+       unregister_netdevice_many(&list_kill);
        rtnl_unlock();
 }
 
@@ -2704,12 +2741,17 @@ static int __init vxlan_init_module(void)
        if (rc)
                goto out1;
 
-       rc = rtnl_link_register(&vxlan_link_ops);
+       rc = register_netdevice_notifier(&vxlan_notifier_block);
        if (rc)
                goto out2;
 
-       return 0;
+       rc = rtnl_link_register(&vxlan_link_ops);
+       if (rc)
+               goto out3;
 
+       return 0;
+out3:
+       unregister_netdevice_notifier(&vxlan_notifier_block);
 out2:
        unregister_pernet_device(&vxlan_net_ops);
 out1:
@@ -2721,6 +2763,7 @@ late_initcall(vxlan_init_module);
 static void __exit vxlan_cleanup_module(void)
 {
        rtnl_link_unregister(&vxlan_link_ops);
+       unregister_netdevice_notifier(&vxlan_notifier_block);
        destroy_workqueue(vxlan_wq);
        unregister_pernet_device(&vxlan_net_ops);
        rcu_barrier();
index e4f539a..10963e8 100644 (file)
@@ -159,7 +159,7 @@ typedef struct {
 /* Packet Descriptor Status bits */
 
 #define ST_TX_EOM     0x80     /* End of frame */
-#define ST_TX_EOT     0x01     /* End of transmition */
+#define ST_TX_EOT     0x01     /* End of transmission */
 
 #define ST_RX_EOM     0x80     /* End of frame */
 #define ST_RX_SHORT   0x40     /* Short frame */
@@ -211,7 +211,7 @@ typedef struct {
 
 #define CTL_NORTS     0x01
 #define CTL_IDLE      0x10     /* Transmit an idle pattern */
-#define CTL_UDRNC     0x20     /* Idle after CRC or FCS+flag transmition */
+#define CTL_UDRNC     0x20     /* Idle after CRC or FCS+flag transmission */
 
 #define ST0_TXRDY     0x02     /* TX ready */
 #define ST0_RXRDY     0x01     /* RX ready */
index 96567c2..22137ee 100644 (file)
@@ -218,7 +218,7 @@ typedef struct {
 #define ST_TX_EOM     0x80     /* End of frame */
 #define ST_TX_UNDRRUN 0x08
 #define ST_TX_OWNRSHP 0x02
-#define ST_TX_EOT     0x01     /* End of transmition */
+#define ST_TX_EOT     0x01     /* End of transmission */
 
 #define ST_RX_EOM     0x80     /* End of frame */
 #define ST_RX_SHORT   0x40     /* Short frame */
index 1d40c69..55eda7a 100644 (file)
@@ -15,7 +15,6 @@
  * more details.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
index 14128fd..7e9ede6 100644 (file)
@@ -23,7 +23,6 @@
 #ifdef __IN_PCMCIA_PACKAGE__
 #include <pcmcia/k_compat.h>
 #endif
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
index 34c8a33..031d4ec 100644 (file)
@@ -1721,7 +1721,7 @@ static void at76_mac80211_tx(struct ieee80211_hw *hw,
         * following workaround is necessary. If the TX frame is an
         * authentication frame extract the bssid and send the CMD_JOIN. */
        if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) {
-               if (!ether_addr_equal(priv->bssid, mgmt->bssid)) {
+               if (!ether_addr_equal_64bits(priv->bssid, mgmt->bssid)) {
                        memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
                        ieee80211_queue_work(hw, &priv->work_join_bssid);
                        dev_kfree_skb_any(skb);
index 280fc3d..8aa20df 100644 (file)
@@ -25,7 +25,6 @@
  * that and only has minimal functionality.
  */
 #include <linux/compiler.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/list.h>
index 69f58b0..6396ad4 100644 (file)
@@ -1245,7 +1245,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,
 
        if (ieee80211_is_beacon(mgmt->frame_control) &&
            le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
-           ether_addr_equal(mgmt->bssid, common->curbssid)) {
+           ether_addr_equal_64bits(mgmt->bssid, common->curbssid)) {
                /*
                 * Received an IBSS beacon with the same BSSID. Hardware *must*
                 * have updated the local TSF. We have to work around various
@@ -1309,7 +1309,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi)
 
        /* only beacons from our BSSID */
        if (!ieee80211_is_beacon(mgmt->frame_control) ||
-           !ether_addr_equal(mgmt->bssid, common->curbssid))
+           !ether_addr_equal_64bits(mgmt->bssid, common->curbssid))
                return;
 
        ewma_add(&ah->ah_beacon_rssi_avg, rssi);
index 149aba3..d480d2f 100644 (file)
@@ -383,6 +383,20 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
        }
 }
 
+static void ar9002_hw_init_hang_checks(struct ath_hw *ah)
+{
+       if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
+               ah->config.hw_hang_checks |= HW_BB_RIFS_HANG;
+               ah->config.hw_hang_checks |= HW_BB_DFS_HANG;
+       }
+
+       if (AR_SREV_9280(ah))
+               ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG;
+
+       if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah))
+               ah->config.hw_hang_checks |= HW_MAC_HANG;
+}
+
 /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
 int ar9002_hw_attach_ops(struct ath_hw *ah)
 {
@@ -395,6 +409,7 @@ int ar9002_hw_attach_ops(struct ath_hw *ah)
                return ret;
 
        priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
+       priv_ops->init_hang_checks = ar9002_hw_init_hang_checks;
 
        ops->config_pci_powersave = ar9002_hw_configpcipowersave;
 
index 97e09d5..8c145cd 100644 (file)
@@ -326,6 +326,224 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
        ah->supp_cals = IQ_MISMATCH_CAL;
 }
 
+#define OFF_UPPER_LT 24
+#define OFF_LOWER_LT 7
+
+static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah,
+                                             bool txiqcal_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2,
+               dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3;
+       int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2,
+               dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3;
+       int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2,
+               dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3;
+       bool status;
+       u32 temp, val;
+
+       /*
+        * Clear offset and IQ calibration, run AGC cal.
+        */
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_OFFSET_CAL);
+       REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+                   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                 REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
+
+       status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                              AR_PHY_AGC_CONTROL_CAL,
+                              0, AH_WAIT_TIMEOUT);
+       if (!status) {
+               ath_dbg(common, CALIBRATE,
+                       "AGC cal without offset cal failed to complete in 1ms");
+               return false;
+       }
+
+       /*
+        * Allow only offset calibration and disable the others
+        * (Carrier Leak calibration, TX Filter calibration and
+        *  Peak Detector offset calibration).
+        */
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_OFFSET_CAL);
+       REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
+                   AR_PHY_CL_CAL_ENABLE);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_FLTR_CAL);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_PKDET_CAL);
+
+       ch0_done = 0;
+       ch1_done = 0;
+       ch2_done = 0;
+
+       while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) {
+               osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3;
+               osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3;
+               osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3;
+
+               REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+               REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                         REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
+
+               status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                      AR_PHY_AGC_CONTROL_CAL,
+                                      0, AH_WAIT_TIMEOUT);
+               if (!status) {
+                       ath_dbg(common, CALIBRATE,
+                               "DC offset cal failed to complete in 1ms");
+                       return false;
+               }
+
+               REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+               /*
+                * High gain.
+                */
+               REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8)));
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
+               dc_off_ch0_i1 = (temp >> 26) & 0x1f;
+               dc_off_ch0_q1 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
+               dc_off_ch1_i1 = (temp >> 26) & 0x1f;
+               dc_off_ch1_q1 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
+               dc_off_ch2_i1 = (temp >> 26) & 0x1f;
+               dc_off_ch2_q1 = (temp >> 21) & 0x1f;
+
+               /*
+                * Low gain.
+                */
+               REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8)));
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
+               dc_off_ch0_i2 = (temp >> 26) & 0x1f;
+               dc_off_ch0_q2 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
+               dc_off_ch1_i2 = (temp >> 26) & 0x1f;
+               dc_off_ch1_q2 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
+               dc_off_ch2_i2 = (temp >> 26) & 0x1f;
+               dc_off_ch2_q2 = (temp >> 21) & 0x1f;
+
+               /*
+                * Loopback.
+                */
+               REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8)));
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
+               dc_off_ch0_i3 = (temp >> 26) & 0x1f;
+               dc_off_ch0_q3 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
+               dc_off_ch1_i3 = (temp >> 26) & 0x1f;
+               dc_off_ch1_q3 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
+               dc_off_ch2_i3 = (temp >> 26) & 0x1f;
+               dc_off_ch2_q3 = (temp >> 21) & 0x1f;
+
+               if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) {
+                       if (osdac_ch0 == 3) {
+                               ch0_done = 1;
+                       } else {
+                               osdac_ch0++;
+
+                               val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff;
+                               val |= (osdac_ch0 << 30);
+                               REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val);
+
+                               ch0_done = 0;
+                       }
+               } else {
+                       ch0_done = 1;
+               }
+
+               if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) {
+                       if (osdac_ch1 == 3) {
+                               ch1_done = 1;
+                       } else {
+                               osdac_ch1++;
+
+                               val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff;
+                               val |= (osdac_ch1 << 30);
+                               REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val);
+
+                               ch1_done = 0;
+                       }
+               } else {
+                       ch1_done = 1;
+               }
+
+               if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) {
+                       if (osdac_ch2 == 3) {
+                               ch2_done = 1;
+                       } else {
+                               osdac_ch2++;
+
+                               val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff;
+                               val |= (osdac_ch2 << 30);
+                               REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val);
+
+                               ch2_done = 0;
+                       }
+               } else {
+                       ch2_done = 1;
+               }
+       }
+
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_OFFSET_CAL);
+       REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+       /*
+        * We don't need to check txiqcal_done here since it is always
+        * set for AR9550.
+        */
+       REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+                   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
+
+       return true;
+}
+
 /*
  * solve 4x4 linear equation used in loopback iq cal.
  */
@@ -1271,6 +1489,11 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
        }
 
+       if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) {
+               if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done))
+                       return false;
+       }
+
 skip_tx_iqcal:
        if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
                if (AR_SREV_9330_11(ah))
index c8d22ec..25243cb 100644 (file)
@@ -3598,7 +3598,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
        if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
                REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
                                AR_SWITCH_TABLE_COM_AR9462_ALL, value);
-       } else if (AR_SREV_9550(ah)) {
+       } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
                                AR_SWITCH_TABLE_COM_AR9550_ALL, value);
        } else
@@ -3975,7 +3975,7 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
        u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0];
 
-       if (AR_SREV_9340(ah))
+       if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
                return;
 
        if (eep->baseEepHeader.featureEnable & 0x40) {
@@ -4030,7 +4030,10 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz)
        if (!(eep->baseEepHeader.featureEnable & 0x80))
                return;
 
-       if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah))
+       if (!AR_SREV_9300(ah) &&
+           !AR_SREV_9340(ah) &&
+           !AR_SREV_9580(ah) &&
+           !AR_SREV_9531(ah))
                return;
 
        xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn;
@@ -4163,7 +4166,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        ar9003_hw_xlna_bias_strength_apply(ah, is2ghz);
        ar9003_hw_atten_apply(ah, chan);
        ar9003_hw_quick_drop_apply(ah, chan->channel);
-       if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
+       if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
                ar9003_hw_internal_regulator_apply(ah);
        ar9003_hw_apply_tuning_caps(ah);
        ar9003_hw_apply_minccapwr_thresh(ah, chan);
@@ -4788,7 +4791,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah,
        }
 
 tempslope:
-       if (AR_SREV_9550(ah)) {
+       if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                /*
                 * AR955x has tempSlope register for each chain.
                 * Check whether temp_compensation feature is enabled or not.
index 29613eb..ec1da0c 100644 (file)
@@ -28,6 +28,7 @@
 #include "ar9462_2p1_initvals.h"
 #include "ar9565_1p0_initvals.h"
 #include "ar9565_1p1_initvals.h"
+#include "ar953x_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
 
@@ -308,6 +309,31 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                /* Fast clock modal settings */
                INIT_INI_ARRAY(&ah->iniModesFastClock,
                                ar955x_1p0_modes_fast_clock);
+       } else if (AR_SREV_9531(ah)) {
+               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+                              qca953x_1p0_mac_core);
+               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+                              qca953x_1p0_mac_postamble);
+               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+                              qca953x_1p0_baseband_core);
+               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+                              qca953x_1p0_baseband_postamble);
+               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+                              qca953x_1p0_radio_core);
+               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+                              qca953x_1p0_radio_postamble);
+               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+                              qca953x_1p0_soc_preamble);
+               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+                              qca953x_1p0_soc_postamble);
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              qca953x_1p0_common_wo_xlna_rx_gain_table);
+               INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+                              qca953x_1p0_common_wo_xlna_rx_gain_bounds);
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              qca953x_1p0_modes_no_xpa_tx_gain_table);
+               INIT_INI_ARRAY(&ah->iniModesFastClock,
+                              qca953x_1p0_modes_fast_clock);
        } else if (AR_SREV_9580(ah)) {
                /* mac */
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -485,6 +511,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
        else if (AR_SREV_9550(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar955x_1p0_modes_xpa_tx_gain_table);
+       else if (AR_SREV_9531(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       qca953x_1p0_modes_xpa_tx_gain_table);
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_lowest_ob_db_tx_gain_table);
@@ -525,7 +554,14 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
        else if (AR_SREV_9550(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar955x_1p0_modes_no_xpa_tx_gain_table);
-       else if (AR_SREV_9462_21(ah))
+       else if (AR_SREV_9531(ah)) {
+               if (AR_SREV_9531_11(ah))
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                                      qca953x_1p1_modes_no_xpa_tx_gain_table);
+               else
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                                      qca953x_1p0_modes_no_xpa_tx_gain_table);
+       } else if (AR_SREV_9462_21(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9462_2p1_modes_high_ob_db_tx_gain);
        else if (AR_SREV_9462_20(ah))
@@ -699,6 +735,11 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
                                ar955x_1p0_common_rx_gain_table);
                INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
                                ar955x_1p0_common_rx_gain_bounds);
+       } else if (AR_SREV_9531(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              qca953x_1p0_common_rx_gain_table);
+               INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+                              qca953x_1p0_common_rx_gain_bounds);
        } else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar9580_1p0_rx_gain_table);
@@ -744,6 +785,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
                        ar955x_1p0_common_wo_xlna_rx_gain_table);
                INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
                        ar955x_1p0_common_wo_xlna_rx_gain_bounds);
+       } else if (AR_SREV_9531(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              qca953x_1p0_common_wo_xlna_rx_gain_table);
+               INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+                              qca953x_1p0_common_wo_xlna_rx_gain_bounds);
        } else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9580_1p0_wo_xlna_rx_gain_table);
@@ -872,6 +918,117 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
        }
 }
 
+static void ar9003_hw_init_hang_checks(struct ath_hw *ah)
+{
+       /*
+        * All chips support detection of BB/MAC hangs.
+        */
+       ah->config.hw_hang_checks |= HW_BB_WATCHDOG;
+       ah->config.hw_hang_checks |= HW_MAC_HANG;
+
+       /*
+        * This is not required for AR9580 1.0
+        */
+       if (AR_SREV_9300_22(ah))
+               ah->config.hw_hang_checks |= HW_PHYRESTART_CLC_WAR;
+
+       if (AR_SREV_9330(ah))
+               ah->bb_watchdog_timeout_ms = 85;
+       else
+               ah->bb_watchdog_timeout_ms = 25;
+}
+
+/*
+ * MAC HW hang check
+ * =================
+ *
+ * Signature: dcu_chain_state is 0x6 and dcu_complete_state is 0x1.
+ *
+ * The state of each DCU chain (mapped to TX queues) is available from these
+ * DMA debug registers:
+ *
+ * Chain 0 state : Bits 4:0   of AR_DMADBG_4
+ * Chain 1 state : Bits 9:5   of AR_DMADBG_4
+ * Chain 2 state : Bits 14:10 of AR_DMADBG_4
+ * Chain 3 state : Bits 19:15 of AR_DMADBG_4
+ * Chain 4 state : Bits 24:20 of AR_DMADBG_4
+ * Chain 5 state : Bits 29:25 of AR_DMADBG_4
+ * Chain 6 state : Bits 4:0   of AR_DMADBG_5
+ * Chain 7 state : Bits 9:5   of AR_DMADBG_5
+ * Chain 8 state : Bits 14:10 of AR_DMADBG_5
+ * Chain 9 state : Bits 19:15 of AR_DMADBG_5
+ *
+ * The DCU chain state "0x6" means "WAIT_FRDONE" - wait for TX frame to be done.
+ */
+
+#define NUM_STATUS_READS 50
+
+static bool ath9k_hw_verify_hang(struct ath_hw *ah, unsigned int queue)
+{
+       u32 dma_dbg_chain, dma_dbg_complete;
+       u8 dcu_chain_state, dcu_complete_state;
+       int i;
+
+       for (i = 0; i < NUM_STATUS_READS; i++) {
+               if (queue < 6)
+                       dma_dbg_chain = REG_READ(ah, AR_DMADBG_4);
+               else
+                       dma_dbg_chain = REG_READ(ah, AR_DMADBG_5);
+
+               dma_dbg_complete = REG_READ(ah, AR_DMADBG_6);
+
+               dcu_chain_state = (dma_dbg_chain >> (5 * queue)) & 0x1f;
+               dcu_complete_state = dma_dbg_complete & 0x3;
+
+               if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1))
+                       return false;
+       }
+
+       ath_dbg(ath9k_hw_common(ah), RESET,
+               "MAC Hang signature found for queue: %d\n", queue);
+
+       return true;
+}
+
+static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah)
+{
+       u32 dma_dbg_4, dma_dbg_5, dma_dbg_6, chk_dbg;
+       u8 dcu_chain_state, dcu_complete_state;
+       bool dcu_wait_frdone = false;
+       unsigned long chk_dcu = 0;
+       unsigned int i = 0;
+
+       dma_dbg_4 = REG_READ(ah, AR_DMADBG_4);
+       dma_dbg_5 = REG_READ(ah, AR_DMADBG_5);
+       dma_dbg_6 = REG_READ(ah, AR_DMADBG_6);
+
+       dcu_complete_state = dma_dbg_6 & 0x3;
+       if (dcu_complete_state != 0x1)
+               goto exit;
+
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+               if (i < 6)
+                       chk_dbg = dma_dbg_4;
+               else
+                       chk_dbg = dma_dbg_5;
+
+               dcu_chain_state = (chk_dbg >> (5 * i)) & 0x1f;
+               if (dcu_chain_state == 0x6) {
+                       dcu_wait_frdone = true;
+                       chk_dcu |= BIT(i);
+               }
+       }
+
+       if ((dcu_complete_state == 0x1) && dcu_wait_frdone) {
+               for_each_set_bit(i, &chk_dcu, ATH9K_NUM_TX_QUEUES) {
+                       if (ath9k_hw_verify_hang(ah, i))
+                               return true;
+               }
+       }
+exit:
+       return false;
+}
+
 /* Sets up the AR9003 hardware familiy callbacks */
 void ar9003_hw_attach_ops(struct ath_hw *ah)
 {
@@ -880,6 +1037,8 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
 
        ar9003_hw_init_mode_regs(ah);
        priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
+       priv_ops->init_hang_checks = ar9003_hw_init_hang_checks;
+       priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang;
 
        ops->config_pci_powersave = ar9003_hw_configpcipowersave;
 
index 9f051a0..09facba 100644 (file)
@@ -103,7 +103,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
                        } else {
                                channelSel = CHANSEL_2G(freq) >> 1;
                        }
-               } else if (AR_SREV_9550(ah)) {
+               } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                        if (ah->is_clk_25mhz)
                                div = 75;
                        else
@@ -118,7 +118,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
                /* Set to 2G mode */
                bMode = 1;
        } else {
-               if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
+               if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) &&
                    ah->is_clk_25mhz) {
                        channelSel = freq / 75;
                        chan_frac = ((freq % 75) * 0x20000) / 75;
@@ -810,10 +810,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        /*
         * TXGAIN initvals.
         */
-       if (AR_SREV_9550(ah)) {
-               int modes_txgain_index;
+       if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+               int modes_txgain_index = 1;
+
+               if (AR_SREV_9550(ah))
+                       modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);
 
-               modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);
                if (modes_txgain_index < 0)
                        return -EINVAL;
 
@@ -1814,6 +1816,68 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
        memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
 }
 
+/*
+ * Baseband Watchdog signatures:
+ *
+ * 0x04000539: BB hang when operating in HT40 DFS Channel.
+ *             Full chip reset is not required, but a recovery
+ *             mechanism is needed.
+ *
+ * 0x1300000a: Related to CAC deafness.
+ *             Chip reset is not required.
+ *
+ * 0x0400000a: Related to CAC deafness.
+ *             Full chip reset is required.
+ *
+ * 0x04000b09: RX state machine gets into an illegal state
+ *             when a packet with unsupported rate is received.
+ *             Full chip reset is required and PHY_RESTART has
+ *             to be disabled.
+ *
+ * 0x04000409: Packet stuck on receive.
+ *             Full chip reset is required for all chips except AR9340.
+ */
+
+/*
+ * ar9003_hw_bb_watchdog_check(): Returns true if a chip reset is required.
+ */
+bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah)
+{
+       u32 val;
+
+       switch(ah->bb_watchdog_last_status) {
+       case 0x04000539:
+               val = REG_READ(ah, AR_PHY_RADAR_0);
+               val &= (~AR_PHY_RADAR_0_FIRPWR);
+               val |= SM(0x7f, AR_PHY_RADAR_0_FIRPWR);
+               REG_WRITE(ah, AR_PHY_RADAR_0, val);
+               udelay(1);
+               val = REG_READ(ah, AR_PHY_RADAR_0);
+               val &= ~AR_PHY_RADAR_0_FIRPWR;
+               val |= SM(AR9300_DFS_FIRPWR, AR_PHY_RADAR_0_FIRPWR);
+               REG_WRITE(ah, AR_PHY_RADAR_0, val);
+
+               return false;
+       case 0x1300000a:
+               return false;
+       case 0x0400000a:
+       case 0x04000b09:
+               return true;
+       case 0x04000409:
+               if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
+                       return false;
+               else
+                       return true;
+       default:
+               /*
+                * For any other unknown signatures, do a
+                * full chip reset.
+                */
+               return true;
+       }
+}
+EXPORT_SYMBOL(ar9003_hw_bb_watchdog_check);
+
 void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1930,6 +1994,7 @@ EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
 
 void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
 {
+       u8 result;
        u32 val;
 
        /* While receiving unsupported rate frame rx state machine
@@ -1937,15 +2002,13 @@ void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
         * state, BB would go hang. If RXSM is in 0xb state after
         * first bb panic, ensure to disable the phy_restart.
         */
-       if (!((MS(ah->bb_watchdog_last_status,
-                 AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) ||
-           ah->bb_hang_rx_ofdm))
-               return;
-
-       ah->bb_hang_rx_ofdm = true;
-       val = REG_READ(ah, AR_PHY_RESTART);
-       val &= ~AR_PHY_RESTART_ENA;
+       result = MS(ah->bb_watchdog_last_status, AR_PHY_WATCHDOG_RX_OFDM_SM);
 
-       REG_WRITE(ah, AR_PHY_RESTART, val);
+       if ((result == 0xb) || ah->bb_hang_rx_ofdm) {
+               ah->bb_hang_rx_ofdm = true;
+               val = REG_READ(ah, AR_PHY_RESTART);
+               val &= ~AR_PHY_RESTART_ENA;
+               REG_WRITE(ah, AR_PHY_RESTART, val);
+       }
 }
 EXPORT_SYMBOL(ar9003_hw_disable_phy_restart);
index 1b44171..fd090b1 100644 (file)
 #define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115
 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125
 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125
-#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95
-#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100
-
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -60
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -60
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ -95
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ -100
 
 #define AR_PHY_65NM_CH1_RXTX4       0x1650c
 #define AR_PHY_65NM_CH2_RXTX4       0x1690c
 
+#define AR_PHY_65NM_CH0_BB1         0x16140
+#define AR_PHY_65NM_CH0_BB2         0x16144
+#define AR_PHY_65NM_CH0_BB3         0x16148
+#define AR_PHY_65NM_CH1_BB1         0x16540
+#define AR_PHY_65NM_CH1_BB2         0x16544
+#define AR_PHY_65NM_CH1_BB3         0x16548
+#define AR_PHY_65NM_CH2_BB1         0x16940
+#define AR_PHY_65NM_CH2_BB2         0x16944
+#define AR_PHY_65NM_CH2_BB3         0x16948
+
 #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3           0x00780000
 #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S         19
 #define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK         0x00000004
 #define AR_PHY_65NM_RXRF_AGC_AGC_OUT                   0x00000004
 #define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S                 2
 
+#define AR9300_DFS_FIRPWR -28
+
 #endif  /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
new file mode 100644 (file)
index 0000000..3c9113d
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros 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 INITVALS_953X_H
+#define INITVALS_953X_H
+
+#define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble
+
+#define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble
+
+#define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2
+
+#define qca953x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
+
+#define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2
+
+static const u32 qca953x_1p0_mac_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00000008, 0x00000000},
+       {0x00000030, 0x00020085},
+       {0x00000034, 0x00000005},
+       {0x00000040, 0x00000000},
+       {0x00000044, 0x00000000},
+       {0x00000048, 0x00000008},
+       {0x0000004c, 0x00000010},
+       {0x00000050, 0x00000000},
+       {0x00001040, 0x002ffc0f},
+       {0x00001044, 0x002ffc0f},
+       {0x00001048, 0x002ffc0f},
+       {0x0000104c, 0x002ffc0f},
+       {0x00001050, 0x002ffc0f},
+       {0x00001054, 0x002ffc0f},
+       {0x00001058, 0x002ffc0f},
+       {0x0000105c, 0x002ffc0f},
+       {0x00001060, 0x002ffc0f},
+       {0x00001064, 0x002ffc0f},
+       {0x000010f0, 0x00000100},
+       {0x00001270, 0x00000000},
+       {0x000012b0, 0x00000000},
+       {0x000012f0, 0x00000000},
+       {0x0000143c, 0x00000000},
+       {0x0000147c, 0x00000000},
+       {0x00008000, 0x00000000},
+       {0x00008004, 0x00000000},
+       {0x00008008, 0x00000000},
+       {0x0000800c, 0x00000000},
+       {0x00008018, 0x00000000},
+       {0x00008020, 0x00000000},
+       {0x00008038, 0x00000000},
+       {0x0000803c, 0x00000000},
+       {0x00008040, 0x00000000},
+       {0x00008044, 0x00000000},
+       {0x00008048, 0x00000000},
+       {0x0000804c, 0xffffffff},
+       {0x00008054, 0x00000000},
+       {0x00008058, 0x00000000},
+       {0x0000805c, 0x000fc78f},
+       {0x00008060, 0x0000000f},
+       {0x00008064, 0x00000000},
+       {0x00008070, 0x00000310},
+       {0x00008074, 0x00000020},
+       {0x00008078, 0x00000000},
+       {0x0000809c, 0x0000000f},
+       {0x000080a0, 0x00000000},
+       {0x000080a4, 0x02ff0000},
+       {0x000080a8, 0x0e070605},
+       {0x000080ac, 0x0000000d},
+       {0x000080b0, 0x00000000},
+       {0x000080b4, 0x00000000},
+       {0x000080b8, 0x00000000},
+       {0x000080bc, 0x00000000},
+       {0x000080c0, 0x2a800000},
+       {0x000080c4, 0x06900168},
+       {0x000080c8, 0x13881c22},
+       {0x000080cc, 0x01f40000},
+       {0x000080d0, 0x00252500},
+       {0x000080d4, 0x00a00000},
+       {0x000080d8, 0x00400000},
+       {0x000080dc, 0x00000000},
+       {0x000080e0, 0xffffffff},
+       {0x000080e4, 0x0000ffff},
+       {0x000080e8, 0x3f3f3f3f},
+       {0x000080ec, 0x00000000},
+       {0x000080f0, 0x00000000},
+       {0x000080f4, 0x00000000},
+       {0x000080fc, 0x00020000},
+       {0x00008100, 0x00000000},
+       {0x00008108, 0x00000052},
+       {0x0000810c, 0x00000000},
+       {0x00008110, 0x00000000},
+       {0x00008114, 0x000007ff},
+       {0x00008118, 0x000000aa},
+       {0x0000811c, 0x00003210},
+       {0x00008124, 0x00000000},
+       {0x00008128, 0x00000000},
+       {0x0000812c, 0x00000000},
+       {0x00008130, 0x00000000},
+       {0x00008134, 0x00000000},
+       {0x00008138, 0x00000000},
+       {0x0000813c, 0x0000ffff},
+       {0x00008140, 0x000000fe},
+       {0x00008144, 0xffffffff},
+       {0x00008168, 0x00000000},
+       {0x0000816c, 0x00000000},
+       {0x000081c0, 0x00000000},
+       {0x000081c4, 0x33332210},
+       {0x000081ec, 0x00000000},
+       {0x000081f0, 0x00000000},
+       {0x000081f4, 0x00000000},
+       {0x000081f8, 0x00000000},
+       {0x000081fc, 0x00000000},
+       {0x00008240, 0x00100000},
+       {0x00008244, 0x0010f3d7},
+       {0x00008248, 0x00000852},
+       {0x0000824c, 0x0001e7ae},
+       {0x00008250, 0x00000000},
+       {0x00008254, 0x00000000},
+       {0x00008258, 0x00000000},
+       {0x0000825c, 0x40000000},
+       {0x00008260, 0x00080922},
+       {0x00008264, 0x9d400010},
+       {0x00008268, 0xffffffff},
+       {0x0000826c, 0x0000ffff},
+       {0x00008270, 0x00000000},
+       {0x00008274, 0x40000000},
+       {0x00008278, 0x003e4180},
+       {0x0000827c, 0x00000004},
+       {0x00008284, 0x0000002c},
+       {0x00008288, 0x0000002c},
+       {0x0000828c, 0x000000ff},
+       {0x00008294, 0x00000000},
+       {0x00008298, 0x00000000},
+       {0x0000829c, 0x00000000},
+       {0x00008300, 0x00001d40},
+       {0x00008314, 0x00000000},
+       {0x0000831c, 0x0000010d},
+       {0x00008328, 0x00000000},
+       {0x0000832c, 0x0000001f},
+       {0x00008330, 0x00000302},
+       {0x00008334, 0x00000700},
+       {0x00008338, 0xffff0000},
+       {0x0000833c, 0x02400000},
+       {0x00008340, 0x000107ff},
+       {0x00008344, 0xaa48107b},
+       {0x00008348, 0x008f0000},
+       {0x0000835c, 0x00000000},
+       {0x00008360, 0xffffffff},
+       {0x00008364, 0xffffffff},
+       {0x00008368, 0x00000000},
+       {0x00008370, 0x00000000},
+       {0x00008374, 0x000000ff},
+       {0x00008378, 0x00000000},
+       {0x0000837c, 0x00000000},
+       {0x00008380, 0xffffffff},
+       {0x00008384, 0xffffffff},
+       {0x00008390, 0xffffffff},
+       {0x00008394, 0xffffffff},
+       {0x00008398, 0x00000000},
+       {0x0000839c, 0x00000000},
+       {0x000083a0, 0x00000000},
+       {0x000083a4, 0x0000fa14},
+       {0x000083a8, 0x000f0c00},
+       {0x000083ac, 0x33332210},
+       {0x000083b0, 0x33332210},
+       {0x000083b4, 0x33332210},
+       {0x000083b8, 0x33332210},
+       {0x000083bc, 0x00000000},
+       {0x000083c0, 0x00000000},
+       {0x000083c4, 0x00000000},
+       {0x000083c8, 0x00000000},
+       {0x000083cc, 0x00000200},
+       {0x000083d0, 0x8c7901ff},
+};
+
+static const u32 qca953x_1p0_baseband_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00009800, 0xafe68e30},
+       {0x00009804, 0xfd14e000},
+       {0x00009808, 0x9c0a9f6b},
+       {0x0000980c, 0x04900000},
+       {0x00009814, 0x0280c00a},
+       {0x00009818, 0x00000000},
+       {0x0000981c, 0x00020028},
+       {0x00009834, 0x6400a190},
+       {0x00009838, 0x0108ecff},
+       {0x0000983c, 0x14000600},
+       {0x00009880, 0x201fff00},
+       {0x00009884, 0x00001042},
+       {0x000098a4, 0x00200400},
+       {0x000098b0, 0x32840bbe},
+       {0x000098bc, 0x00000002},
+       {0x000098d0, 0x004b6a8e},
+       {0x000098d4, 0x00000820},
+       {0x000098dc, 0x00000000},
+       {0x000098f0, 0x00000000},
+       {0x000098f4, 0x00000000},
+       {0x00009c04, 0xff55ff55},
+       {0x00009c08, 0x0320ff55},
+       {0x00009c0c, 0x00000000},
+       {0x00009c10, 0x00000000},
+       {0x00009c14, 0x00046384},
+       {0x00009c18, 0x05b6b440},
+       {0x00009c1c, 0x00b6b440},
+       {0x00009d00, 0xc080a333},
+       {0x00009d04, 0x40206c10},
+       {0x00009d08, 0x009c4060},
+       {0x00009d0c, 0x9883800a},
+       {0x00009d10, 0x01884061},
+       {0x00009d14, 0x00c0040b},
+       {0x00009d18, 0x00000000},
+       {0x00009e08, 0x0038230c},
+       {0x00009e24, 0x990bb515},
+       {0x00009e28, 0x0c6f0000},
+       {0x00009e30, 0x06336f77},
+       {0x00009e34, 0x6af6532f},
+       {0x00009e38, 0x0cc80c00},
+       {0x00009e40, 0x0d261820},
+       {0x00009e4c, 0x00001004},
+       {0x00009e50, 0x00ff03f1},
+       {0x00009fc0, 0x813e4788},
+       {0x00009fc4, 0x0001efb5},
+       {0x00009fcc, 0x40000014},
+       {0x00009fd0, 0x01193b91},
+       {0x0000a20c, 0x00000000},
+       {0x0000a220, 0x00000000},
+       {0x0000a224, 0x00000000},
+       {0x0000a228, 0x10002310},
+       {0x0000a23c, 0x00000000},
+       {0x0000a244, 0x0c000000},
+       {0x0000a248, 0x00000140},
+       {0x0000a2a0, 0x00000007},
+       {0x0000a2c0, 0x00000007},
+       {0x0000a2c8, 0x00000000},
+       {0x0000a2d4, 0x00000000},
+       {0x0000a2ec, 0x00000000},
+       {0x0000a2f0, 0x00000000},
+       {0x0000a2f4, 0x00000000},
+       {0x0000a2f8, 0x00000000},
+       {0x0000a344, 0x00000000},
+       {0x0000a34c, 0x00000000},
+       {0x0000a350, 0x0000a000},
+       {0x0000a364, 0x00000000},
+       {0x0000a370, 0x00000000},
+       {0x0000a390, 0x00000001},
+       {0x0000a394, 0x00000444},
+       {0x0000a398, 0x1f020503},
+       {0x0000a39c, 0x29180c03},
+       {0x0000a3a0, 0x9a8b6844},
+       {0x0000a3a4, 0x000000ff},
+       {0x0000a3a8, 0x6a6a6a6a},
+       {0x0000a3ac, 0x6a6a6a6a},
+       {0x0000a3b0, 0x00c8641a},
+       {0x0000a3b4, 0x0000001a},
+       {0x0000a3b8, 0x0088642a},
+       {0x0000a3bc, 0x000001fa},
+       {0x0000a3c0, 0x20202020},
+       {0x0000a3c4, 0x22222220},
+       {0x0000a3c8, 0x20200020},
+       {0x0000a3cc, 0x20202020},
+       {0x0000a3d0, 0x20202020},
+       {0x0000a3d4, 0x20202020},
+       {0x0000a3d8, 0x20202020},
+       {0x0000a3dc, 0x20202020},
+       {0x0000a3e0, 0x20202020},
+       {0x0000a3e4, 0x20202020},
+       {0x0000a3e8, 0x20202020},
+       {0x0000a3ec, 0x20202020},
+       {0x0000a3f0, 0x00000000},
+       {0x0000a3f4, 0x00000000},
+       {0x0000a3f8, 0x0c9bd380},
+       {0x0000a3fc, 0x000f0f01},
+       {0x0000a400, 0x8fa91f01},
+       {0x0000a404, 0x00000000},
+       {0x0000a408, 0x0e79e5c6},
+       {0x0000a40c, 0x00820820},
+       {0x0000a414, 0x1ce42108},
+       {0x0000a418, 0x2d001dce},
+       {0x0000a41c, 0x1ce73908},
+       {0x0000a420, 0x000001ce},
+       {0x0000a424, 0x1ce738e7},
+       {0x0000a428, 0x000001ce},
+       {0x0000a42c, 0x1ce739ce},
+       {0x0000a430, 0x1ce739ce},
+       {0x0000a434, 0x00000000},
+       {0x0000a438, 0x00001801},
+       {0x0000a43c, 0x00100000},
+       {0x0000a444, 0x00000000},
+       {0x0000a448, 0x05000080},
+       {0x0000a44c, 0x00000001},
+       {0x0000a450, 0x00010000},
+       {0x0000a458, 0x00000000},
+       {0x0000a644, 0xbfad9d74},
+       {0x0000a648, 0x0048060a},
+       {0x0000a64c, 0x00003c37},
+       {0x0000a670, 0x03020100},
+       {0x0000a674, 0x09080504},
+       {0x0000a678, 0x0d0c0b0a},
+       {0x0000a67c, 0x13121110},
+       {0x0000a680, 0x31301514},
+       {0x0000a684, 0x35343332},
+       {0x0000a688, 0x00000036},
+       {0x0000a690, 0x08000838},
+       {0x0000a7cc, 0x00000000},
+       {0x0000a7d0, 0x00000000},
+       {0x0000a7d4, 0x00000004},
+       {0x0000a7dc, 0x00000000},
+       {0x0000a8d0, 0x004b6a8e},
+       {0x0000a8d4, 0x00000820},
+       {0x0000a8dc, 0x00000000},
+       {0x0000a8f0, 0x00000000},
+       {0x0000a8f4, 0x00000000},
+       {0x0000b2d0, 0x00000080},
+       {0x0000b2d4, 0x00000000},
+       {0x0000b2ec, 0x00000000},
+       {0x0000b2f0, 0x00000000},
+       {0x0000b2f4, 0x00000000},
+       {0x0000b2f8, 0x00000000},
+       {0x0000b408, 0x0e79e5c0},
+       {0x0000b40c, 0x00820820},
+       {0x0000b420, 0x00000000},
+};
+
+static const u32 qca953x_1p0_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},
+       {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, 0x3379605e, 0x33795d5e},
+       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+       {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822},
+       {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+       {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+       {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
+       {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+       {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
+       {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+       {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+       {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
+       {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+       {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+       {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
+       {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
+       {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+       {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+       {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+       {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+       {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
+       {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
+       {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
+       {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+       {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+       {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+};
+
+static const u32 qca953x_1p0_radio_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00016000, 0x36db6db6},
+       {0x00016004, 0x6db6db40},
+       {0x00016008, 0x73f00000},
+       {0x0001600c, 0x00000000},
+       {0x00016040, 0x3f80fff8},
+       {0x0001604c, 0x000f0278},
+       {0x00016050, 0x8036db6c},
+       {0x00016054, 0x6db60000},
+       {0x00016080, 0x00080000},
+       {0x00016084, 0x0e48048c},
+       {0x00016088, 0x14214514},
+       {0x0001608c, 0x119f080a},
+       {0x00016090, 0x24926490},
+       {0x00016094, 0x00000000},
+       {0x000160a0, 0xc2108ffe},
+       {0x000160a4, 0x812fc370},
+       {0x000160a8, 0x423c8000},
+       {0x000160b4, 0x92480080},
+       {0x000160c0, 0x006db6d8},
+       {0x000160c4, 0x24b6db6c},
+       {0x000160c8, 0x6db6db6c},
+       {0x000160cc, 0x6db6fb7c},
+       {0x000160d0, 0x6db6da44},
+       {0x00016100, 0x07ff8001},
+       {0x00016108, 0x00080010},
+       {0x00016144, 0x01884080},
+       {0x00016148, 0x000080d8},
+       {0x00016280, 0x01000901},
+       {0x00016284, 0x15d30000},
+       {0x00016288, 0x00318000},
+       {0x0001628c, 0x50000000},
+       {0x00016380, 0x00000000},
+       {0x00016384, 0x00000000},
+       {0x00016388, 0x00800700},
+       {0x0001638c, 0x00800700},
+       {0x00016390, 0x00800700},
+       {0x00016394, 0x00000000},
+       {0x00016398, 0x00000000},
+       {0x0001639c, 0x00000000},
+       {0x000163a0, 0x00000001},
+       {0x000163a4, 0x00000001},
+       {0x000163a8, 0x00000000},
+       {0x000163ac, 0x00000000},
+       {0x000163b0, 0x00000000},
+       {0x000163b4, 0x00000000},
+       {0x000163b8, 0x00000000},
+       {0x000163bc, 0x00000000},
+       {0x000163c0, 0x000000a0},
+       {0x000163c4, 0x000c0000},
+       {0x000163c8, 0x14021402},
+       {0x000163cc, 0x00001402},
+       {0x000163d0, 0x00000000},
+       {0x000163d4, 0x00000000},
+       {0x00016400, 0x36db6db6},
+       {0x00016404, 0x6db6db40},
+       {0x00016408, 0x73f00000},
+       {0x0001640c, 0x00000000},
+       {0x00016440, 0x3f80fff8},
+       {0x0001644c, 0x000f0278},
+       {0x00016450, 0x8036db6c},
+       {0x00016454, 0x6db60000},
+       {0x00016500, 0x07ff8001},
+       {0x00016508, 0x00080010},
+       {0x00016544, 0x01884080},
+       {0x00016548, 0x000080d8},
+       {0x00016780, 0x00000000},
+       {0x00016784, 0x00000000},
+       {0x00016788, 0x00800700},
+       {0x0001678c, 0x00800700},
+       {0x00016790, 0x00800700},
+       {0x00016794, 0x00000000},
+       {0x00016798, 0x00000000},
+       {0x0001679c, 0x00000000},
+       {0x000167a0, 0x00000001},
+       {0x000167a4, 0x00000001},
+       {0x000167a8, 0x00000000},
+       {0x000167ac, 0x00000000},
+       {0x000167b0, 0x00000000},
+       {0x000167b4, 0x00000000},
+       {0x000167b8, 0x00000000},
+       {0x000167bc, 0x00000000},
+       {0x000167c0, 0x000000a0},
+       {0x000167c4, 0x000c0000},
+       {0x000167c8, 0x14021402},
+       {0x000167cc, 0x00001402},
+       {0x000167d0, 0x00000000},
+       {0x000167d4, 0x00000000},
+};
+
+static const u32 qca953x_1p0_radio_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c},
+       {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25},
+       {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800},
+       {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46},
+       {0x00016104, 0xb7a00001, 0xb7a00001, 0xfff80005, 0xfff80005},
+       {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+       {0x00016504, 0xb7a00001, 0xb7a00001, 0xfff80001, 0xfff80001},
+       {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+};
+
+static const u32 qca953x_1p0_soc_preamble[][2] = {
+       /* Addr      allmodes  */
+       {0x00007000, 0x00000000},
+       {0x00007004, 0x00000000},
+       {0x00007008, 0x00000000},
+       {0x0000700c, 0x00000000},
+       {0x0000701c, 0x00000000},
+       {0x00007020, 0x00000000},
+       {0x00007024, 0x00000000},
+       {0x00007028, 0x00000000},
+       {0x0000702c, 0x00000000},
+       {0x00007030, 0x00000000},
+       {0x00007034, 0x00000002},
+       {0x00007038, 0x000004c2},
+       {0x00007048, 0x00000000},
+};
+
+static const u32 qca953x_1p0_common_rx_gain_bounds[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018},
+};
+
+static const u32 qca953x_1p0_common_wo_xlna_rx_gain_bounds[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+};
+
+static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xfffd5aaa},
+       {0x0000a2e0, 0xfffe9ccc},
+       {0x0000a2e4, 0xffffe0f0},
+       {0x0000a2e8, 0xfffcff00},
+       {0x0000a410, 0x000050da},
+       {0x0000a500, 0x00000000},
+       {0x0000a504, 0x04000002},
+       {0x0000a508, 0x08000004},
+       {0x0000a50c, 0x0c000006},
+       {0x0000a510, 0x0f00000a},
+       {0x0000a514, 0x1300000c},
+       {0x0000a518, 0x1700000e},
+       {0x0000a51c, 0x1b000064},
+       {0x0000a520, 0x1f000242},
+       {0x0000a524, 0x23000229},
+       {0x0000a528, 0x270002a2},
+       {0x0000a52c, 0x2c001203},
+       {0x0000a530, 0x30001803},
+       {0x0000a534, 0x33000881},
+       {0x0000a538, 0x38001809},
+       {0x0000a53c, 0x3a000814},
+       {0x0000a540, 0x3f001a0c},
+       {0x0000a544, 0x43001a0e},
+       {0x0000a548, 0x46001812},
+       {0x0000a54c, 0x49001884},
+       {0x0000a550, 0x4d001e84},
+       {0x0000a554, 0x50001e69},
+       {0x0000a558, 0x550006f4},
+       {0x0000a55c, 0x59000ad3},
+       {0x0000a560, 0x5e000ad5},
+       {0x0000a564, 0x61001ced},
+       {0x0000a568, 0x660018d4},
+       {0x0000a56c, 0x660018d4},
+       {0x0000a570, 0x660018d4},
+       {0x0000a574, 0x660018d4},
+       {0x0000a578, 0x660018d4},
+       {0x0000a57c, 0x660018d4},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x03804000},
+       {0x0000a610, 0x0300ca02},
+       {0x0000a614, 0x00000e04},
+       {0x0000a618, 0x03014000},
+       {0x0000a61c, 0x00000000},
+       {0x0000a620, 0x00000000},
+       {0x0000a624, 0x03014000},
+       {0x0000a628, 0x03804c05},
+       {0x0000a62c, 0x0701de06},
+       {0x0000a630, 0x07819c07},
+       {0x0000a634, 0x0701dc07},
+       {0x0000a638, 0x0701dc07},
+       {0x0000a63c, 0x0701dc07},
+       {0x0000b2dc, 0xfffd5aaa},
+       {0x0000b2e0, 0xfffe9ccc},
+       {0x0000b2e4, 0xffffe0f0},
+       {0x0000b2e8, 0xfffcff00},
+       {0x00016044, 0x010002d4},
+       {0x00016048, 0x66482400},
+       {0x00016280, 0x01000015},
+       {0x00016444, 0x010002d4},
+       {0x00016448, 0x66482400},
+};
+
+static const u32 qca953x_1p0_modes_no_xpa_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xffd5f552},
+       {0x0000a2e0, 0xffe60664},
+       {0x0000a2e4, 0xfff80780},
+       {0x0000a2e8, 0xfffff800},
+       {0x0000a410, 0x000050d6},
+       {0x0000a500, 0x00060020},
+       {0x0000a504, 0x04060060},
+       {0x0000a508, 0x080600a0},
+       {0x0000a50c, 0x0c068020},
+       {0x0000a510, 0x10068060},
+       {0x0000a514, 0x140680a0},
+       {0x0000a518, 0x18090040},
+       {0x0000a51c, 0x1b090080},
+       {0x0000a520, 0x1f0900c0},
+       {0x0000a524, 0x240c0041},
+       {0x0000a528, 0x280d0021},
+       {0x0000a52c, 0x2d0f0061},
+       {0x0000a530, 0x310f00a1},
+       {0x0000a534, 0x350e00a2},
+       {0x0000a538, 0x360e80a2},
+       {0x0000a53c, 0x380f00a2},
+       {0x0000a540, 0x3b0e00a3},
+       {0x0000a544, 0x3d110083},
+       {0x0000a548, 0x3e1100a3},
+       {0x0000a54c, 0x401100e3},
+       {0x0000a550, 0x421380e3},
+       {0x0000a554, 0x431780e3},
+       {0x0000a558, 0x461f80e3},
+       {0x0000a55c, 0x461f80e3},
+       {0x0000a560, 0x461f80e3},
+       {0x0000a564, 0x461f80e3},
+       {0x0000a568, 0x461f80e3},
+       {0x0000a56c, 0x461f80e3},
+       {0x0000a570, 0x461f80e3},
+       {0x0000a574, 0x461f80e3},
+       {0x0000a578, 0x461f80e3},
+       {0x0000a57c, 0x461f80e3},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x00804201},
+       {0x0000a610, 0x01008201},
+       {0x0000a614, 0x0180c402},
+       {0x0000a618, 0x0180c603},
+       {0x0000a61c, 0x0180c603},
+       {0x0000a620, 0x01c10603},
+       {0x0000a624, 0x01c10704},
+       {0x0000a628, 0x02c18b05},
+       {0x0000a62c, 0x0301cc07},
+       {0x0000a630, 0x0301cc07},
+       {0x0000a634, 0x0301cc07},
+       {0x0000a638, 0x0301cc07},
+       {0x0000a63c, 0x0301cc07},
+       {0x0000b2dc, 0xffd5f552},
+       {0x0000b2e0, 0xffe60664},
+       {0x0000b2e4, 0xfff80780},
+       {0x0000b2e8, 0xfffff800},
+       {0x00016044, 0x049242db},
+       {0x00016048, 0x6c927a70},
+       {0x00016444, 0x049242db},
+       {0x00016448, 0x6c927a70},
+};
+
+static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xffd5f552},
+       {0x0000a2e0, 0xffe60664},
+       {0x0000a2e4, 0xfff80780},
+       {0x0000a2e8, 0xfffff800},
+       {0x0000a410, 0x000050de},
+       {0x0000a500, 0x00000061},
+       {0x0000a504, 0x04000063},
+       {0x0000a508, 0x08000065},
+       {0x0000a50c, 0x0c000261},
+       {0x0000a510, 0x10000263},
+       {0x0000a514, 0x14000265},
+       {0x0000a518, 0x18000482},
+       {0x0000a51c, 0x1b000484},
+       {0x0000a520, 0x1f000486},
+       {0x0000a524, 0x240008c2},
+       {0x0000a528, 0x28000cc1},
+       {0x0000a52c, 0x2d000ce3},
+       {0x0000a530, 0x31000ce5},
+       {0x0000a534, 0x350010e5},
+       {0x0000a538, 0x360012e5},
+       {0x0000a53c, 0x380014e5},
+       {0x0000a540, 0x3b0018e5},
+       {0x0000a544, 0x3d001d04},
+       {0x0000a548, 0x3e001d05},
+       {0x0000a54c, 0x40001d07},
+       {0x0000a550, 0x42001f27},
+       {0x0000a554, 0x43001f67},
+       {0x0000a558, 0x46001fe7},
+       {0x0000a55c, 0x47001f2b},
+       {0x0000a560, 0x49001f0d},
+       {0x0000a564, 0x4b001ed2},
+       {0x0000a568, 0x4c001ed4},
+       {0x0000a56c, 0x4e001f15},
+       {0x0000a570, 0x4f001ff6},
+       {0x0000a574, 0x4f001ff6},
+       {0x0000a578, 0x4f001ff6},
+       {0x0000a57c, 0x4f001ff6},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x00804201},
+       {0x0000a610, 0x01008201},
+       {0x0000a614, 0x0180c402},
+       {0x0000a618, 0x0180c603},
+       {0x0000a61c, 0x0180c603},
+       {0x0000a620, 0x01c10603},
+       {0x0000a624, 0x01c10704},
+       {0x0000a628, 0x02c18b05},
+       {0x0000a62c, 0x02c14c07},
+       {0x0000a630, 0x01008704},
+       {0x0000a634, 0x01c10402},
+       {0x0000a638, 0x0301cc07},
+       {0x0000a63c, 0x0301cc07},
+       {0x0000b2dc, 0xffd5f552},
+       {0x0000b2e0, 0xffe60664},
+       {0x0000b2e4, 0xfff80780},
+       {0x0000b2e8, 0xfffff800},
+       {0x00016044, 0x049242db},
+       {0x00016048, 0x6c927a70},
+       {0x00016444, 0x049242db},
+       {0x00016448, 0x6c927a70},
+};
+
+#endif /* INITVALS_953X_H */
index f2202e7..f622a98 100644 (file)
@@ -455,10 +455,8 @@ bool ath9k_csa_is_finished(struct ath_softc *sc);
 
 void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
-void ath_hw_check(struct work_struct *work);
+bool ath_hw_check(struct ath_softc *sc);
 void ath_hw_pll_work(struct work_struct *work);
-void ath_rx_poll(unsigned long data);
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 void ath_start_ani(struct ath_softc *sc);
@@ -722,12 +720,10 @@ struct ath_softc {
        spinlock_t sc_pcu_lock;
        struct mutex mutex;
        struct work_struct paprd_work;
-       struct work_struct hw_check_work;
        struct work_struct hw_reset_work;
        struct completion paprd_complete;
        wait_queue_head_t tx_wait;
 
-       unsigned int hw_busy_count;
        unsigned long sc_flags;
        unsigned long driver_data;
 
@@ -761,7 +757,6 @@ struct ath_softc {
        struct ath_beacon_config cur_beacon_conf;
        struct delayed_work tx_complete_work;
        struct delayed_work hw_pll_work;
-       struct timer_list rx_poll_timer;
        struct timer_list sleep_timer;
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
index 112aff7..2e8bba0 100644 (file)
@@ -337,8 +337,14 @@ void ath9k_beacon_tasklet(unsigned long data)
 
                ath9k_hw_check_nav(ah);
 
-               if (!ath9k_hw_check_alive(ah))
-                       ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+               /*
+                * If the previous beacon has not been transmitted
+                * and a MAC/BB hang has been identified, return
+                * here because a chip reset would have been
+                * initiated.
+                */
+               if (!ath_hw_check(sc))
+                       return;
 
                if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
                        ath_dbg(common, BSTUCK,
index c028df7..b41e008 100644 (file)
@@ -1077,7 +1077,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
 
        if (ieee80211_is_beacon(hdr->frame_control) &&
            !is_zero_ether_addr(common->curbssid) &&
-           ether_addr_equal(hdr->addr3, common->curbssid)) {
+           ether_addr_equal_64bits(hdr->addr3, common->curbssid)) {
                s8 rssi = rxbuf->rxstatus.rs_rssi;
 
                if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
index cc58a8e..a47ea84 100644 (file)
@@ -107,6 +107,21 @@ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
 
 /* Private hardware call ops */
 
+static inline void ath9k_hw_init_hang_checks(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->init_hang_checks(ah);
+}
+
+static inline bool ath9k_hw_detect_mac_hang(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->detect_mac_hang(ah);
+}
+
+static inline bool ath9k_hw_detect_bb_hang(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->detect_bb_hang(ah);
+}
+
 /* PHY ops */
 
 static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah,
@@ -232,4 +247,31 @@ static inline void ath9k_hw_set_radar_params(struct ath_hw *ah)
        ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf);
 }
 
+static inline void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->init_cal_settings(ah);
+}
+
+static inline u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
+                                              struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan);
+}
+
+static inline void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs)
+               return;
+
+       ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
+}
+
+static inline void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
+               return;
+
+       ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
+}
+
 #endif /* ATH9K_HW_OPS_H */
index a4b1ae0..ce41658 100644 (file)
@@ -37,57 +37,6 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
 MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
-static int __init ath9k_init(void)
-{
-       return 0;
-}
-module_init(ath9k_init);
-
-static void __exit ath9k_exit(void)
-{
-       return;
-}
-module_exit(ath9k_exit);
-
-/* Private hardware callbacks */
-
-static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
-{
-       ath9k_hw_private_ops(ah)->init_cal_settings(ah);
-}
-
-static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
-                                       struct ath9k_channel *chan)
-{
-       return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan);
-}
-
-static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
-{
-       if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs)
-               return;
-
-       ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
-}
-
-static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
-{
-       /* You will not have this callback if using the old ANI */
-       if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
-               return;
-
-       ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
-}
-
-/********************/
-/* Helper Functions */
-/********************/
-
-#ifdef CONFIG_ATH9K_DEBUGFS
-
-#endif
-
-
 static void ath9k_hw_set_clockrate(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -296,6 +245,9 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
        case AR9300_DEVID_QCA955X:
                ah->hw_version.macVersion = AR_SREV_VERSION_9550;
                return;
+       case AR9300_DEVID_AR953X:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9531;
+               return;
        }
 
        val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
@@ -397,9 +349,10 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
 
 static void ath9k_hw_init_config(struct ath_hw *ah)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
+
        ah->config.dma_beacon_response_time = 1;
        ah->config.sw_beacon_response_time = 6;
-       ah->config.ack_6mb = 0x0;
        ah->config.cwm_ignore_extcca = 0;
        ah->config.analog_shiftreg = 1;
 
@@ -423,6 +376,24 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
         */
        if (num_possible_cpus() > 1)
                ah->config.serialize_regmode = SER_REG_MODE_AUTO;
+
+       if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&
+                    !ah->is_pciexpress)) {
+                       ah->config.serialize_regmode = SER_REG_MODE_ON;
+               } else {
+                       ah->config.serialize_regmode = SER_REG_MODE_OFF;
+               }
+       }
+
+       ath_dbg(common, RESET, "serialize_regmode is %d\n",
+               ah->config.serialize_regmode);
+
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
+       else
+               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
 }
 
 static void ath9k_hw_init_defaults(struct ath_hw *ah)
@@ -435,15 +406,24 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->hw_version.magic = AR5416_MAGIC;
        ah->hw_version.subvendorid = 0;
 
-       ah->sta_id1_defaults =
-               AR_STA_ID1_CRPT_MIC_ENABLE |
-               AR_STA_ID1_MCAST_KSRCH;
+       ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE |
+                              AR_STA_ID1_MCAST_KSRCH;
        if (AR_SREV_9100(ah))
                ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
+
        ah->slottime = ATH9K_SLOT_TIME_9;
        ah->globaltxtimeout = (u32) -1;
        ah->power_mode = ATH9K_PM_UNDEFINED;
        ah->htc_reset_init = true;
+
+       ah->ani_function = ATH9K_ANI_ALL;
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
+
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
+       else
+               ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 }
 
 static int ath9k_hw_init_macaddr(struct ath_hw *ah)
@@ -525,6 +505,31 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 
        ath9k_hw_read_revisions(ah);
 
+       switch (ah->hw_version.macVersion) {
+       case AR_SREV_VERSION_5416_PCI:
+       case AR_SREV_VERSION_5416_PCIE:
+       case AR_SREV_VERSION_9160:
+       case AR_SREV_VERSION_9100:
+       case AR_SREV_VERSION_9280:
+       case AR_SREV_VERSION_9285:
+       case AR_SREV_VERSION_9287:
+       case AR_SREV_VERSION_9271:
+       case AR_SREV_VERSION_9300:
+       case AR_SREV_VERSION_9330:
+       case AR_SREV_VERSION_9485:
+       case AR_SREV_VERSION_9340:
+       case AR_SREV_VERSION_9462:
+       case AR_SREV_VERSION_9550:
+       case AR_SREV_VERSION_9565:
+       case AR_SREV_VERSION_9531:
+               break;
+       default:
+               ath_err(common,
+                       "Mac Chip Rev 0x%02x.%x is not supported by this driver\n",
+                       ah->hw_version.macVersion, ah->hw_version.macRev);
+               return -EOPNOTSUPP;
+       }
+
        /*
         * Read back AR_WA into a permanent copy and set bits 14 and 17.
         * We need to do this to avoid RMW of this register. We cannot
@@ -558,50 +563,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
                return -EIO;
        }
 
-       if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
-               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
-                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&
-                    !ah->is_pciexpress)) {
-                       ah->config.serialize_regmode =
-                               SER_REG_MODE_ON;
-               } else {
-                       ah->config.serialize_regmode =
-                               SER_REG_MODE_OFF;
-               }
-       }
-
-       ath_dbg(common, RESET, "serialize_regmode is %d\n",
-               ah->config.serialize_regmode);
-
-       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
-       else
-               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
-
-       switch (ah->hw_version.macVersion) {
-       case AR_SREV_VERSION_5416_PCI:
-       case AR_SREV_VERSION_5416_PCIE:
-       case AR_SREV_VERSION_9160:
-       case AR_SREV_VERSION_9100:
-       case AR_SREV_VERSION_9280:
-       case AR_SREV_VERSION_9285:
-       case AR_SREV_VERSION_9287:
-       case AR_SREV_VERSION_9271:
-       case AR_SREV_VERSION_9300:
-       case AR_SREV_VERSION_9330:
-       case AR_SREV_VERSION_9485:
-       case AR_SREV_VERSION_9340:
-       case AR_SREV_VERSION_9462:
-       case AR_SREV_VERSION_9550:
-       case AR_SREV_VERSION_9565:
-               break;
-       default:
-               ath_err(common,
-                       "Mac Chip Rev 0x%02x.%x is not supported by this driver\n",
-                       ah->hw_version.macVersion, ah->hw_version.macRev);
-               return -EOPNOTSUPP;
-       }
-
        if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) ||
            AR_SREV_9330(ah) || AR_SREV_9550(ah))
                ah->is_pciexpress = false;
@@ -609,10 +570,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
        ath9k_hw_init_cal_settings(ah);
 
-       ah->ani_function = ATH9K_ANI_ALL;
-       if (!AR_SREV_9300_20_OR_LATER(ah))
-               ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
-
        if (!ah->is_pciexpress)
                ath9k_hw_disablepcie(ah);
 
@@ -631,15 +588,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
                return r;
        }
 
-       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-               ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
-       else
-               ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
-
-       if (AR_SREV_9330(ah))
-               ah->bb_watchdog_timeout_ms = 85;
-       else
-               ah->bb_watchdog_timeout_ms = 25;
+       ath9k_hw_init_hang_checks(ah);
 
        common->state = ATH_HW_INITIALIZED;
 
@@ -672,6 +621,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        case AR9300_DEVID_AR9462:
        case AR9485_DEVID_AR1111:
        case AR9300_DEVID_AR9565:
+       case AR9300_DEVID_AR953X:
                break;
        default:
                if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -807,7 +757,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
                /* program BB PLL phase_shift */
                REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
                              AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1);
-       } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
+       } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                u32 regval, pll2_divint, pll2_divfrac, refdiv;
 
                REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
@@ -817,9 +767,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
                udelay(100);
 
                if (ah->is_clk_25mhz) {
-                       pll2_divint = 0x54;
-                       pll2_divfrac = 0x1eb85;
-                       refdiv = 3;
+                       if (AR_SREV_9531(ah)) {
+                               pll2_divint = 0x1c;
+                               pll2_divfrac = 0xa3d2;
+                               refdiv = 1;
+                       } else {
+                               pll2_divint = 0x54;
+                               pll2_divfrac = 0x1eb85;
+                               refdiv = 3;
+                       }
                } else {
                        if (AR_SREV_9340(ah)) {
                                pll2_divint = 88;
@@ -833,7 +789,10 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
                }
 
                regval = REG_READ(ah, AR_PHY_PLL_MODE);
-               regval |= (0x1 << 16);
+               if (AR_SREV_9531(ah))
+                       regval |= (0x1 << 22);
+               else
+                       regval |= (0x1 << 16);
                REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
                udelay(100);
 
@@ -843,14 +802,33 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
 
                regval = REG_READ(ah, AR_PHY_PLL_MODE);
                if (AR_SREV_9340(ah))
-                       regval = (regval & 0x80071fff) | (0x1 << 30) |
-                                (0x1 << 13) | (0x4 << 26) | (0x18 << 19);
+                       regval = (regval & 0x80071fff) |
+                               (0x1 << 30) |
+                               (0x1 << 13) |
+                               (0x4 << 26) |
+                               (0x18 << 19);
+               else if (AR_SREV_9531(ah))
+                       regval = (regval & 0x01c00fff) |
+                               (0x1 << 31) |
+                               (0x2 << 29) |
+                               (0xa << 25) |
+                               (0x1 << 19) |
+                               (0x6 << 12);
                else
-                       regval = (regval & 0x80071fff) | (0x3 << 30) |
-                                (0x1 << 13) | (0x4 << 26) | (0x60 << 19);
+                       regval = (regval & 0x80071fff) |
+                               (0x3 << 30) |
+                               (0x1 << 13) |
+                               (0x4 << 26) |
+                               (0x60 << 19);
                REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
-               REG_WRITE(ah, AR_PHY_PLL_MODE,
-                         REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
+
+               if (AR_SREV_9531(ah))
+                       REG_WRITE(ah, AR_PHY_PLL_MODE,
+                                 REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff);
+               else
+                       REG_WRITE(ah, AR_PHY_PLL_MODE,
+                                 REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
+
                udelay(1000);
        }
 
@@ -1532,76 +1510,6 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
        }
 }
 
-static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states,
-                              int *hang_state, int *hang_pos)
-{
-       static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */
-       u32 chain_state, dcs_pos, i;
-
-       for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) {
-               chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f;
-               for (i = 0; i < 3; i++) {
-                       if (chain_state == dcu_chain_state[i]) {
-                               *hang_state = chain_state;
-                               *hang_pos = dcs_pos;
-                               return true;
-                       }
-               }
-       }
-       return false;
-}
-
-#define DCU_COMPLETE_STATE        1
-#define DCU_COMPLETE_STATE_MASK 0x3
-#define NUM_STATUS_READS         50
-static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah)
-{
-       u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4;
-       u32 i, hang_pos, hang_state, num_state = 6;
-
-       comp_state = REG_READ(ah, AR_DMADBG_6);
-
-       if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) {
-               ath_dbg(ath9k_hw_common(ah), RESET,
-                       "MAC Hang signature not found at DCU complete\n");
-               return false;
-       }
-
-       chain_state = REG_READ(ah, dcs_reg);
-       if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
-               goto hang_check_iter;
-
-       dcs_reg = AR_DMADBG_5;
-       num_state = 4;
-       chain_state = REG_READ(ah, dcs_reg);
-       if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
-               goto hang_check_iter;
-
-       ath_dbg(ath9k_hw_common(ah), RESET,
-               "MAC Hang signature 1 not found\n");
-       return false;
-
-hang_check_iter:
-       ath_dbg(ath9k_hw_common(ah), RESET,
-               "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n",
-               chain_state, comp_state, hang_state, hang_pos);
-
-       for (i = 0; i < NUM_STATUS_READS; i++) {
-               chain_state = REG_READ(ah, dcs_reg);
-               chain_state = (chain_state >> (5 * hang_pos)) & 0x1f;
-               comp_state = REG_READ(ah, AR_DMADBG_6);
-
-               if (((comp_state & DCU_COMPLETE_STATE_MASK) !=
-                                       DCU_COMPLETE_STATE) ||
-                   (chain_state != hang_state))
-                       return false;
-       }
-
-       ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n");
-
-       return true;
-}
-
 void ath9k_hw_check_nav(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1676,7 +1584,6 @@ static void ath9k_hw_reset_opmode(struct ath_hw *ah,
 
        REG_RMW(ah, AR_STA_ID1, macStaId1
                  | AR_STA_ID1_RTS_USE_DEF
-                 | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
                  | ah->sta_id1_defaults,
                  ~AR_STA_ID1_SADH_MASK);
        ath_hw_setbssidmask(common);
@@ -1735,7 +1642,7 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
                }
 #ifdef __BIG_ENDIAN
                else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
-                        AR_SREV_9550(ah))
+                        AR_SREV_9550(ah) || AR_SREV_9531(ah))
                        REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
                else
                        REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -1865,7 +1772,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        /* Save TSF before chip reset, a cold reset clears it */
        tsf = ath9k_hw_gettsf64(ah);
        getrawmonotonic(&ts);
-       usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000;
+       usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
 
        saveLedState = REG_READ(ah, AR_CFG_LED) &
                (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1899,7 +1806,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        /* Restore TSF */
        getrawmonotonic(&ts);
-       usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec;
+       usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
        ath9k_hw_settsf64(ah, tsf + usec);
 
        if (AR_SREV_9280_20_OR_LATER(ah))
@@ -2008,10 +1915,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
-       if (AR_SREV_9300_20_OR_LATER(ah)) {
+       if (AR_SREV_9300_20_OR_LATER(ah))
                ar9003_hw_bb_watchdog_config(ah);
+
+       if (ah->config.hw_hang_checks & HW_PHYRESTART_CLC_WAR)
                ar9003_hw_disable_phy_restart(ah);
-       }
 
        ath9k_hw_apply_gpio_override(ah);
 
@@ -2135,7 +2043,11 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
 
        REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
                    AR_RTC_FORCE_WAKE_EN);
-       udelay(50);
+
+       if (AR_SREV_9100(ah))
+               udelay(10000);
+       else
+               udelay(50);
 
        for (i = POWER_UP_TIME / 50; i > 0; i--) {
                val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
@@ -2564,13 +2476,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
            ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
                        pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
 
-       /*
-        * Fast channel change across bands is available
-        * only for AR9462 and AR9565.
-        */
-       if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
-               pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH;
-
        return 0;
 }
 
@@ -3084,14 +2989,14 @@ void ath_gen_timer_isr(struct ath_hw *ah)
        trigger_mask &= timer_table->timer_mask;
        thresh_mask &= timer_table->timer_mask;
 
-       trigger_mask &= ~thresh_mask;
-
        for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) {
                timer = timer_table->timers[index];
                if (!timer)
                    continue;
                if (!timer->overflow)
                    continue;
+
+               trigger_mask &= ~BIT(index);
                timer->overflow(timer->arg);
        }
 
index 6132ffe..e766399 100644 (file)
@@ -52,6 +52,7 @@
 #define AR9300_DEVID_QCA955X   0x0038
 #define AR9485_DEVID_AR1111    0x0037
 #define AR9300_DEVID_AR9565     0x0036
+#define AR9300_DEVID_AR953X     0x003d
 
 #define AR5416_AR9100_DEVID    0x000b
 
@@ -277,10 +278,24 @@ struct ath9k_hw_capabilities {
        u8 txs_len;
 };
 
+#define AR_NO_SPUR             0x8000
+#define AR_BASE_FREQ_2GHZ      2300
+#define AR_BASE_FREQ_5GHZ      4900
+#define AR_SPUR_FEEQ_BOUND_HT40 19
+#define AR_SPUR_FEEQ_BOUND_HT20 10
+
+enum ath9k_hw_hang_checks {
+       HW_BB_WATCHDOG            = BIT(0),
+       HW_PHYRESTART_CLC_WAR     = BIT(1),
+       HW_BB_RIFS_HANG           = BIT(2),
+       HW_BB_DFS_HANG            = BIT(3),
+       HW_BB_RX_CLEAR_STUCK_HANG = BIT(4),
+       HW_MAC_HANG               = BIT(5),
+};
+
 struct ath9k_ops_config {
        int dma_beacon_response_time;
        int sw_beacon_response_time;
-       int ack_6mb;
        u32 cwm_ignore_extcca;
        u32 pcie_waen;
        u8 analog_shiftreg;
@@ -292,13 +307,9 @@ struct ath9k_ops_config {
        int serialize_regmode;
        bool rx_intr_mitigation;
        bool tx_intr_mitigation;
-#define AR_NO_SPUR             0x8000
-#define AR_BASE_FREQ_2GHZ      2300
-#define AR_BASE_FREQ_5GHZ      4900
-#define AR_SPUR_FEEQ_BOUND_HT40 19
-#define AR_SPUR_FEEQ_BOUND_HT20 10
        u8 max_txtrig_level;
        u16 ani_poll_interval; /* ANI poll interval in ms */
+       u16 hw_hang_checks;
 
        /* Platform specific config */
        u32 aspm_l1_fix;
@@ -573,6 +584,10 @@ struct ath_hw_radar_conf {
  *     register settings through the register initialization.
  */
 struct ath_hw_private_ops {
+       void (*init_hang_checks)(struct ath_hw *ah);
+       bool (*detect_mac_hang)(struct ath_hw *ah);
+       bool (*detect_bb_hang)(struct ath_hw *ah);
+
        /* Calibration ops */
        void (*init_cal_settings)(struct ath_hw *ah);
        bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
@@ -1029,6 +1044,7 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
  * Code specific to AR9003, we stuff these here to avoid callbacks
  * for older families
  */
+bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
index e63465b..f2a17fc 100644 (file)
@@ -763,10 +763,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 
        setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
        INIT_WORK(&sc->hw_reset_work, ath_reset_work);
-       INIT_WORK(&sc->hw_check_work, ath_hw_check);
        INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
        INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-       setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
 
        /*
         * Cache line size is used to size and align various
index aed7e29..30dcef5 100644 (file)
@@ -65,50 +65,26 @@ void ath_tx_complete_poll_work(struct work_struct *work)
 /*
  * Checks if the BB/MAC is hung.
  */
-void ath_hw_check(struct work_struct *work)
+bool ath_hw_check(struct ath_softc *sc)
 {
-       struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       unsigned long flags;
-       int busy;
-       u8 is_alive, nbeacon = 1;
        enum ath_reset_type type;
+       bool is_alive;
 
        ath9k_ps_wakeup(sc);
+
        is_alive = ath9k_hw_check_alive(sc->sc_ah);
 
-       if ((is_alive && !AR_SREV_9300(sc->sc_ah)) || sc->tx99_state)
-               goto out;
-       else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
+       if (!is_alive) {
                ath_dbg(common, RESET,
-                       "DCU stuck is detected. Schedule chip reset\n");
+                       "HW hang detected, schedule chip reset\n");
                type = RESET_TYPE_MAC_HANG;
-               goto sched_reset;
-       }
-
-       spin_lock_irqsave(&common->cc_lock, flags);
-       busy = ath_update_survey_stats(sc);
-       spin_unlock_irqrestore(&common->cc_lock, flags);
-
-       ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
-               busy, sc->hw_busy_count + 1);
-       if (busy >= 99) {
-               if (++sc->hw_busy_count >= 3) {
-                       type = RESET_TYPE_BB_HANG;
-                       goto sched_reset;
-               }
-       } else if (busy >= 0) {
-               sc->hw_busy_count = 0;
-               nbeacon = 3;
+               ath9k_queue_reset(sc, type);
        }
 
-       ath_start_rx_poll(sc, nbeacon);
-       goto out;
-
-sched_reset:
-       ath9k_queue_reset(sc, type);
-out:
        ath9k_ps_restore(sc);
+
+       return is_alive;
 }
 
 /*
@@ -162,29 +138,6 @@ void ath_hw_pll_work(struct work_struct *work)
 }
 
 /*
- * RX Polling - monitors baseband hangs.
- */
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
-{
-       if (!AR_SREV_9300(sc->sc_ah))
-               return;
-
-       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
-               return;
-
-       mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
-                 (nbeacon * sc->cur_beacon_conf.beacon_interval));
-}
-
-void ath_rx_poll(unsigned long data)
-{
-       struct ath_softc *sc = (struct ath_softc *)data;
-
-       if (!test_bit(SC_OP_INVALID, &sc->sc_flags))
-               ieee80211_queue_work(sc->hw, &sc->hw_check_work);
-}
-
-/*
  * PA Pre-distortion.
  */
 static void ath_paprd_activate(struct ath_softc *sc)
@@ -409,10 +362,10 @@ void ath_ani_calibrate(unsigned long data)
 
        /* Call ANI routine if necessary */
        if (aniflag) {
-               spin_lock_irqsave(&common->cc_lock, flags);
+               spin_lock(&common->cc_lock);
                ath9k_hw_ani_monitor(ah, ah->curchan);
                ath_update_survey_stats(sc);
-               spin_unlock_irqrestore(&common->cc_lock, flags);
+               spin_unlock(&common->cc_lock);
        }
 
        /* Perform calibration if necessary */
index 89d7e20..5f72758 100644 (file)
@@ -922,11 +922,29 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah)
                        mask2 |= AR_IMR_S2_CST;
        }
 
+       if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
+               if (ints & ATH9K_INT_BB_WATCHDOG) {
+                       mask |= AR_IMR_BCNMISC;
+                       mask2 |= AR_IMR_S2_BB_WATCHDOG;
+               }
+       }
+
        ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask);
        REG_WRITE(ah, AR_IMR, mask);
-       ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
-                          AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
-                          AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST);
+       ah->imrs2_reg &= ~(AR_IMR_S2_TIM |
+                          AR_IMR_S2_DTIM |
+                          AR_IMR_S2_DTIMSYNC |
+                          AR_IMR_S2_CABEND |
+                          AR_IMR_S2_CABTO |
+                          AR_IMR_S2_TSFOOR |
+                          AR_IMR_S2_GTT |
+                          AR_IMR_S2_CST);
+
+       if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
+               if (ints & ATH9K_INT_BB_WATCHDOG)
+                       ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG;
+       }
+
        ah->imrs2_reg |= mask2;
        REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
 
index 21b764b..d0c3aec 100644 (file)
@@ -170,7 +170,6 @@ void ath9k_ps_restore(struct ath_softc *sc)
 static void __ath_cancel_work(struct ath_softc *sc)
 {
        cancel_work_sync(&sc->paprd_work);
-       cancel_work_sync(&sc->hw_check_work);
        cancel_delayed_work_sync(&sc->tx_complete_work);
        cancel_delayed_work_sync(&sc->hw_pll_work);
 
@@ -194,7 +193,6 @@ void ath_restart_work(struct ath_softc *sc)
                ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
                                     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
 
-       ath_start_rx_poll(sc, 3);
        ath_start_ani(sc);
 }
 
@@ -204,11 +202,7 @@ static bool ath_prepare_reset(struct ath_softc *sc)
        bool ret = true;
 
        ieee80211_stop_queues(sc->hw);
-
-       sc->hw_busy_count = 0;
        ath_stop_ani(sc);
-       del_timer_sync(&sc->rx_poll_timer);
-
        ath9k_hw_disable_interrupts(ah);
 
        if (!ath_drain_all_txq(sc))
@@ -336,7 +330,6 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand
        struct ieee80211_hw *hw = sc->hw;
        struct ath9k_channel *hchan;
        struct ieee80211_channel *chan = chandef->chan;
-       unsigned long flags;
        bool offchannel;
        int pos = chan->hw_value;
        int old_pos = -1;
@@ -354,9 +347,9 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand
                chan->center_freq, chandef->width);
 
        /* update survey stats for the old channel before switching */
-       spin_lock_irqsave(&common->cc_lock, flags);
+       spin_lock_bh(&common->cc_lock);
        ath_update_survey_stats(sc);
-       spin_unlock_irqrestore(&common->cc_lock, flags);
+       spin_unlock_bh(&common->cc_lock);
 
        ath9k_cmn_get_channel(hw, ah, chandef);
 
@@ -427,12 +420,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
        an->vif = vif;
 
        ath_tx_node_init(sc, an);
-
-       if (sta->ht_cap.ht_supported) {
-               an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
-                                    sta->ht_cap.ampdu_factor);
-               an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
-       }
 }
 
 static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@ -454,14 +441,8 @@ void ath9k_tasklet(unsigned long data)
        ath9k_ps_wakeup(sc);
        spin_lock(&sc->sc_pcu_lock);
 
-       if ((status & ATH9K_INT_FATAL) ||
-           (status & ATH9K_INT_BB_WATCHDOG)) {
-
-               if (status & ATH9K_INT_FATAL)
-                       type = RESET_TYPE_FATAL_INT;
-               else
-                       type = RESET_TYPE_BB_WATCHDOG;
-
+       if (status & ATH9K_INT_FATAL) {
+               type = RESET_TYPE_FATAL_INT;
                ath9k_queue_reset(sc, type);
 
                /*
@@ -473,6 +454,28 @@ void ath9k_tasklet(unsigned long data)
                goto out;
        }
 
+       if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
+           (status & ATH9K_INT_BB_WATCHDOG)) {
+               spin_lock(&common->cc_lock);
+               ath_hw_cycle_counters_update(common);
+               ar9003_hw_bb_watchdog_dbg_info(ah);
+               spin_unlock(&common->cc_lock);
+
+               if (ar9003_hw_bb_watchdog_check(ah)) {
+                       type = RESET_TYPE_BB_WATCHDOG;
+                       ath9k_queue_reset(sc, type);
+
+                       /*
+                        * Increment the ref. counter here so that
+                        * interrupts are enabled in the reset routine.
+                        */
+                       atomic_inc(&ah->intr_ref_cnt);
+                       ath_dbg(common, ANY,
+                               "BB_WATCHDOG: Skipping interrupts\n");
+                       goto out;
+               }
+       }
+
        spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                /*
@@ -541,7 +544,7 @@ irqreturn_t ath_isr(int irq, void *dev)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        enum ath9k_int status;
-       u32 sync_cause;
+       u32 sync_cause = 0;
        bool sched = false;
 
        /*
@@ -593,16 +596,9 @@ irqreturn_t ath_isr(int irq, void *dev)
            !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
                goto chip_reset;
 
-       if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
-           (status & ATH9K_INT_BB_WATCHDOG)) {
-
-               spin_lock(&common->cc_lock);
-               ath_hw_cycle_counters_update(common);
-               ar9003_hw_bb_watchdog_dbg_info(ah);
-               spin_unlock(&common->cc_lock);
-
+       if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
+           (status & ATH9K_INT_BB_WATCHDOG))
                goto chip_reset;
-       }
 
 #ifdef CONFIG_ATH9K_WOW
        if (status & ATH9K_INT_BMISS) {
@@ -732,11 +728,13 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ah->imask |= ATH9K_INT_RXHP |
-                            ATH9K_INT_RXLP |
-                            ATH9K_INT_BB_WATCHDOG;
+                            ATH9K_INT_RXLP;
        else
                ah->imask |= ATH9K_INT_RX;
 
+       if (ah->config.hw_hang_checks & HW_BB_WATCHDOG)
+               ah->imask |= ATH9K_INT_BB_WATCHDOG;
+
        ah->imask |= ATH9K_INT_GTT;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
@@ -860,7 +858,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        mutex_lock(&sc->mutex);
 
        ath_cancel_work(sc);
-       del_timer_sync(&sc->rx_poll_timer);
 
        if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
@@ -1791,13 +1788,12 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
-       unsigned long flags;
        int pos;
 
        if (config_enabled(CONFIG_ATH9K_TX99))
                return -EOPNOTSUPP;
 
-       spin_lock_irqsave(&common->cc_lock, flags);
+       spin_lock_bh(&common->cc_lock);
        if (idx == 0)
                ath_update_survey_stats(sc);
 
@@ -1811,7 +1807,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
                sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
 
        if (!sband || idx >= sband->n_channels) {
-               spin_unlock_irqrestore(&common->cc_lock, flags);
+               spin_unlock_bh(&common->cc_lock);
                return -ENOENT;
        }
 
@@ -1819,7 +1815,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
        pos = chan->hw_value;
        memcpy(survey, &sc->survey[pos], sizeof(*survey));
        survey->channel = chan;
-       spin_unlock_irqrestore(&common->cc_lock, flags);
+       spin_unlock_bh(&common->cc_lock);
 
        return 0;
 }
index e9a5857..55724b0 100644 (file)
@@ -412,6 +412,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         0x11AD, /* LITEON */
+                        0x06B2),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0842),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
                         0x6671),
          .driver_data = ATH9K_PCI_AR9565_1ANT },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -424,6 +434,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x1B9A, /* XAVI */
                         0x2812),
          .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x1B9A, /* XAVI */
+                        0x28A1),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x218A),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
 
        /* WB335 1-ANT / Antenna Diversity */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -469,22 +489,17 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         0x11AD, /* LITEON */
-                        0x0682),
+                        0x06A2),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
-                        PCI_VENDOR_ID_AZWAVE,
-                        0x213A),
-         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
-       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
-                        0x0036,
-                        PCI_VENDOR_ID_LENOVO,
-                        0x3026),
+                        0x11AD, /* LITEON */
+                        0x0682),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
-                        PCI_VENDOR_ID_LENOVO,
-                        0x4026),
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x213A),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
@@ -504,37 +519,35 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_DELL,
-                        0x020E),
+                        0x020C),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
 
-       /* WB335 2-ANT */
+       /* WB335 2-ANT / Antenna-Diversity */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411A),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411B),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411C),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411D),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411E),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
-
-       /* WB335 2-ANT / Antenna-Diversity */
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_ATHEROS,
@@ -562,11 +575,31 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
+                        0x11AD, /* LITEON */
+                        0x0832),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0692),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
                         PCI_VENDOR_ID_AZWAVE,
                         0x2130),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x213B),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x2182),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
                         0x144F, /* ASKEY */
                         0x7202),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -577,6 +610,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
+                        0x1B9A, /* XAVI */
+                        0x28A2),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
                         0x185F, /* WNC */
                         0x3027),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -590,6 +628,31 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         PCI_VENDOR_ID_FOXCONN,
                         0xE07F),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE081),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_LENOVO,
+                        0x3026),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_LENOVO,
+                        0x4026),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ASUSTEK,
+                        0x85F2),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_DELL,
+                        0x020E),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
 
        /* PCI-E AR9565 (WB335) */
        { PCI_VDEVICE(ATHEROS, 0x0036),
index 3692b2a..f7cc5b3 100644 (file)
@@ -419,7 +419,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
                rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
        }
 
-       if (AR_SREV_9550(sc->sc_ah))
+       if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
                rfilt |= ATH9K_RX_FILTER_4ADDRESS;
 
        return rfilt;
@@ -850,20 +850,15 @@ static int ath9k_process_rate(struct ath_common *common,
        enum ieee80211_band band;
        unsigned int i = 0;
        struct ath_softc __maybe_unused *sc = common->priv;
+       struct ath_hw *ah = sc->sc_ah;
 
-       band = hw->conf.chandef.chan->band;
+       band = ah->curchan->chan->band;
        sband = hw->wiphy->bands[band];
 
-       switch (hw->conf.chandef.width) {
-       case NL80211_CHAN_WIDTH_5:
+       if (IS_CHAN_QUARTER_RATE(ah->curchan))
                rxs->flag |= RX_FLAG_5MHZ;
-               break;
-       case NL80211_CHAN_WIDTH_10:
+       else if (IS_CHAN_HALF_RATE(ah->curchan))
                rxs->flag |= RX_FLAG_10MHZ;
-               break;
-       default:
-               break;
-       }
 
        if (rx_stats->rs_rate & 0x80) {
                /* HT rate */
@@ -982,7 +977,7 @@ static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
        if (ieee80211_is_beacon(hdr->frame_control)) {
                RX_STAT_INC(rx_beacons);
                if (!is_zero_ether_addr(common->curbssid) &&
-                   ether_addr_equal(hdr->addr3, common->curbssid))
+                   ether_addr_equal_64bits(hdr->addr3, common->curbssid))
                        return true;
        }
 
@@ -1077,9 +1072,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        }
 
        rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
-       if (rx_stats->is_mybeacon) {
-               sc->hw_busy_count = 0;
-               ath_start_rx_poll(sc, 3);
+
+       /*
+        * This shouldn't happen, but have a safety check anyway.
+        */
+       if (WARN_ON(!ah->curchan)) {
+               ret = -EINVAL;
+               goto exit;
        }
 
        if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
@@ -1089,8 +1088,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 
        ath9k_process_rssi(common, hw, rx_stats, rx_status);
 
-       rx_status->band = hw->conf.chandef.chan->band;
-       rx_status->freq = hw->conf.chandef.chan->center_freq;
+       rx_status->band = ah->curchan->chan->band;
+       rx_status->freq = ah->curchan->chan->center_freq;
        rx_status->antenna = rx_stats->rs_antenna;
        rx_status->flag |= RX_FLAG_MACTIME_END;
 
index 9ad0073..b1fd3fa 100644 (file)
 #define AR_IMR_S2              0x00ac
 #define AR_IMR_S2_QCU_TXURN    0x000003FF
 #define AR_IMR_S2_QCU_TXURN_S  0
+#define AR_IMR_S2_BB_WATCHDOG  0x00010000
 #define AR_IMR_S2_CST          0x00400000
 #define AR_IMR_S2_GTT          0x00800000
 #define AR_IMR_S2_TIM          0x01000000
 #define AR_SREV_REVISION_9565_101       1
 #define AR_SREV_REVISION_9565_11        2
 #define AR_SREV_VERSION_9550           0x400
+#define AR_SREV_VERSION_9531            0x500
+#define AR_SREV_REVISION_9531_10        0
+#define AR_SREV_REVISION_9531_11        1
 
 #define AR_SREV_5416(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
 #define AR_SREV_9580(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10))
-
 #define AR_SREV_9580_10(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10))
 
+#define AR_SREV_9531(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531))
+#define AR_SREV_9531_10(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_10))
+#define AR_SREV_9531_11(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11))
+
 /* NOTE: When adding chips newer than Peacock, add chip check here */
 #define AR_SREV_9580_10_OR_LATER(_ah) \
        (AR_SREV_9580(_ah))
index 11adb5e..99f4de9 100644 (file)
@@ -497,7 +497,7 @@ static int remove_buf_file_handler(struct dentry *dentry)
        return 0;
 }
 
-struct rchan_callbacks rfs_spec_scan_cb = {
+static struct rchan_callbacks rfs_spec_scan_cb = {
        .create_buf_file = create_buf_file_handler,
        .remove_buf_file = remove_buf_file_handler,
 };
index f1cde81..1b3230f 100644 (file)
@@ -197,7 +197,6 @@ int ath9k_suspend(struct ieee80211_hw *hw,
 
        ath_cancel_work(sc);
        ath_stop_ani(sc);
-       del_timer_sync(&sc->rx_poll_timer);
 
        if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
index 9d735c5..e8d0e7f 100644 (file)
@@ -774,11 +774,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        if (bt_aggr_limit)
                aggr_limit = bt_aggr_limit;
 
-       /*
-        * h/w can accept aggregates up to 16 bit lengths (65535).
-        * The IE, however can hold up to 65536, which shows up here
-        * as zero. Ignore 65536 since we  are constrained by hw.
-        */
        if (tid->an->maxampdu)
                aggr_limit = min(aggr_limit, tid->an->maxampdu);
 
@@ -1403,8 +1398,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
         * has already been added.
         */
        if (sta->ht_cap.ht_supported) {
-               an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
-                                    sta->ht_cap.ampdu_factor);
+               an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+                                     sta->ht_cap.ampdu_factor)) - 1;
                density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
                an->mpdudensity = density;
        }
index 3d70cd2..1c0af9c 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
index 349fa22..4c3f576 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
index e935f61..1b1b207 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
@@ -536,7 +535,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, ar->common.curbssid) ||
+       if (!ether_addr_equal_64bits(hdr->addr3, ar->common.curbssid) ||
            !ar->common.curaid)
                return;
 
@@ -602,8 +601,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
 
                if (bar->start_seq_num == entry_bar->start_seq_num &&
                    TID_CHECK(bar->control, entry_bar->control) &&
-                   ether_addr_equal(bar->ra, entry_bar->ta) &&
-                   ether_addr_equal(bar->ta, entry_bar->ra)) {
+                   ether_addr_equal_64bits(bar->ra, entry_bar->ta) &&
+                   ether_addr_equal_64bits(bar->ta, entry_bar->ra)) {
                        struct ieee80211_tx_info *tx_info;
 
                        tx_info = IEEE80211_SKB_CB(entry_skb);
index e3f696e..4cadfd4 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
index 8205d3e..10919f9 100644 (file)
@@ -156,6 +156,19 @@ void wil6210_enable_irq(struct wil6210_priv *wil)
        iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
                  offsetof(struct RGF_ICR, ICC));
 
+       /* interrupt moderation parameters */
+       if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               /* disable interrupt moderation for monitor
+                * to get better timestamp precision
+                */
+               iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+       } else {
+               iowrite32(WIL6210_ITR_TRSH,
+                         wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+               iowrite32(BIT_DMA_ITR_CNT_CRL_EN,
+                         wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+       }
+
        wil6210_unmask_irq_pseudo(wil);
        wil6210_unmask_irq_tx(wil);
        wil6210_unmask_irq_rx(wil);
index d505b26..9b88440 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <net/ipv6.h>
+#include <asm/processor.h>
 
 #include "wil6210.h"
 #include "wmi.h"
@@ -377,6 +378,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        }
        skb_trim(skb, dmalen);
 
+       prefetch(skb->data);
+
        wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
                          skb->data, skb_headlen(skb), false);
 
@@ -673,9 +676,12 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
 
+       d->dma.b11 = ETH_HLEN; /* MAC header length */
+
        switch (skb->protocol) {
        case cpu_to_be16(ETH_P_IP):
                protocol = ip_hdr(skb)->protocol;
+               d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);
                break;
        case cpu_to_be16(ETH_P_IPV6):
                protocol = ipv6_hdr(skb)->nexthdr;
@@ -701,8 +707,6 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
        }
 
        d->dma.ip_length = skb_network_header_len(skb);
-       d->dma.b11 = ETH_HLEN; /* MAC header length */
-       d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);
        /* Enable TCP/UDP checksum */
        d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS);
        /* Calculate pseudo-header */
index c4a5163..1f91eaf 100644 (file)
@@ -39,6 +39,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 #define WIL6210_MAX_TX_RINGS   (24) /* HW limit */
 #define WIL6210_MAX_CID                (8) /* HW limit */
 #define WIL6210_NAPI_BUDGET    (16) /* arbitrary */
+#define WIL6210_ITR_TRSH       (10000) /* arbitrary - about 15 IRQs/msec */
 
 /* Hardware definitions begin */
 
index b73b7e3..bf93ea8 100644 (file)
@@ -39,7 +39,6 @@
 
 ******************************************************************************/
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 
 #include <linux/kernel.h>
index 5e2749d..4cfb4d9 100644 (file)
@@ -32,7 +32,6 @@
 #ifdef __IN_PCMCIA_PACKAGE__
 #include <pcmcia/k_compat.h>
 #endif
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
index 64d5973..5cd97e3 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/netdevice.h>
 #include "atmel.h"
 
index 12c27d1..c229210 100644 (file)
@@ -41,9 +41,6 @@ struct brcmf_proto_bcdc_dcmd {
        __le32 status;  /* status code returned from the device */
 };
 
-/* Max valid buffer size that can be sent to the dongle */
-#define BCDC_MAX_MSG_SIZE      (ETH_FRAME_LEN+ETH_FCS_LEN)
-
 /* BCDC flag definitions */
 #define BCDC_DCMD_ERROR                0x01            /* 1=cmd failed */
 #define BCDC_DCMD_SET          0x02            /* 0=get, 1=set cmd */
@@ -133,9 +130,12 @@ brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
        if (buf)
                memcpy(bcdc->buf, buf, len);
 
+       len += sizeof(*msg);
+       if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE)
+               len = BRCMF_TX_IOCTL_MAX_MSG_SIZE;
+
        /* Send request */
-       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
-                              len + sizeof(struct brcmf_proto_bcdc_dcmd));
+       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
 }
 
 static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
index 2b5cde6..34c993d 100644 (file)
@@ -47,8 +47,6 @@
 
 #define SDIOH_API_ACCESS_RETRY_LIMIT   2
 
-#define SDIO_VENDOR_ID_BROADCOM                0x02d0
-
 #define DMA_ALIGN_MASK 0x03
 
 #define SDIO_FUNC1_BLOCKSIZE           64
@@ -216,94 +214,104 @@ static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func,
        return err_ret;
 }
 
-static int brcmf_sdiod_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
-                                   uint func, uint regaddr, u8 *byte)
+static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
+                                   u32 addr, u8 regsz, void *data, bool write)
 {
-       int err_ret;
+       struct sdio_func *func;
+       int ret;
 
-       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
+       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+                 write, fn, addr, regsz);
 
-       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
+       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
        if (brcmf_sdiod_pm_resume_error(sdiodev))
                return -EIO;
 
-       if (rw && func == 0) {
-               /* handle F0 separately */
-               err_ret = brcmf_sdiod_f0_writeb(sdiodev->func[func],
-                                               regaddr, *byte);
-       } else {
-               if (rw) /* CMD52 Write */
-                       sdio_writeb(sdiodev->func[func], *byte, regaddr,
-                                   &err_ret);
-               else if (func == 0) {
-                       *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
-                                             &err_ret);
+       /* only allow byte access on F0 */
+       if (WARN_ON(regsz > 1 && !fn))
+               return -EINVAL;
+       func = sdiodev->func[fn];
+
+       switch (regsz) {
+       case sizeof(u8):
+               if (write) {
+                       if (fn)
+                               sdio_writeb(func, *(u8 *)data, addr, &ret);
+                       else
+                               ret = brcmf_sdiod_f0_writeb(func, addr,
+                                                           *(u8 *)data);
                } else {
-                       *byte = sdio_readb(sdiodev->func[func], regaddr,
-                                          &err_ret);
+                       if (fn)
+                               *(u8 *)data = sdio_readb(func, addr, &ret);
+                       else
+                               *(u8 *)data = sdio_f0_readb(func, addr, &ret);
                }
+               break;
+       case sizeof(u16):
+               if (write)
+                       sdio_writew(func, *(u16 *)data, addr, &ret);
+               else
+                       *(u16 *)data = sdio_readw(func, addr, &ret);
+               break;
+       case sizeof(u32):
+               if (write)
+                       sdio_writel(func, *(u32 *)data, addr, &ret);
+               else
+                       *(u32 *)data = sdio_readl(func, addr, &ret);
+               break;
+       default:
+               brcmf_err("invalid size: %d\n", regsz);
+               break;
        }
 
-       if (err_ret) {
+       if (ret) {
                /*
                 * SleepCSR register access can fail when
                 * waking up the device so reduce this noise
                 * in the logs.
                 */
-               if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
-                       brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                                 rw ? "write" : "read", func, regaddr, *byte,
-                                 err_ret);
+               if (addr != SBSDIO_FUNC1_SLEEPCSR)
+                       brcmf_err("failed to %s data F%d@0x%05x, err: %d\n",
+                                 write ? "write" : "read", fn, addr, ret);
                else
-                       brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                                 rw ? "write" : "read", func, regaddr, *byte,
-                                 err_ret);
+                       brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
+                                 write ? "write" : "read", fn, addr, ret);
        }
-       return err_ret;
+       return ret;
 }
 
-static int brcmf_sdiod_request_word(struct brcmf_sdio_dev *sdiodev, uint rw,
-                                   uint func, uint addr, u32 *word,
-                                   uint nbytes)
+static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
+                                  u8 regsz, void *data, bool write)
 {
-       int err_ret = -EIO;
-
-       if (func == 0) {
-               brcmf_err("Only CMD52 allowed to F0\n");
-               return -EINVAL;
-       }
-
-       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
-                 rw, func, addr, nbytes);
+       u8 func_num;
+       s32 retry = 0;
+       int ret;
 
-       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
-       if (brcmf_sdiod_pm_resume_error(sdiodev))
-               return -EIO;
+       /*
+        * figure out how to read the register based on address range
+        * 0x00 ~ 0x7FF: function 0 CCCR and FBR
+        * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
+        * The rest: function 1 silicon backplane core registers
+        */
+       if ((addr & ~REG_F0_REG_MASK) == 0)
+               func_num = SDIO_FUNC_0;
+       else
+               func_num = SDIO_FUNC_1;
 
-       if (rw) {               /* CMD52 Write */
-               if (nbytes == 4)
-                       sdio_writel(sdiodev->func[func], *word, addr,
-                                   &err_ret);
-               else if (nbytes == 2)
-                       sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
-                                   addr, &err_ret);
-               else
-                       brcmf_err("Invalid nbytes: %d\n", nbytes);
-       } else {                /* CMD52 Read */
-               if (nbytes == 4)
-                       *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
-               else if (nbytes == 2)
-                       *word = sdio_readw(sdiodev->func[func], addr,
-                                          &err_ret) & 0xFFFF;
-               else
-                       brcmf_err("Invalid nbytes: %d\n", nbytes);
-       }
+       do {
+               if (!write)
+                       memset(data, 0, regsz);
+               /* for retry wait for 1 ms till bus get settled down */
+               if (retry)
+                       usleep_range(1000, 2000);
+               ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz,
+                                              data, write);
+       } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
 
-       if (err_ret)
-               brcmf_err("Failed to %s word, Err: 0x%08x\n",
-                         rw ? "write" : "read", err_ret);
+       if (ret != 0)
+               brcmf_err("failed with %d\n", ret);
 
-       return err_ret;
+       return ret;
 }
 
 static int
@@ -311,24 +319,17 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
 {
        int err = 0, i;
        u8 addr[3];
-       s32 retry;
 
        addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
        addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
        addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
 
        for (i = 0; i < 3; i++) {
-               retry = 0;
-               do {
-                       if (retry)
-                               usleep_range(1000, 2000);
-                       err = brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE,
-                                       SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
-                                       &addr[i]);
-               } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
-
+               err = brcmf_sdiod_regrw_helper(sdiodev,
+                                              SBSDIO_FUNC1_SBADDRLOW + i,
+                                              sizeof(u8), &addr[i], true);
                if (err) {
-                       brcmf_err("failed at addr:0x%0x\n",
+                       brcmf_err("failed at addr: 0x%0x\n",
                                  SBSDIO_FUNC1_SBADDRLOW + i);
                        break;
                }
@@ -359,61 +360,14 @@ brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
        return 0;
 }
 
-static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
-                                   void *data, bool write)
-{
-       u8 func_num, reg_size;
-       s32 retry = 0;
-       int ret;
-
-       /*
-        * figure out how to read the register based on address range
-        * 0x00 ~ 0x7FF: function 0 CCCR and FBR
-        * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
-        * The rest: function 1 silicon backplane core registers
-        */
-       if ((addr & ~REG_F0_REG_MASK) == 0) {
-               func_num = SDIO_FUNC_0;
-               reg_size = 1;
-       } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
-               func_num = SDIO_FUNC_1;
-               reg_size = 1;
-       } else {
-               func_num = SDIO_FUNC_1;
-               reg_size = 4;
-
-               ret = brcmf_sdiod_addrprep(sdiodev, reg_size, &addr);
-               if (ret)
-                       goto done;
-       }
-
-       do {
-               if (!write)
-                       memset(data, 0, reg_size);
-               if (retry)      /* wait for 1 ms till bus get settled down */
-                       usleep_range(1000, 2000);
-               if (reg_size == 1)
-                       ret = brcmf_sdiod_request_byte(sdiodev, write,
-                                                      func_num, addr, data);
-               else
-                       ret = brcmf_sdiod_request_word(sdiodev, write,
-                                                      func_num, addr, data, 4);
-       } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
-
-done:
-       if (ret != 0)
-               brcmf_err("failed with %d\n", ret);
-
-       return ret;
-}
-
 u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
 {
        u8 data;
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         false);
        brcmf_dbg(SDIO, "data:0x%02x\n", data);
 
        if (ret)
@@ -428,9 +382,14 @@ u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
+       retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
+       if (retval)
+               goto done;
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         false);
        brcmf_dbg(SDIO, "data:0x%08x\n", data);
 
+done:
        if (ret)
                *ret = retval;
 
@@ -443,8 +402,8 @@ void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
-
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         true);
        if (ret)
                *ret = retval;
 }
@@ -455,8 +414,13 @@ void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
+       retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
+       if (retval)
+               goto done;
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         true);
 
+done:
        if (ret)
                *ret = retval;
 }
@@ -879,8 +843,8 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
        brcmf_dbg(SDIO, "Enter\n");
 
        /* issue abort cmd52 command through F0 */
-       brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
-                                SDIO_CCCR_ABORT, &t_func);
+       brcmf_sdiod_request_data(sdiodev, SDIO_FUNC_0, SDIO_CCCR_ABORT,
+                                sizeof(t_func), &t_func, true);
 
        brcmf_dbg(SDIO, "Exit\n");
        return 0;
@@ -981,6 +945,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
                     SDIO_DEVICE_ID_BROADCOM_4335_4339)},
        { /* end: all zeroes */ },
@@ -1037,7 +1002,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        sdiodev->pdata = brcmfmac_sdio_pdata;
 
        atomic_set(&sdiodev->suspend, false);
-       init_waitqueue_head(&sdiodev->request_byte_wait);
        init_waitqueue_head(&sdiodev->request_word_wait);
        init_waitqueue_head(&sdiodev->request_buffer_wait);
 
index 252024b..939d6b1 100644 (file)
@@ -21,8 +21,6 @@
 #ifndef _BRCMF_H_
 #define _BRCMF_H_
 
-#define BRCMF_VERSION_STR              "4.218.248.5"
-
 #include "fweh.h"
 
 #define TOE_TX_CSUM_OL         0x00000001
 #define BRCMF_DCMD_MEDLEN      1536
 #define BRCMF_DCMD_MAXLEN      8192
 
+/* IOCTL from host to device are limited in lenght. A device can only handle
+ * ethernet frame size. This limitation is to be applied by protocol layer.
+ */
+#define BRCMF_TX_IOCTL_MAX_MSG_SIZE    (ETH_FRAME_LEN+ETH_FCS_LEN)
+
 #define BRCMF_AMPDU_RX_REORDER_MAXFLOWS                256
 
 /* Length of firmware version string stored for
index 548dbb5..6a8983a 100644 (file)
 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
 #define BRCMF_DEFAULT_PACKET_FILTER    "100 0 0 0 0x01 0x00"
 
-#ifdef DEBUG
-static const char brcmf_version[] =
-       "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
-       __DATE__ " at " __TIME__;
-#else
-static const char brcmf_version[] =
-       "Dongle Host Driver, version " BRCMF_VERSION_STR;
-#endif
-
 
 bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
                      struct sk_buff *pkt, int prec)
index bce0b8e..af39eda 100644 (file)
@@ -702,7 +702,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 
        brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
 
-       ndev->destructor = free_netdev;
+       ndev->destructor = brcmf_cfg80211_free_netdev;
        return 0;
 
 fail:
@@ -859,8 +859,6 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
                }
                /* unregister will take care of freeing it */
                unregister_netdev(ifp->ndev);
-               if (bssidx == 0)
-                       brcmf_cfg80211_detach(drvr->config);
        } else {
                kfree(ifp);
        }
@@ -963,8 +961,7 @@ int brcmf_bus_start(struct device *dev)
 fail:
        if (ret < 0) {
                brcmf_err("failed: %d\n", ret);
-               if (drvr->config)
-                       brcmf_cfg80211_detach(drvr->config);
+               brcmf_cfg80211_detach(drvr->config);
                if (drvr->fws) {
                        brcmf_fws_del_interface(ifp);
                        brcmf_fws_deinit(drvr);
@@ -1039,6 +1036,8 @@ void brcmf_detach(struct device *dev)
                        brcmf_del_if(drvr, i);
                }
 
+       brcmf_cfg80211_detach(drvr->config);
+
        brcmf_bus_detach(drvr);
 
        brcmf_proto_detach(drvr);
index f214510..9c7f08a 100644 (file)
@@ -509,6 +509,8 @@ enum brcmf_sdio_frmtype {
 #define BCM4334_NVRAM_NAME             "brcm/brcmfmac4334-sdio.txt"
 #define BCM4335_FIRMWARE_NAME          "brcm/brcmfmac4335-sdio.bin"
 #define BCM4335_NVRAM_NAME             "brcm/brcmfmac4335-sdio.txt"
+#define BCM43362_FIRMWARE_NAME         "brcm/brcmfmac43362-sdio.bin"
+#define BCM43362_NVRAM_NAME            "brcm/brcmfmac43362-sdio.txt"
 #define BCM4339_FIRMWARE_NAME          "brcm/brcmfmac4339-sdio.bin"
 #define BCM4339_NVRAM_NAME             "brcm/brcmfmac4339-sdio.txt"
 
@@ -526,6 +528,8 @@ MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
 MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43362_NVRAM_NAME);
 MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
 
@@ -552,6 +556,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
        { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
        { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
        { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
+       { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
        { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }
 };
 
@@ -3384,7 +3389,8 @@ err:
 
 static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
 {
-       u32 addr, reg;
+       u32 addr, reg, pmu_cc3_mask = ~0;
+       int err;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3392,13 +3398,27 @@ static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
        if (bus->ci->pmurev < 17)
                return false;
 
-       /* read PMU chipcontrol register 3*/
-       addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
-       brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
-       addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
-       reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
+       switch (bus->ci->chip) {
+       case BCM43241_CHIP_ID:
+       case BCM4335_CHIP_ID:
+       case BCM4339_CHIP_ID:
+               /* read PMU chipcontrol register 3 */
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
+               brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
+               reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
+               return (reg & pmu_cc3_mask) != 0;
+       default:
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, pmucapabilities_ext);
+               reg = brcmf_sdiod_regrl(bus->sdiodev, addr, &err);
+               if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
+                       return false;
 
-       return (bool)reg;
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, retention_ctl);
+               reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
+               return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
+                              PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
+       }
 }
 
 static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
@@ -3615,7 +3635,7 @@ static int brcmf_sdio_bus_init(struct device *dev)
        }
 
        /* If we didn't come up, turn off backplane clock */
-       if (bus_if->state != BRCMF_BUS_DATA)
+       if (ret != 0)
                brcmf_sdio_clkctl(bus, CLK_NONE, false);
 
 exit:
@@ -3750,31 +3770,6 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
        }
 }
 
-static void brcmf_sdio_release_malloc(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       kfree(bus->rxbuf);
-       bus->rxctl = bus->rxbuf = NULL;
-       bus->rxlen = 0;
-}
-
-static bool brcmf_sdio_probe_malloc(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       if (bus->sdiodev->bus_if->maxctl) {
-               bus->rxblen =
-                   roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
-                           ALIGNMENT) + bus->head_align;
-               bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
-               if (!(bus->rxbuf))
-                       return false;
-       }
-
-       return true;
-}
-
 static bool
 brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 {
@@ -3888,39 +3883,6 @@ fail:
        return false;
 }
 
-static bool brcmf_sdio_probe_init(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       sdio_claim_host(bus->sdiodev->func[1]);
-
-       /* Disable F2 to clear any intermediate frame state on the dongle */
-       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
-
-       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-       bus->rxflow = false;
-
-       /* Done with backplane-dependent accesses, can drop clock... */
-       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
-
-       sdio_release_host(bus->sdiodev->func[1]);
-
-       /* ...and initialize clock/power states */
-       bus->clkstate = CLK_SDONLY;
-       bus->idletime = BRCMF_IDLE_INTERVAL;
-       bus->idleclock = BRCMF_IDLE_ACTIVE;
-
-       /* Query the F2 block size, set roundup accordingly */
-       bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
-       bus->roundup = min(max_roundup, bus->blocksize);
-
-       /* SR state */
-       bus->sleeping = false;
-       bus->sr_enabled = false;
-
-       return true;
-}
-
 static int
 brcmf_sdio_watchdog_thread(void *data)
 {
@@ -3955,24 +3917,6 @@ brcmf_sdio_watchdog(unsigned long data)
        }
 }
 
-static void brcmf_sdio_release_dongle(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       if (bus->ci) {
-               sdio_claim_host(bus->sdiodev->func[1]);
-               brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
-               brcmf_sdio_clkctl(bus, CLK_NONE, false);
-               sdio_release_host(bus->sdiodev->func[1]);
-               brcmf_sdio_chip_detach(&bus->ci);
-               if (bus->vars && bus->varsz)
-                       kfree(bus->vars);
-               bus->vars = NULL;
-       }
-
-       brcmf_dbg(TRACE, "Disconnected\n");
-}
-
 static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
        .stop = brcmf_sdio_bus_stop,
        .preinit = brcmf_sdio_bus_preinit,
@@ -4066,15 +4010,42 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        }
 
        /* Allocate buffers */
-       if (!(brcmf_sdio_probe_malloc(bus))) {
-               brcmf_err("brcmf_sdio_probe_malloc failed\n");
-               goto fail;
+       if (bus->sdiodev->bus_if->maxctl) {
+               bus->rxblen =
+                   roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
+                           ALIGNMENT) + bus->head_align;
+               bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
+               if (!(bus->rxbuf)) {
+                       brcmf_err("rxbuf allocation failed\n");
+                       goto fail;
+               }
        }
 
-       if (!(brcmf_sdio_probe_init(bus))) {
-               brcmf_err("brcmf_sdio_probe_init failed\n");
-               goto fail;
-       }
+       sdio_claim_host(bus->sdiodev->func[1]);
+
+       /* Disable F2 to clear any intermediate frame state on the dongle */
+       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
+
+       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
+       bus->rxflow = false;
+
+       /* Done with backplane-dependent accesses, can drop clock... */
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+       sdio_release_host(bus->sdiodev->func[1]);
+
+       /* ...and initialize clock/power states */
+       bus->clkstate = CLK_SDONLY;
+       bus->idletime = BRCMF_IDLE_INTERVAL;
+       bus->idleclock = BRCMF_IDLE_ACTIVE;
+
+       /* Query the F2 block size, set roundup accordingly */
+       bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
+       bus->roundup = min(max_roundup, bus->blocksize);
+
+       /* SR state */
+       bus->sleeping = false;
+       bus->sr_enabled = false;
 
        brcmf_sdio_debugfs_create(bus);
        brcmf_dbg(INFO, "completed!!\n");
@@ -4108,12 +4079,20 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
 
                if (bus->sdiodev->bus_if->drvr) {
                        brcmf_detach(bus->sdiodev->dev);
-                       brcmf_sdio_release_dongle(bus);
+               }
+
+               if (bus->ci) {
+                       sdio_claim_host(bus->sdiodev->func[1]);
+                       brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+                       brcmf_sdio_clkctl(bus, CLK_NONE, false);
+                       sdio_release_host(bus->sdiodev->func[1]);
+                       brcmf_sdio_chip_detach(&bus->ci);
                }
 
                brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
-               brcmf_sdio_release_malloc(bus);
+               kfree(bus->rxbuf);
                kfree(bus->hdrbuf);
+               kfree(bus->vars);
                kfree(bus);
        }
 
@@ -4131,7 +4110,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
        }
 
        /* don't start the wd until fw is loaded */
-       if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN)
+       if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
                return;
 
        if (wdtick) {
index 7918c10..c3e7d76 100644 (file)
@@ -1873,7 +1873,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
        /* determine the priority */
        if (!skb->priority)
-               skb->priority = cfg80211_classify8021d(skb);
+               skb->priority = cfg80211_classify8021d(skb, NULL);
 
        drvr->tx_multicast += !!multicast;
        if (pae)
index 185af8a..fc4f98b 100644 (file)
@@ -1955,21 +1955,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
                err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
                if (err < 0) {
                        brcmf_err("set p2p_disc error\n");
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
                /* obtain bsscfg index for P2P discovery */
                err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
                if (err < 0) {
                        brcmf_err("retrieving discover bsscfg index failed\n");
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
                /* Verify that firmware uses same bssidx as driver !! */
                if (p2p_ifp->bssidx != bssidx) {
                        brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
                                  bssidx, p2p_ifp->bssidx);
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
 
@@ -1997,7 +1997,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
                brcmf_p2p_cancel_remain_on_channel(vif->ifp);
                brcmf_p2p_deinit_discovery(p2p);
                /* remove discovery interface */
-               brcmf_free_vif(p2p->cfg, vif);
+               brcmf_free_vif(vif);
                p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
        }
        /* just set it all to zero */
@@ -2222,7 +2222,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
        return &p2p_vif->wdev;
 
 fail:
-       brcmf_free_vif(p2p->cfg, p2p_vif);
+       brcmf_free_vif(p2p_vif);
        return ERR_PTR(err);
 }
 
@@ -2231,31 +2231,12 @@ fail:
  *
  * @vif: virtual interface object to delete.
  */
-static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg,
+static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
                                    struct brcmf_cfg80211_vif *vif)
 {
        cfg80211_unregister_wdev(&vif->wdev);
-       cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
-       brcmf_free_vif(cfg, vif);
-}
-
-/**
- * brcmf_p2p_free_p2p_if() - free up net device related data.
- *
- * @ndev: net device that needs to be freed.
- */
-static void brcmf_p2p_free_p2p_if(struct net_device *ndev)
-{
-       struct brcmf_cfg80211_info *cfg;
-       struct brcmf_cfg80211_vif *vif;
-       struct brcmf_if *ifp;
-
-       ifp = netdev_priv(ndev);
-       cfg = ifp->drvr->config;
-       vif = ifp->vif;
-
-       brcmf_free_vif(cfg, vif);
-       free_netdev(ifp->ndev);
+       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+       brcmf_free_vif(vif);
 }
 
 /**
@@ -2335,8 +2316,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
                brcmf_err("Registering netdevice failed\n");
                goto fail;
        }
-       /* override destructor */
-       ifp->ndev->destructor = brcmf_p2p_free_p2p_if;
 
        cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
        /* Disable firmware roaming for P2P interface  */
@@ -2349,7 +2328,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
        return &ifp->vif->wdev;
 
 fail:
-       brcmf_free_vif(cfg, vif);
+       brcmf_free_vif(vif);
        return ERR_PTR(err);
 }
 
@@ -2358,8 +2337,6 @@ fail:
  *
  * @wiphy: wiphy device of interface.
  * @wdev: wireless device of interface.
- *
- * TODO: not yet supported.
  */
 int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
 {
@@ -2385,7 +2362,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                break;
 
        case NL80211_IFTYPE_P2P_DEVICE:
-               brcmf_p2p_delete_p2pdev(cfg, vif);
+               brcmf_p2p_delete_p2pdev(p2p, vif);
                return 0;
        default:
                return -ENOTSUPP;
index 5f39f28..9fd4067 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/netdevice.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
 #include <linux/ssb/ssb_regs.h>
 #include <linux/bcma/bcma.h>
 
@@ -83,6 +84,24 @@ static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
        {0, 0x1}
 };
 
+/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
+        {6, 0x7},
+        {5, 0x6},
+        {4, 0x5},
+        {3, 0x4},
+        {2, 0x2},
+        {1, 0x1},
+        {0, 0x0}
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
+static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
+       {3, 0x3},
+       {2, 0x2},
+       {1, 0x1},
+       {0, 0x0} };
+
 /* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
 static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
        {16, 0x7},
@@ -569,6 +588,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
                ci->ramsize = 0xc0000;
                ci->rambase = 0x180000;
                break;
+       case BCM43362_CHIP_ID:
+               ci->c_inf[0].wrapbase = 0x18100000;
+               ci->c_inf[0].cib = 0x27004211;
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = 0x18002000;
+               ci->c_inf[1].wrapbase = 0x18102000;
+               ci->c_inf[1].cib = 0x0a004211;
+               ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+               ci->c_inf[2].base = 0x18004000;
+               ci->c_inf[2].wrapbase = 0x18104000;
+               ci->c_inf[2].cib = 0x08080401;
+               ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+               ci->c_inf[3].base = 0x18003000;
+               ci->c_inf[3].wrapbase = 0x18103000;
+               ci->c_inf[3].cib = 0x03004211;
+               ci->ramsize = 0x3C000;
+               break;
        default:
                brcmf_err("chipid 0x%x is not supported\n", ci->chip);
                return -ENODEV;
@@ -757,6 +793,11 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
                str_mask = 0x00003800;
                str_shift = 11;
                break;
+       case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
+               str_tab = sdiod_drvstr_tab6_1v8;
+               str_mask = 0x00001800;
+               str_shift = 11;
+               break;
        case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
                /* note: 43143 does not support tristate */
                i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
@@ -769,6 +810,11 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
                                  brcmf_sdio_chip_name(ci->chip, chn, 8),
                                  drivestrength);
                break;
+       case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
+               str_tab = sdiod_drive_strength_tab5_1v8;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
        default:
                brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
                          brcmf_sdio_chip_name(ci->chip, chn, 8),
index d0f4b45..7ea424e 100644 (file)
 
 #define BRCMF_MAX_CORENUM      6
 
-/* SDIO device ID */
-#define SDIO_DEVICE_ID_BROADCOM_43143          43143
-#define SDIO_DEVICE_ID_BROADCOM_43241          0x4324
-#define SDIO_DEVICE_ID_BROADCOM_4329           0x4329
-#define SDIO_DEVICE_ID_BROADCOM_4330           0x4330
-#define SDIO_DEVICE_ID_BROADCOM_4334           0x4334
-#define SDIO_DEVICE_ID_BROADCOM_4335_4339      0x4335
-
 struct chip_core_info {
        u16 id;
        u16 rev;
index a0981b3..092e9c8 100644 (file)
@@ -167,7 +167,6 @@ struct brcmf_sdio_dev {
        u32 sbwad;                      /* Save backplane window address */
        struct brcmf_sdio *bus;
        atomic_t suspend;               /* suspend flag */
-       wait_queue_head_t request_byte_wait;
        wait_queue_head_t request_word_wait;
        wait_queue_head_t request_buffer_wait;
        struct device *dev;
index 3966fe0..aad83ae 100644 (file)
@@ -1095,10 +1095,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
                                             BRCMF_C_DISASSOC, NULL, 0);
                if (err) {
                        brcmf_err("WLC_DISASSOC failed (%d)\n", err);
-                       cfg80211_disconnected(vif->wdev.netdev, 0,
-                                             NULL, 0, GFP_KERNEL);
                }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
+               cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
+
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
        clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
@@ -1758,6 +1758,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
                return -EIO;
 
        clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
+       cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
 
        memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
        scbval.val = cpu_to_le32(reason_code);
@@ -4359,9 +4360,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 {
        struct brcmf_cfg80211_vif *vif;
 
-       if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
-               return ERR_PTR(-ENOSPC);
-
        brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
                  sizeof(*vif));
        vif = kzalloc(sizeof(*vif), GFP_KERNEL);
@@ -4378,21 +4376,25 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
        brcmf_init_prof(&vif->profile);
 
        list_add_tail(&vif->list, &cfg->vif_list);
-       cfg->vif_cnt++;
        return vif;
 }
 
-void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
-                   struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 {
        list_del(&vif->list);
-       cfg->vif_cnt--;
-
        kfree(vif);
-       if (!cfg->vif_cnt) {
-               wiphy_unregister(cfg->wiphy);
-               wiphy_free(cfg->wiphy);
-       }
+}
+
+void brcmf_cfg80211_free_netdev(struct net_device *ndev)
+{
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_if *ifp;
+
+       ifp = netdev_priv(ndev);
+       vif = ifp->vif;
+
+       brcmf_free_vif(vif);
+       free_netdev(ndev);
 }
 
 static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
@@ -4979,20 +4981,20 @@ cfg80211_p2p_attach_out:
        wl_deinit_priv(cfg);
 
 cfg80211_attach_out:
-       brcmf_free_vif(cfg, vif);
+       brcmf_free_vif(vif);
        return NULL;
 }
 
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 {
-       struct brcmf_cfg80211_vif *vif;
-       struct brcmf_cfg80211_vif *tmp;
+       if (!cfg)
+               return;
 
-       wl_deinit_priv(cfg);
+       WARN_ON(!list_empty(&cfg->vif_list));
+       wiphy_unregister(cfg->wiphy);
        brcmf_btcoex_detach(cfg);
-       list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
-               brcmf_free_vif(cfg, vif);
-       }
+       wl_deinit_priv(cfg);
+       wiphy_free(cfg->wiphy);
 }
 
 static s32
@@ -5087,7 +5089,8 @@ dongle_scantime_out:
 }
 
 
-static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
+static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
+                                  u32 bw_cap[])
 {
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct ieee80211_channel *band_chan_arr;
@@ -5100,7 +5103,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
        enum ieee80211_band band;
        u32 channel;
        u32 *n_cnt;
-       bool ht40_allowed;
        u32 index;
        u32 ht40_flag;
        bool update;
@@ -5133,18 +5135,17 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                        array_size = ARRAY_SIZE(__wl_2ghz_channels);
                        n_cnt = &__wl_band_2ghz.n_channels;
                        band = IEEE80211_BAND_2GHZ;
-                       ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
                } else if (ch.band == BRCMU_CHAN_BAND_5G) {
                        band_chan_arr = __wl_5ghz_a_channels;
                        array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
                        n_cnt = &__wl_band_5ghz_a.n_channels;
                        band = IEEE80211_BAND_5GHZ;
-                       ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
                } else {
-                       brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec);
+                       brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
                        continue;
                }
-               if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40)
+               if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
+                   ch.bw == BRCMU_CHAN_BW_40)
                        continue;
                update = false;
                for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
@@ -5162,7 +5163,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                                ieee80211_channel_to_frequency(ch.chnum, band);
                        band_chan_arr[index].hw_value = ch.chnum;
 
-                       if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) {
+                       brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
+                                 ch.chnum, band_chan_arr[index].center_freq,
+                                 ch.bw, ch.sb);
+                       if (ch.bw == BRCMU_CHAN_BW_40) {
                                /* assuming the order is HT20, HT40 Upper,
                                 * HT40 lower from chanspecs
                                 */
@@ -5213,6 +5217,46 @@ exit:
        return err;
 }
 
+static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
+{
+       u32 band, mimo_bwcap;
+       int err;
+
+       band = WLC_BAND_2G;
+       err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+       if (!err) {
+               bw_cap[IEEE80211_BAND_2GHZ] = band;
+               band = WLC_BAND_5G;
+               err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+               if (!err) {
+                       bw_cap[IEEE80211_BAND_5GHZ] = band;
+                       return;
+               }
+               WARN_ON(1);
+               return;
+       }
+       brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
+       mimo_bwcap = 0;
+       err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
+       if (err)
+               /* assume 20MHz if firmware does not give a clue */
+               mimo_bwcap = WLC_N_BW_20ALL;
+
+       switch (mimo_bwcap) {
+       case WLC_N_BW_40ALL:
+               bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
+               /* fall-thru */
+       case WLC_N_BW_20IN2G_40IN5G:
+               bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
+               /* fall-thru */
+       case WLC_N_BW_20ALL:
+               bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
+               bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
+               break;
+       default:
+               brcmf_err("invalid mimo_bw_cap value\n");
+       }
+}
 
 static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 {
@@ -5221,13 +5265,13 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        s32 phy_list;
        u32 band_list[3];
        u32 nmode;
-       u32 bw_cap = 0;
+       u32 bw_cap[2] = { 0, 0 };
        s8 phy;
        s32 err;
        u32 nband;
        s32 i;
-       struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
-       s32 index;
+       struct ieee80211_supported_band *bands[2] = { NULL, NULL };
+       struct ieee80211_supported_band *band;
 
        err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
                                     &phy_list, sizeof(phy_list));
@@ -5253,11 +5297,10 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        if (err) {
                brcmf_err("nmode error (%d)\n", err);
        } else {
-               err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
-               if (err)
-                       brcmf_err("mimo_bw_cap error (%d)\n", err);
+               brcmf_get_bwcap(ifp, bw_cap);
        }
-       brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
+       brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
+                 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 
        err = brcmf_construct_reginfo(cfg, bw_cap);
        if (err) {
@@ -5266,40 +5309,33 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        }
 
        nband = band_list[0];
-       memset(bands, 0, sizeof(bands));
 
        for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
-               index = -1;
+               band = NULL;
                if ((band_list[i] == WLC_BAND_5G) &&
-                   (__wl_band_5ghz_a.n_channels > 0)) {
-                       index = IEEE80211_BAND_5GHZ;
-                       bands[index] = &__wl_band_5ghz_a;
-                       if ((bw_cap == WLC_N_BW_40ALL) ||
-                           (bw_cap == WLC_N_BW_20IN2G_40IN5G))
-                               bands[index]->ht_cap.cap |=
-                                                       IEEE80211_HT_CAP_SGI_40;
-               } else if ((band_list[i] == WLC_BAND_2G) &&
-                          (__wl_band_2ghz.n_channels > 0)) {
-                       index = IEEE80211_BAND_2GHZ;
-                       bands[index] = &__wl_band_2ghz;
-                       if (bw_cap == WLC_N_BW_40ALL)
-                               bands[index]->ht_cap.cap |=
-                                                       IEEE80211_HT_CAP_SGI_40;
-               }
+                   (__wl_band_5ghz_a.n_channels > 0))
+                       band = &__wl_band_5ghz_a;
+               else if ((band_list[i] == WLC_BAND_2G) &&
+                        (__wl_band_2ghz.n_channels > 0))
+                       band = &__wl_band_2ghz;
+               else
+                       continue;
 
-               if ((index >= 0) && nmode) {
-                       bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
-                       bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
-                       bands[index]->ht_cap.ht_supported = true;
-                       bands[index]->ht_cap.ampdu_factor =
-                                               IEEE80211_HT_MAX_AMPDU_64K;
-                       bands[index]->ht_cap.ampdu_density =
-                                               IEEE80211_HT_MPDU_DENSITY_16;
-                       /* An HT shall support all EQM rates for one spatial
-                        * stream
-                        */
-                       bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+               if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
+                       band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+                       band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
                }
+               band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+               band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+               band->ht_cap.ht_supported = true;
+               band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+               band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+               /* An HT shall support all EQM rates for one spatial
+                * stream
+                */
+               band->ht_cap.mcs.rx_mask[0] = 0xff;
+               band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+               bands[band->band] = band;
        }
 
        wiphy = cfg_to_wiphy(cfg);
index d9bdaf9..2dc6a07 100644 (file)
@@ -412,7 +412,6 @@ struct brcmf_cfg80211_info {
        struct work_struct escan_timeout_work;
        u8 *escan_ioctl_buf;
        struct list_head vif_list;
-       u8 vif_cnt;
        struct brcmf_cfg80211_vif_event vif_event;
        struct completion vif_disabled;
        struct brcmu_d11inf d11inf;
@@ -487,8 +486,7 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
                                           enum nl80211_iftype type,
                                           bool pm_block);
-void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
-                   struct brcmf_cfg80211_vif *vif);
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
 
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
                          const u8 *vndr_ie_buf, u32 vndr_ie_len);
@@ -507,5 +505,6 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                                bool fw_abort);
 void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
 void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
+void brcmf_cfg80211_free_netdev(struct net_device *ndev);
 
 #endif                         /* _wl_cfg80211_h_ */
index 84113ea..6fa5d48 100644 (file)
@@ -41,6 +41,7 @@
 #define BCM4331_CHIP_ID                0x4331
 #define BCM4334_CHIP_ID                0x4334
 #define BCM4335_CHIP_ID                0x4335
+#define BCM43362_CHIP_ID       43362
 #define BCM4339_CHIP_ID                0x4339
 
 #endif                         /* _BRCM_HW_IDS_H_ */
index 0505cc0..7ca2aa1 100644 (file)
 #define WLC_N_BW_40ALL                 1
 #define WLC_N_BW_20IN2G_40IN5G         2
 
+#define WLC_BW_20MHZ_BIT               BIT(0)
+#define WLC_BW_40MHZ_BIT               BIT(1)
+#define WLC_BW_80MHZ_BIT               BIT(2)
+#define WLC_BW_160MHZ_BIT              BIT(3)
+
+/* Bandwidth capabilities */
+#define WLC_BW_CAP_20MHZ               (WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_40MHZ               (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_80MHZ               (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT| \
+                                        WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_160MHZ              (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \
+                                        WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_UNRESTRICTED                0xFF
+
 /* band types */
 #define        WLC_BAND_AUTO                   0       /* auto-select */
 #define        WLC_BAND_5G                     1       /* 5 Ghz */
index acdff0f..5a9ffd3 100644 (file)
@@ -14,7 +14,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #include <linux/firmware.h>
index 090f015..d1270da 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
index b37abb9..6907c8f 100644 (file)
@@ -225,7 +225,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                cw1200_set_pm(priv, &priv->powersave_mode);
                if (wait_event_interruptible_timeout(priv->ps_mode_switch_done,
                                                     !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) {
-                       goto revert3;
+                       goto revert4;
                }
        }
 
@@ -254,11 +254,11 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        /* Stop serving thread */
        if (cw1200_bh_suspend(priv))
-               goto revert4;
+               goto revert5;
 
        ret = timer_pending(&priv->mcast_timeout);
        if (ret)
-               goto revert5;
+               goto revert6;
 
        /* Store suspend state */
        pm_state->suspend_state = state;
@@ -280,9 +280,9 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        return 0;
 
-revert5:
+revert6:
        WARN_ON(cw1200_bh_resume(priv));
-revert4:
+revert5:
        cw1200_resume_work(priv, &priv->bss_loss_work,
                           state->bss_loss_tmo);
        cw1200_resume_work(priv, &priv->join_timeout,
@@ -291,6 +291,7 @@ revert4:
                           state->direct_probe);
        cw1200_resume_work(priv, &priv->link_id_gc_work,
                           state->link_id_gc);
+revert4:
        kfree(state);
 revert3:
        wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
index 56cd01c..9f825f2 100644 (file)
@@ -1,7 +1,6 @@
 #define PRISM2_PCCARD
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/if.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
index 2454a74..3e5fa78 100644 (file)
@@ -2567,7 +2567,7 @@ static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
                local->passive_scan_interval = value;
                if (timer_pending(&local->passive_scan_timer))
                        del_timer(&local->passive_scan_timer);
-               if (value > 0) {
+               if (value > 0 && value < INT_MAX / HZ) {
                        local->passive_scan_timer.expires = jiffies +
                                local->passive_scan_interval * HZ;
                        add_timer(&local->passive_scan_timer);
index 05ca340..91158e2 100644 (file)
@@ -5,7 +5,6 @@
  * Andy Warner <andyw@pobox.com> */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
index c3d067e..3bf530d 100644 (file)
@@ -8,7 +8,6 @@
 
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
index 570d6fb..aa301d1 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
index 5c62538..a586a85 100644 (file)
@@ -1468,7 +1468,7 @@ static inline int is_same_network(struct libipw_network *src,
         * as one network */
        return ((src->ssid_len == dst->ssid_len) &&
                (src->channel == dst->channel) &&
-               ether_addr_equal(src->bssid, dst->bssid) &&
+               ether_addr_equal_64bits(src->bssid, dst->bssid) &&
                !memcmp(src->ssid, dst->ssid, src->ssid_len));
 }
 
index aea667b..9a45f6f 100644 (file)
@@ -25,7 +25,6 @@
  *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index f09e257..d37a6fd 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
@@ -466,10 +465,10 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header)
        switch (il->iw_mode) {
        case NL80211_IFTYPE_ADHOC:      /* Header: Dest. | Source    | BSSID */
                /* packets to our IBSS update information */
-               return ether_addr_equal(header->addr3, il->bssid);
+               return ether_addr_equal_64bits(header->addr3, il->bssid);
        case NL80211_IFTYPE_STATION:    /* Header: Dest. | AP{BSSID} | Source */
                /* packets to our IBSS update information */
-               return ether_addr_equal(header->addr2, il->bssid);
+               return ether_addr_equal_64bits(header->addr2, il->bssid);
        default:
                return 1;
        }
index 3ccbaf7..4d5e332 100644 (file)
@@ -24,7 +24,6 @@
  *
  *****************************************************************************/
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index 777a578..fe47db9 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index a27b14c..02e8233 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/lockdep.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
@@ -3746,10 +3745,10 @@ il_full_rxon_required(struct il_priv *il)
 
        /* These items are only settable from the full RXON command */
        CHK(!il_is_associated(il));
-       CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
-       CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
-       CHK(!ether_addr_equal(staging->wlap_bssid_addr,
-                             active->wlap_bssid_addr));
+       CHK(!ether_addr_equal_64bits(staging->bssid_addr, active->bssid_addr));
+       CHK(!ether_addr_equal_64bits(staging->node_addr, active->node_addr));
+       CHK(!ether_addr_equal_64bits(staging->wlap_bssid_addr,
+                                    active->wlap_bssid_addr));
        CHK_NEQ(staging->dev_type, active->dev_type);
        CHK_NEQ(staging->channel, active->channel);
        CHK_NEQ(staging->air_propagation, active->air_propagation);
index 23d5f02..562772d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1b0f0d5..be1086c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cfddde1..aeae4e8 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ebdac90..751ae1d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f69301e..d2fe259 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 7434d9e..3441f70 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 352c6cb..7b140e4 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 33c7e15..ca4d669 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -27,7 +27,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
index 8749dcf..6a0817d 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 3d5bdc4..576f7ee 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -29,7 +29,6 @@
 #include <linux/etherdevice.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <net/mac80211.h>
 
index 9f4239d..40eb5e6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -28,7 +28,6 @@
  *****************************************************************************/
 #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>
index fd9f6cf..ba1b1ea 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
index 77cb597..b4e6141 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <net/mac80211.h>
 #include "iwl-io.h"
 #include "iwl-debug.h"
index 7b03e13..570d3a5 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
index b647e50..0977d93 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -24,7 +24,6 @@
  *
  *****************************************************************************/
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index 41988f4..bdd5644 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index d71776d..b68bb2f 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portionhelp of the ieee80211 subsystem header files.
index d7ce2f1..503a81e 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 928f864..be98b91 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index c3c13ce..c0d070c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
index fbeee08..058c589 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <net/mac80211.h>
 #include "iwl-io.h"
 #include "iwl-modparams.h"
index 9356c4b..5077265 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
index e12b1a6..a6839df 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -29,7 +29,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ieee80211.h>
 #include "iwl-io.h"
index 6363794..f59709a 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -28,7 +28,6 @@
  *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 
 #include "iwl-io.h"
 #include "iwl-agn-hw.h"
index 0d2afe0..854ba84 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index c727ec7..3e63323 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index ecc01e1..6674f2c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 8ac305b..8048de9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 5fb3772..2a59da2 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6d73f94..7f37fb8 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e05440f..1ced525 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index da4eca8..9d32551 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
                                 CSR_INT_BIT_RF_KILL | \
                                 CSR_INT_BIT_SW_RX   | \
                                 CSR_INT_BIT_WAKEUP  | \
-                                CSR_INT_BIT_ALIVE)
+                                CSR_INT_BIT_ALIVE   | \
+                                CSR_INT_BIT_RX_PERIODIC)
 
 /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
 #define CSR_FH_INT_BIT_ERR       (1 << 31) /* Error */
index b2bb32a..a75aac9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index 8f61c71..23e7351 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 684c416..78bd41b 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 4bebfb5..c372816 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 429337a..592c01e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,7 +67,7 @@
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
 #define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT  "Copyright(c) 2003-2013 Intel Corporation"
+#define DRV_COPYRIGHT  "Copyright(c) 2003- 2014 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 
index 4380c16..c44cf11 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d73304a..e3c7dea 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e5f2e36..25d0105 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8e941f8..a6d3bdf 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 484d318..9564ae1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4f95734..88e2d6e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8704e30..5f1493c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ad8e19a..f98175a 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index 63d10ec..c339c1b 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index a1f580c..0a84ade 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 940b8a9..b5bc959 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2e2f1c8..95af97a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a48decc..1b61cb5 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3325059..0c4399a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f50e6c6..b5be51f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1a405ae..fa77d63 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ce983af..9ee18d0 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f6412da..d69b0fb 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0c36478..8d1b5ed 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -622,6 +622,10 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 {
        int ret;
 
+       if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
+                    test_bit(STATUS_RFKILL, &trans->status)))
+               return -ERFKILL;
+
        if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
                return -EIO;
 
@@ -684,9 +688,6 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
 
 static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
 {
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
-               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
-
        trans->ops->txq_disable(trans, queue);
 }
 
index 57d3eed..a137653 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d126245..76cde6c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -294,9 +294,9 @@ static const __le64 iwl_ci_mask[][3] = {
                cpu_to_le64(0x0)
        },
        {
-               cpu_to_le64(0xFE00000000ULL),
+               cpu_to_le64(0xFFC0000000ULL),
                cpu_to_le64(0x0ULL),
-               cpu_to_le64(0x0)
+               cpu_to_le64(0x0ULL)
        },
 };
 
index 4b6d670..0368576 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 665f87e..f04d2f4 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b866757..0e29cd8 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e8f62a6..76cdce9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -123,51 +123,31 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 {
        struct iwl_mvm *mvm = file->private_data;
        const struct fw_img *img;
-       int ofs, len, pos = 0;
-       size_t bufsz, ret;
-       char *buf;
+       unsigned int ofs, len;
+       size_t ret;
        u8 *ptr;
 
        if (!mvm->ucode_loaded)
                return -EINVAL;
 
        /* default is to dump the entire data segment */
+       img = &mvm->fw->img[mvm->cur_ucode];
+       ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
+       len = img->sec[IWL_UCODE_SECTION_DATA].len;
+
        if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
-               img = &mvm->fw->img[mvm->cur_ucode];
-               ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
-               len = img->sec[IWL_UCODE_SECTION_DATA].len;
-       } else {
                ofs = mvm->dbgfs_sram_offset;
                len = mvm->dbgfs_sram_len;
        }
 
-       bufsz = len * 4 + 256;
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
        ptr = kzalloc(len, GFP_KERNEL);
-       if (!ptr) {
-               kfree(buf);
+       if (!ptr)
                return -ENOMEM;
-       }
-
-       pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
-       pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", ofs);
 
        iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
-       for (ofs = 0; ofs < len; ofs += 16) {
-               pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
-               hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
-                                  bufsz - pos, false);
-               pos += strlen(buf + pos);
-               if (bufsz - pos > 0)
-                       buf[pos++] = '\n';
-       }
 
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
 
-       kfree(buf);
        kfree(ptr);
 
        return ret;
@@ -176,11 +156,24 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
                                    size_t count, loff_t *ppos)
 {
+       const struct fw_img *img;
        u32 offset, len;
+       u32 img_offset, img_len;
+
+       if (!mvm->ucode_loaded)
+               return -EINVAL;
+
+       img = &mvm->fw->img[mvm->cur_ucode];
+       img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
+       img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
 
        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
                if ((offset & 0x3) || (len & 0x3))
                        return -EINVAL;
+
+               if (offset + len > img_offset + img_len)
+                       return -EINVAL;
+
                mvm->dbgfs_sram_offset = offset;
                mvm->dbgfs_sram_len = len;
        } else {
index 85f9f95..e3a9774 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index af50099..1b4e54d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4e7dd8c..8415ff3 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 39c3148..c405cda 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cb78e55..884c087 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 532312c..8505721 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b3ed592..73cbba7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8c73ba7..6bbbad4 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2286467..b674c2a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1c30797..989d7db 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 27ba104..c03d395 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2269a9e..6b4ea6b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -103,7 +103,7 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
                return 0;
        default:
                return -EINVAL;
-       };
+       }
 
        mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
                                   wiphy_name(mvm->hw->wiphy));
index fb93961..ba723d5 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "mvm.h"
 
 const u8 iwl_mvm_ac_to_tx_fifo[] = {
-       IWL_MVM_TX_FIFO_BK,
-       IWL_MVM_TX_FIFO_BE,
-       IWL_MVM_TX_FIFO_VI,
        IWL_MVM_TX_FIFO_VO,
+       IWL_MVM_TX_FIFO_VI,
+       IWL_MVM_TX_FIFO_BE,
+       IWL_MVM_TX_FIFO_BK,
 };
 
 struct iwl_mvm_mac_iface_iterator_data {
@@ -85,35 +85,15 @@ struct iwl_mvm_mac_iface_iterator_data {
        bool found_vif;
 };
 
-static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
-                                      struct ieee80211_vif *vif)
+static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
+                                   struct ieee80211_vif *vif)
 {
        struct iwl_mvm_mac_iface_iterator_data *data = _data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       u32 ac;
 
-       /* Iterator may already find the interface being added -- skip it */
-       if (vif == data->vif) {
-               data->found_vif = true;
+       /* Skip the interface for which we are trying to assign a tsf_id  */
+       if (vif == data->vif)
                return;
-       }
-
-       /* Mark the queues used by the vif */
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-                       __set_bit(vif->hw_queue[ac], data->used_hw_queues);
-
-       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-               __set_bit(vif->cab_queue, data->used_hw_queues);
-
-       /*
-        * Mark MAC IDs as used by clearing the available bit, and
-        * (below) mark TSFs as used if their existing use is not
-        * compatible with the new interface type.
-        * No locking or atomic bit operations are needed since the
-        * data is on the stack of the caller function.
-        */
-       __clear_bit(mvmvif->id, data->available_mac_ids);
 
        /*
         * The TSF is a hardware/firmware resource, there are 4 and
@@ -135,21 +115,26 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
        case NL80211_IFTYPE_STATION:
                /*
                 * The new interface is client, so if the existing one
-                * we're iterating is an AP, the TSF should be used to
+                * we're iterating is an AP, and both interfaces have the
+                * same beacon interval, the same TSF should be used to
                 * avoid drift between the new client and existing AP,
                 * the existing AP will get drift updates from the new
                 * client context in this case
                 */
                if (vif->type == NL80211_IFTYPE_AP) {
                        if (data->preferred_tsf == NUM_TSF_IDS &&
-                           test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+                           test_bit(mvmvif->tsf_id, data->available_tsf_ids) &&
+                           (vif->bss_conf.beacon_int ==
+                            data->vif->bss_conf.beacon_int)) {
                                data->preferred_tsf = mvmvif->tsf_id;
-                       return;
+                               return;
+                       }
                }
                break;
        case NL80211_IFTYPE_AP:
                /*
-                * The new interface is AP/GO, so should get drift
+                * The new interface is AP/GO, so in case both interfaces
+                * have the same beacon interval, it should get drift
                 * updates from an existing client or use the same
                 * TSF as an existing GO. There's no drift between
                 * TSFs internally but if they used different TSFs
@@ -159,9 +144,12 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
                if (vif->type == NL80211_IFTYPE_STATION ||
                    vif->type == NL80211_IFTYPE_AP) {
                        if (data->preferred_tsf == NUM_TSF_IDS &&
-                           test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+                           test_bit(mvmvif->tsf_id, data->available_tsf_ids) &&
+                           (vif->bss_conf.beacon_int ==
+                            data->vif->bss_conf.beacon_int)) {
                                data->preferred_tsf = mvmvif->tsf_id;
-                       return;
+                               return;
+                       }
                }
                break;
        default:
@@ -187,6 +175,39 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
                data->preferred_tsf = NUM_TSF_IDS;
 }
 
+static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
+                                      struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_mac_iface_iterator_data *data = _data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       u32 ac;
+
+       /* Iterator may already find the interface being added -- skip it */
+       if (vif == data->vif) {
+               data->found_vif = true;
+               return;
+       }
+
+       /* Mark the queues used by the vif */
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+                       __set_bit(vif->hw_queue[ac], data->used_hw_queues);
+
+       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+               __set_bit(vif->cab_queue, data->used_hw_queues);
+
+       /* Mark MAC IDs as used by clearing the available bit, and
+        * (below) mark TSFs as used if their existing use is not
+        * compatible with the new interface type.
+        * No locking or atomic bit operations are needed since the
+        * data is on the stack of the caller function.
+        */
+       __clear_bit(mvmvif->id, data->available_mac_ids);
+
+       /* find a suitable tsf_id */
+       iwl_mvm_mac_tsf_id_iter(_data, mac, vif);
+}
+
 /*
  * Get the mask of the queus used by the vif
  */
@@ -205,6 +226,29 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
        return qmask;
 }
 
+void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm_mac_iface_iterator_data data = {
+               .mvm = mvm,
+               .vif = vif,
+               .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
+               /* no preference yet */
+               .preferred_tsf = NUM_TSF_IDS,
+       };
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               iwl_mvm_mac_tsf_id_iter, &data);
+
+       if (data.preferred_tsf != NUM_TSF_IDS)
+               mvmvif->tsf_id = data.preferred_tsf;
+       else if (!test_bit(mvmvif->tsf_id, data.available_tsf_ids))
+               mvmvif->tsf_id = find_first_bit(data.available_tsf_ids,
+                                               NUM_TSF_IDS);
+}
+
 static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
                                               struct ieee80211_vif *vif)
 {
@@ -586,18 +630,23 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                cpu_to_le32(vif->bss_conf.use_short_slot ?
                            MAC_FLG_SHORT_SLOT : 0);
 
-       for (i = 0; i < AC_NUM; i++) {
-               cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min);
-               cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max);
-               cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs;
-               cmd->ac[i].edca_txop =
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+               u8 txf = iwl_mvm_ac_to_tx_fifo[i];
+
+               cmd->ac[txf].cw_min =
+                       cpu_to_le16(mvmvif->queue_params[i].cw_min);
+               cmd->ac[txf].cw_max =
+                       cpu_to_le16(mvmvif->queue_params[i].cw_max);
+               cmd->ac[txf].edca_txop =
                        cpu_to_le16(mvmvif->queue_params[i].txop * 32);
-               cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);
+               cmd->ac[txf].aifsn = mvmvif->queue_params[i].aifs;
+               cmd->ac[txf].fifos_mask = BIT(txf);
        }
 
        /* in AP mode, the MCAST FIFO takes the EDCA params from VO */
        if (vif->type == NL80211_IFTYPE_AP)
-               cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST);
+               cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |=
+                       BIT(IWL_MVM_TX_FIFO_MCAST);
 
        if (vif->bss_conf.qos)
                cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
@@ -1007,7 +1056,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
                        iwl_mvm_mac_ap_iterator, &data);
 
                if (data.beacon_device_ts) {
-                       u32 rand = (prandom_u32() % (80 - 20)) + 20;
+                       u32 rand = (prandom_u32() % (64 - 36)) + 36;
                        mvmvif->ap_beacon_time = data.beacon_device_ts +
                                ieee80211_tu_to_usec(data.beacon_int * rand /
                                                     100);
@@ -1186,10 +1235,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
 static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
                                         struct ieee80211_vif *vif)
 {
-       u16 *id = _data;
+       struct iwl_missed_beacons_notif *missed_beacons = _data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
-       if (mvmvif->id == *id)
+       if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id))
+               return;
+
+       /*
+        * TODO: the threshold should be adjusted based on latency conditions,
+        * and/or in case of a CS flow on one of the other AP vifs.
+        */
+       if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) >
+            IWL_MVM_MISSED_BEACONS_THRESHOLD)
                ieee80211_beacon_loss(vif);
 }
 
@@ -1198,12 +1255,19 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data;
-       u16 id = (u16)le32_to_cpu(missed_beacons->mac_id);
+       struct iwl_missed_beacons_notif *mb = (void *)pkt->data;
+
+       IWL_DEBUG_INFO(mvm,
+                      "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
+                      le32_to_cpu(mb->mac_id),
+                      le32_to_cpu(mb->consec_missed_beacons),
+                      le32_to_cpu(mb->consec_missed_beacons_since_last_rx),
+                      le32_to_cpu(mb->num_recvd_beacons),
+                      le32_to_cpu(mb->num_expected_beacons));
 
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
                                                   IEEE80211_IFACE_ITER_NORMAL,
                                                   iwl_mvm_beacon_loss_iterator,
-                                                  &id);
+                                                  mb);
        return 0;
 }
index 2f52693..b41177e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -262,7 +262,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 
        /* currently FW API supports only one optional cipher scheme */
-       if (mvm->fw->cs && mvm->fw->cs->cipher) {
+       if (mvm->fw->cs->cipher) {
                mvm->hw->n_cipher_schemes = 1;
                mvm->hw->cipher_schemes = mvm->fw->cs;
        }
@@ -866,6 +866,14 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
 
+       /*
+        * Re-calculate the tsf id, as the master-slave relations depend on the
+        * beacon interval, which was not known when the station interface was
+        * added.
+        */
+       if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
+               iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
+
        ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
        if (ret)
                IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
@@ -979,6 +987,13 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
        if (ret)
                goto out_unlock;
 
+       /*
+        * Re-calculate the tsf id, as the master-slave relations depend on the
+        * beacon interval, which was not known when the AP interface was added.
+        */
+       if (vif->type == NL80211_IFTYPE_AP)
+               iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
+
        /* Add the mac context */
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
@@ -1671,7 +1686,8 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
        if (WARN_ONCE((phy_ctxt->ref > 1) &&
                      (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
                                   IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
-                                  IEEE80211_CHANCTX_CHANGE_RADAR)),
+                                  IEEE80211_CHANCTX_CHANGE_RADAR |
+                                  IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)),
                      "Cannot change PHY. Ref=%d, changed=0x%X\n",
                      phy_ctxt->ref, changed))
                return;
index 84edf36..e4ead86 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,6 +81,7 @@
 #define IWL_MVM_MAX_ADDRESSES          5
 /* RSSI offset for WkP */
 #define IWL_RSSI_OFFSET 50
+#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8
 
 enum iwl_mvm_tx_fifo {
        IWL_MVM_TX_FIFO_BK = 0,
@@ -711,6 +712,8 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
 int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                    struct iwl_rx_cmd_buffer *rxb,
                                    struct iwl_device_cmd *cmd);
+void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif);
 
 /* Bindings */
 int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
index 48089b1..c6beb0f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -367,16 +367,17 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
                        break;
                }
 
+               if (WARN(section_id >= NVM_NUM_OF_SECTIONS,
+                        "Invalid NVM section ID %d\n", section_id)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
                if (!temp) {
                        ret = -ENOMEM;
                        break;
                }
-               if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) {
-                       IWL_ERR(mvm, "Invalid NVM section ID\n");
-                       ret = -EINVAL;
-                       break;
-               }
                mvm->nvm_sections[section_id].data = temp;
                mvm->nvm_sections[section_id].length = section_size;
 
index a362430..552c76a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -665,6 +665,8 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
        else
                clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
 
+       if (state && mvm->cur_ucode != IWL_UCODE_INIT)
+               iwl_trans_stop_device(mvm->trans);
        wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
 }
 
index a8652dd..b7268c0 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 483ecc6..d9eab3b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 
 #include <net/mac80211.h>
 
index 2ce79ba..ef712ae 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 38165eb..ce5db6c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d6d28d7..ba078a3 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -24,7 +24,6 @@
  *
  *****************************************************************************/
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
@@ -700,7 +699,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
        u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate);
        u8 nss;
 
-       memset(rate, 0, sizeof(struct rs_rate));
+       memset(rate, 0, sizeof(*rate));
        rate->index = iwl_hwrate_to_plcp_idx(ucode_rate);
 
        if (rate->index == IWL_RATE_INVALID) {
@@ -2121,7 +2120,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
                tbl->column = RS_COLUMN_LEGACY_ANT_B;
 
        rs_set_expected_tpt_table(lq_sta, tbl);
-       rs_fill_lq_cmd(NULL, NULL, lq_sta, rate);
+       rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
        /* TODO restore station should remember the lq cmd */
        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init);
 }
@@ -2446,10 +2445,9 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
        struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
        bool toggle_ant = false;
 
-       memcpy(&rate, initial_rate, sizeof(struct rs_rate));
+       memcpy(&rate, initial_rate, sizeof(rate));
 
-       if (mvm)
-               valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+       valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
 
        if (is_siso(&rate)) {
                num_rates = RS_INITIAL_SISO_NUM_RATES;
@@ -2623,7 +2621,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
                struct rs_rate rate;
                rs_rate_from_ucode_rate(lq_sta->dbg_fixed_rate,
                                        lq_sta->band, &rate);
-               rs_fill_lq_cmd(NULL, NULL, lq_sta, &rate);
+               rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate);
                iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
        }
 }
index c31aa59..7bc6404 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 454341c..a85b60f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ce9bb5..0e00079 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -473,13 +473,18 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return;
 
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ieee80211_scan_completed(mvm->hw, true);
+               mvm->scan_status = IWL_MVM_SCAN_NONE;
+               return;
+       }
+
        iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
                                   scan_abort_notif,
                                   ARRAY_SIZE(scan_abort_notif),
                                   iwl_mvm_scan_abort_notif, NULL);
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD,
-                                  CMD_SYNC | CMD_SEND_IN_RFKILL, 0, NULL);
+       ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL);
        if (ret) {
                IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
                /* mac80211's state will be cleaned in the fw_restart flow */
index 97bb3c3..8401627 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0a8af20..ec18121 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b349411..4968d02 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eb74391..0241665 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 95ce4b6..50f3d7f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d9c8d6c..4a61c8c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a0ec7b3..3afa6b6 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 735f86d..3c575a3 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f4aff56..487d61b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2e97a39..3040924 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -362,21 +362,27 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095B, 0x5012, iwl7265_2ac_cfg)},
-       {IWL_PCI_DEVICE(0x095B, 0x500A, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5000, iwl7265_2n_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5200, iwl7265_2n_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5002, iwl7265_n_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5420, iwl7265_2n_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5090, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x5190, iwl7265_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)},
        {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)},
 #endif /* CONFIG_IWLMVM */
index 674c75b..e851f26 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -262,6 +262,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  * @rx_page_order: page order for receive buffer size
  * @wd_timeout: queue watchdog timeout (jiffies)
  * @reg_lock: protect hw register access
+ * @cmd_in_flight: true when we have a host command in flight
  */
 struct iwl_trans_pcie {
        struct iwl_rxq rxq;
@@ -273,7 +274,6 @@ struct iwl_trans_pcie {
        __le32 *ict_tbl;
        dma_addr_t ict_tbl_dma;
        int ict_index;
-       u32 inta;
        bool use_ict;
        struct isr_statistics isr_stats;
 
@@ -311,6 +311,7 @@ struct iwl_trans_pcie {
 
        /*protect hw register */
        spinlock_t reg_lock;
+       bool cmd_in_flight;
 };
 
 #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
@@ -343,7 +344,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans);
 /*****************************************************
 * ICT - interrupt handling
 ******************************************************/
-irqreturn_t iwl_pcie_isr_ict(int irq, void *data);
+irqreturn_t iwl_pcie_isr(int irq, void *data);
 int iwl_pcie_alloc_ict(struct iwl_trans *trans);
 void iwl_pcie_free_ict(struct iwl_trans *trans);
 void iwl_pcie_reset_ict(struct iwl_trans *trans);
@@ -397,13 +398,17 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
 
        IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
        set_bit(STATUS_INT_ENABLED, &trans->status);
+       trans_pcie->inta_mask = CSR_INI_SET_MASK;
        iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
 }
 
 static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
        IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-       iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+       trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL;
+       iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
@@ -456,4 +461,31 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
 }
 
+static inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
+                                                 u32 reg, u32 mask, u32 value)
+{
+       u32 v;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       WARN_ON_ONCE(value & ~mask);
+#endif
+
+       v = iwl_read32(trans, reg);
+       v &= ~mask;
+       v |= value;
+       iwl_write32(trans, reg, v);
+}
+
+static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
+                                             u32 reg, u32 mask)
+{
+       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
+}
+
+static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
+                                           u32 reg, u32 mask)
+{
+       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
+}
+
 #endif /* __iwl_trans_int_pcie_h__ */
index 7aeec5c..1890ea2 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -148,10 +148,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans)
 static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
                                    struct iwl_rxq *rxq)
 {
-       unsigned long flags;
        u32 reg;
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
 
        if (rxq->need_update == 0)
                goto exit_unlock;
@@ -190,7 +189,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
        rxq->need_update = 0;
 
  exit_unlock:
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 }
 
 /*
@@ -209,7 +208,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
-       unsigned long flags;
 
        /*
         * If the device isn't enabled - not need to try to add buffers...
@@ -222,7 +220,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
                return;
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
        while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) {
                /* The overwritten rxb must be a used one */
                rxb = rxq->queue[rxq->write];
@@ -239,7 +237,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
                rxq->free_count--;
        }
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
        /* If the pre-allocated buffer pool is dropping low, schedule to
         * refill it */
        if (rxq->free_count <= RX_LOW_WATERMARK)
@@ -248,9 +246,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        /* If we've added more space for the firmware to place data, tell it.
         * Increment device's write pointer in multiples of 8. */
        if (rxq->write_actual != (rxq->write & ~0x7)) {
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
                rxq->need_update = 1;
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
                iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
        }
 }
@@ -270,16 +268,15 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
-       unsigned long flags;
        gfp_t gfp_mask = priority;
 
        while (1) {
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
                if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       spin_unlock(&rxq->lock);
                        return;
                }
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
 
                if (rxq->free_count > RX_LOW_WATERMARK)
                        gfp_mask |= __GFP_NOWARN;
@@ -308,17 +305,17 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                        return;
                }
 
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
 
                if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       spin_unlock(&rxq->lock);
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
                rxb = list_first_entry(&rxq->rx_used, struct iwl_rx_mem_buffer,
                                       list);
                list_del(&rxb->list);
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
 
                BUG_ON(rxb->page);
                rxb->page = page;
@@ -329,9 +326,9 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                                     DMA_FROM_DEVICE);
                if (dma_mapping_error(trans->dev, rxb->page_dma)) {
                        rxb->page = NULL;
-                       spin_lock_irqsave(&rxq->lock, flags);
+                       spin_lock(&rxq->lock);
                        list_add(&rxb->list, &rxq->rx_used);
-                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       spin_unlock(&rxq->lock);
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
@@ -340,12 +337,12 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                /* and also 256 byte aligned! */
                BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
 
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
 
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
 
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
        }
 }
 
@@ -379,13 +376,12 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
 static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
        iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_pcie_rxq_restock(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 }
 
 static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans)
@@ -511,7 +507,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        int i, err;
-       unsigned long flags;
 
        if (!rxq->bd) {
                err = iwl_pcie_rx_alloc(trans);
@@ -519,7 +514,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
                        return err;
        }
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
 
        INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work);
 
@@ -535,16 +530,16 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        rxq->read = rxq->write = 0;
        rxq->write_actual = 0;
        memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 
        iwl_pcie_rx_replenish(trans);
 
        iwl_pcie_rx_hw_init(trans, rxq);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        rxq->need_update = 1;
        iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        return 0;
 }
@@ -553,7 +548,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       unsigned long flags;
 
        /*if rxq->bd is NULL, it means that nothing has been allocated,
         * exit now */
@@ -564,9 +558,9 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
 
        cancel_work_sync(&trans_pcie->rx_replenish);
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
        iwl_pcie_rxq_free_rbs(trans);
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 
        dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
                          rxq->bd, rxq->bd_dma);
@@ -589,7 +583,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-       unsigned long flags;
        bool page_stolen = false;
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
        u32 offset = 0;
@@ -691,7 +684,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
        /* Reuse the page if possible. For notification packets and
         * SKBs that fail to Rx correctly, add them back into the
         * rx_free list for reuse later. */
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
        if (rxb->page != NULL) {
                rxb->page_dma =
                        dma_map_page(trans->dev, rxb->page, 0,
@@ -712,7 +705,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                }
        } else
                list_add_tail(&rxb->list, &rxq->rx_used);
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 }
 
 /*
@@ -807,6 +800,87 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
        wake_up(&trans_pcie->wait_command_queue);
 }
 
+static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 inta;
+
+       lockdep_assert_held(&trans_pcie->irq_lock);
+
+       trace_iwlwifi_dev_irq(trans->dev);
+
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(trans, CSR_INT);
+
+       /* the thread will service interrupts and re-enable them */
+       return inta;
+}
+
+/* a device (PCI-E) page is 4096 bytes long */
+#define ICT_SHIFT      12
+#define ICT_SIZE       (1 << ICT_SHIFT)
+#define ICT_COUNT      (ICT_SIZE / sizeof(u32))
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 inta;
+       u32 val = 0;
+       u32 read;
+
+       trace_iwlwifi_dev_irq(trans->dev);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
+       if (!read)
+               return 0;
+
+       /*
+        * Collect all entries up to the first 0, starting from ict_index;
+        * note we already read at ict_index.
+        */
+       do {
+               val |= read;
+               IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
+                               trans_pcie->ict_index, read);
+               trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
+               trans_pcie->ict_index =
+                       iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
+
+               read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
+                                          read);
+       } while (read);
+
+       /* We should not get this value, just ignore it. */
+       if (val == 0xffffffff)
+               val = 0;
+
+       /*
+        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+        * (bit 15 before shifting it to 31) to clear when using interrupt
+        * coalescing. fortunately, bits 18 and 19 stay set when this happens
+        * so we use them to decide on the real state of the Rx bit.
+        * In order words, bit 15 is set if bit 18 or bit 19 are set.
+        */
+       if (val & 0xC0000)
+               val |= 0x8000;
+
+       inta = (0xff & val) | ((0xff00 & val) << 16);
+       return inta;
+}
+
 irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 {
        struct iwl_trans *trans = dev_id;
@@ -814,12 +888,61 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
        struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
        u32 inta = 0;
        u32 handled = 0;
-       unsigned long flags;
        u32 i;
 
        lock_map_acquire(&trans->sync_cmd_lockdep_map);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
+
+       /* dram interrupt table not set yet,
+        * use legacy interrupt.
+        */
+       if (likely(trans_pcie->use_ict))
+               inta = iwl_pcie_int_cause_ict(trans);
+       else
+               inta = iwl_pcie_int_cause_non_ict(trans);
+
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
+               IWL_DEBUG_ISR(trans,
+                             "ISR inta 0x%08x, enabled 0x%08x(sw), enabled(hw) 0x%08x, fh 0x%08x\n",
+                             inta, trans_pcie->inta_mask,
+                             iwl_read32(trans, CSR_INT_MASK),
+                             iwl_read32(trans, CSR_FH_INT_STATUS));
+               if (inta & (~trans_pcie->inta_mask))
+                       IWL_DEBUG_ISR(trans,
+                                     "We got a masked interrupt (0x%08x)\n",
+                                     inta & (~trans_pcie->inta_mask));
+       }
+
+       inta &= trans_pcie->inta_mask;
+
+       /*
+        * Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC.
+        */
+       if (unlikely(!inta)) {
+               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+               /*
+                * Re-enable interrupts here since we don't
+                * have anything to service
+                */
+               if (test_bit(STATUS_INT_ENABLED, &trans->status))
+                       iwl_enable_interrupts(trans);
+               spin_unlock(&trans_pcie->irq_lock);
+               lock_map_release(&trans->sync_cmd_lockdep_map);
+               return IRQ_NONE;
+       }
+
+       if (unlikely(inta == 0xFFFFFFFF || (inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /*
+                * Hardware disappeared. It might have
+                * already raised an interrupt.
+                */
+               IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               spin_unlock(&trans_pcie->irq_lock);
+               goto out;
+       }
 
        /* Ack/clear/reset pending uCode interrupts.
         * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
@@ -832,19 +955,13 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
         * hardware bugs here by ACKing all the possible interrupts so that
         * interrupt coalescing can still be achieved.
         */
-       iwl_write32(trans, CSR_INT,
-                   trans_pcie->inta | ~trans_pcie->inta_mask);
-
-       inta = trans_pcie->inta;
+       iwl_write32(trans, CSR_INT, inta | ~trans_pcie->inta_mask);
 
        if (iwl_have_debug_level(IWL_DL_ISR))
                IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
                              inta, iwl_read32(trans, CSR_INT_MASK));
 
-       /* saved interrupt in inta variable now we can reset trans_pcie->inta */
-       trans_pcie->inta = 0;
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
@@ -1019,11 +1136,6 @@ out:
  *
  ******************************************************************************/
 
-/* a device (PCI-E) page is 4096 bytes long */
-#define ICT_SHIFT      12
-#define ICT_SIZE       (1 << ICT_SHIFT)
-#define ICT_COUNT      (ICT_SIZE / sizeof(u32))
-
 /* Free dram table */
 void iwl_pcie_free_ict(struct iwl_trans *trans)
 {
@@ -1048,7 +1160,7 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        trans_pcie->ict_tbl =
-               dma_alloc_coherent(trans->dev, ICT_SIZE,
+               dma_zalloc_coherent(trans->dev, ICT_SIZE,
                                   &trans_pcie->ict_tbl_dma,
                                   GFP_KERNEL);
        if (!trans_pcie->ict_tbl)
@@ -1060,17 +1172,10 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans)
                return -EINVAL;
        }
 
-       IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
-                     (unsigned long long)trans_pcie->ict_tbl_dma);
-
-       IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
+       IWL_DEBUG_ISR(trans, "ict dma addr %Lx ict vir addr %p\n",
+                     (unsigned long long)trans_pcie->ict_tbl_dma,
+                     trans_pcie->ict_tbl);
 
-       /* reset table and index to all 0 */
-       memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
-       trans_pcie->ict_index = 0;
-
-       /* add periodic RX interrupt */
-       trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
        return 0;
 }
 
@@ -1081,12 +1186,11 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 val;
-       unsigned long flags;
 
        if (!trans_pcie->ict_tbl)
                return;
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
 
        memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
@@ -1103,120 +1207,26 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)
        trans_pcie->ict_index = 0;
        iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
        iwl_enable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 }
 
 /* Device is going down disable ict interrupt usage */
 void iwl_pcie_disable_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        trans_pcie->use_ict = false;
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-/* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */
-static irqreturn_t iwl_pcie_isr(int irq, void *data)
-{
-       struct iwl_trans *trans = data;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 inta, inta_mask;
-
-       lockdep_assert_held(&trans_pcie->irq_lock);
-
-       trace_iwlwifi_dev_irq(trans->dev);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the irq thread will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl_read32(trans, CSR_INT_MASK);
-       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-       /* Discover which interrupts are active/pending */
-       inta = iwl_read32(trans, CSR_INT);
-
-       if (inta & (~inta_mask)) {
-               IWL_DEBUG_ISR(trans,
-                             "We got a masked interrupt (0x%08x)...Ack and ignore\n",
-                             inta & (~inta_mask));
-               iwl_write32(trans, CSR_INT, inta & (~inta_mask));
-               inta &= inta_mask;
-       }
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!inta) {
-               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-               /*
-                * Re-enable interrupts here since we don't have anything to
-                * service, but only in case the handler won't run. Note that
-                * the handler can be scheduled because of a previous
-                * interrupt.
-                */
-               if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
-                   !trans_pcie->inta)
-                       iwl_enable_interrupts(trans);
-               return IRQ_NONE;
-       }
-
-       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-               /* Hardware disappeared. It might have already raised
-                * an interrupt */
-               IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-               return IRQ_HANDLED;
-       }
-
-       if (iwl_have_debug_level(IWL_DL_ISR))
-               IWL_DEBUG_ISR(trans,
-                             "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-                             inta, inta_mask,
-                             iwl_read32(trans, CSR_FH_INT_STATUS));
-
-       trans_pcie->inta |= inta;
-       /* the thread will service interrupts and re-enable them */
-       return IRQ_WAKE_THREAD;
+       spin_unlock(&trans_pcie->irq_lock);
 }
 
-/* interrupt handler using ict table, with this interrupt driver will
- * stop using INTA register to get device's interrupt, reading this register
- * is expensive, device will write interrupts in ICT dram table, increment
- * index then will fire interrupt to driver, driver will OR all ICT table
- * entries from current index up to table entry with 0 value. the result is
- * the interrupt we need to service, driver will set the entries back to 0 and
- * set index.
- */
-irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
+irqreturn_t iwl_pcie_isr(int irq, void *data)
 {
        struct iwl_trans *trans = data;
-       struct iwl_trans_pcie *trans_pcie;
-       u32 inta;
-       u32 val = 0;
-       u32 read;
-       unsigned long flags;
-       irqreturn_t ret = IRQ_NONE;
 
        if (!trans)
                return IRQ_NONE;
 
-       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* dram interrupt table not set yet,
-        * use legacy interrupt.
-        */
-       if (unlikely(!trans_pcie->use_ict)) {
-               ret = iwl_pcie_isr(irq, data);
-               spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-               return ret;
-       }
-
-       trace_iwlwifi_dev_irq(trans->dev);
-
        /* Disable (but don't clear!) interrupts here to avoid
         * back-to-back ISRs and sporadic interrupts from our NIC.
         * If we have something to service, the tasklet will re-enable ints.
@@ -1224,73 +1234,5 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
         */
        iwl_write32(trans, CSR_INT_MASK, 0x00000000);
 
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
-       if (!read) {
-               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-               goto none;
-       }
-
-       /*
-        * Collect all entries up to the first 0, starting from ict_index;
-        * note we already read at ict_index.
-        */
-       do {
-               val |= read;
-               IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
-                               trans_pcie->ict_index, read);
-               trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
-               trans_pcie->ict_index =
-                       iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
-
-               read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
-                                          read);
-       } while (read);
-
-       /* We should not get this value, just ignore it. */
-       if (val == 0xffffffff)
-               val = 0;
-
-       /*
-        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
-        * (bit 15 before shifting it to 31) to clear when using interrupt
-        * coalescing. fortunately, bits 18 and 19 stay set when this happens
-        * so we use them to decide on the real state of the Rx bit.
-        * In order words, bit 15 is set if bit 18 or bit 19 are set.
-        */
-       if (val & 0xC0000)
-               val |= 0x8000;
-
-       inta = (0xff & val) | ((0xff00 & val) << 16);
-       IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled(sw) 0x%08x ict 0x%08x\n",
-                     inta, trans_pcie->inta_mask, val);
-       if (iwl_have_debug_level(IWL_DL_ISR))
-               IWL_DEBUG_ISR(trans, "enabled(hw) 0x%08x\n",
-                             iwl_read32(trans, CSR_INT_MASK));
-
-       inta &= trans_pcie->inta_mask;
-       trans_pcie->inta |= inta;
-
-       /* iwl_pcie_tasklet() will service interrupts and re-enable them */
-       if (likely(inta)) {
-               spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-               return IRQ_WAKE_THREAD;
-       }
-
-       ret = IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service.
-        * only Re-enable if disabled by irq.
-        */
-       if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
-           !trans_pcie->inta)
-               iwl_enable_interrupts(trans);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return ret;
+       return IRQ_WAKE_THREAD;
 }
index eecd38e..16f66c1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "iwl-agn-hw.h"
 #include "internal.h"
 
-static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
-                                                 u32 reg, u32 mask, u32 value)
-{
-       u32 v;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       WARN_ON_ONCE(value & ~mask);
-#endif
-
-       v = iwl_read32(trans, reg);
-       v &= ~mask;
-       v |= value;
-       iwl_write32(trans, reg, v);
-}
-
-static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
-                                             u32 reg, u32 mask)
-{
-       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
-}
-
-static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
-                                           u32 reg, u32 mask)
-{
-       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
-}
-
 static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 {
        if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
@@ -271,13 +244,12 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans)
 static int iwl_pcie_nic_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
        /* nic_init */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_pcie_apm_init(trans);
 
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        iwl_pcie_set_pwr(trans, false);
 
@@ -635,13 +607,14 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
 static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
-       bool hw_rfkill;
+       bool hw_rfkill, was_hw_rfkill;
+
+       was_hw_rfkill = iwl_is_rfkill_set(trans);
 
        /* tell the device to stop sending interrupts */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* device going down, Stop using ICT table */
        iwl_pcie_disable_ict(trans);
@@ -673,9 +646,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        /* Upon stop, the APM issues an interrupt if HW RF kill is set.
         * Clean again the interrupt here
         */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* stop and reset the on-board processor */
        iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
@@ -698,13 +671,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
         * all the interrupts were disabled, in this case we couldn't
         * receive the RF kill interrupt and update the state in the
         * op_mode.
+        * Don't call the op_mode if the rkfill state hasn't changed.
+        * This allows the op_mode to call stop_device from the rfkill
+        * notification without endless recursion. Under very rare
+        * circumstances, we might have a small recursion if the rfkill
+        * state changed exactly now while we were called from stop_device.
+        * This is very unlikely but can happen and is supported.
         */
        hw_rfkill = iwl_is_rfkill_set(trans);
        if (hw_rfkill)
                set_bit(STATUS_RFKILL, &trans->status);
        else
                clear_bit(STATUS_RFKILL, &trans->status);
-       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+       if (hw_rfkill != was_hw_rfkill)
+               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 }
 
 static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -799,7 +779,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
        }
 
        /* Reset the entire device */
-       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+       iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
        usleep_range(10, 15);
 
@@ -821,18 +801,17 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
        /* disable interrupts - don't enable HW RF kill interrupt */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        iwl_pcie_apm_stop(trans);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        iwl_pcie_disable_ict(trans);
 }
@@ -932,6 +911,9 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
 
        spin_lock_irqsave(&trans_pcie->reg_lock, *flags);
 
+       if (trans_pcie->cmd_in_flight)
+               goto out;
+
        /* this bit wakes up the NIC */
        __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -971,6 +953,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
                }
        }
 
+out:
        /*
         * Fool sparse by faking we release the lock - sparse will
         * track nic_access anyway.
@@ -992,6 +975,9 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
         */
        __acquire(&trans_pcie->reg_lock);
 
+       if (trans_pcie->cmd_in_flight)
+               goto out;
+
        __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        /*
@@ -1001,6 +987,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
         * scheduled on different CPUs (after we drop reg_lock).
         */
        mmiowb();
+out:
        spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags);
 }
 
@@ -1597,7 +1584,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        if (iwl_pcie_alloc_ict(trans))
                goto out_free_cmd_pool;
 
-       err = request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
+       err = request_threaded_irq(pdev->irq, iwl_pcie_isr,
                                   iwl_pcie_irq_handler,
                                   IRQF_SHARED, DRV_NAME, trans);
        if (err) {
index 8df2478..3b14fa8 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -737,10 +737,9 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ch, txq_id, ret;
-       unsigned long flags;
 
        /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
 
        iwl_pcie_txq_set_sched(trans, 0);
 
@@ -757,13 +756,19 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
                                iwl_read_direct32(trans,
                                                  FH_TSSR_TX_STATUS_REG));
        }
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
-       if (!trans_pcie->txq) {
-               IWL_WARN(trans,
-                        "Stopping tx queues that aren't allocated...\n");
+       /*
+        * This function can be called before the op_mode disabled the
+        * queues. This happens when we have an rfkill interrupt.
+        * Since we stop Tx altogether - mark the queues as stopped.
+        */
+       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+
+       /* This can happen: start_hw, stop_device */
+       if (!trans_pcie->txq)
                return 0;
-       }
 
        /* Unmap DMA from host system and free skb's */
        for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
@@ -865,7 +870,6 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
        int txq_id, slots_num;
-       unsigned long flags;
        bool alloc = false;
 
        if (!trans_pcie->txq) {
@@ -875,7 +879,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
                alloc = true;
        }
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
 
        /* Turn off all Tx DMA fifos */
        iwl_write_prph(trans, SCD_TXFACT, 0);
@@ -884,7 +888,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
        iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
                           trans_pcie->kw.dma >> 4);
 
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* Alloc and init all Tx queues, including the command queue (#4/#9) */
        for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
@@ -1003,6 +1007,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_txq *txq = &trans_pcie->txq[txq_id];
        struct iwl_queue *q = &txq->q;
+       unsigned long flags;
        int nfreed = 0;
 
        lockdep_assert_held(&txq->lock);
@@ -1025,6 +1030,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
                }
        }
 
+       if (q->read_ptr == q->write_ptr) {
+               spin_lock_irqsave(&trans_pcie->reg_lock, flags);
+               WARN_ON(!trans_pcie->cmd_in_flight);
+               trans_pcie->cmd_in_flight = false;
+               __iwl_trans_pcie_clear_bit(trans,
+                                          CSR_GP_CNTRL,
+                                          CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+               spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+       }
+
        iwl_pcie_txq_progress(trans_pcie, txq);
 }
 
@@ -1141,8 +1156,15 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
                        SCD_TX_STTS_QUEUE_OFFSET(txq_id);
        static const u32 zero_val[4] = {};
 
+       /*
+        * Upon HW Rfkill - we stop the device, and then stop the queues
+        * in the op_mode. Just for the sake of the simplicity of the op_mode,
+        * allow the op_mode to call txq_disable after it already called
+        * stop_device.
+        */
        if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
-               WARN_ONCE(1, "queue %d not used", txq_id);
+               WARN_ONCE(test_bit(STATUS_DEVICE_ENABLED, &trans->status),
+                         "queue %d not used", txq_id);
                return;
        }
 
@@ -1176,12 +1198,13 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
        struct iwl_queue *q = &txq->q;
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
+       unsigned long flags;
        void *dup_buf = NULL;
        dma_addr_t phys_addr;
        int idx;
        u16 copy_size, cmd_size, scratch_size;
        bool had_nocopy = false;
-       int i;
+       int i, ret;
        u32 cmd_pos;
        const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
        u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];
@@ -1379,10 +1402,38 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
        if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
                mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
 
+       spin_lock_irqsave(&trans_pcie->reg_lock, flags);
+
+       /*
+        * wake up the NIC to make sure that the firmware will see the host
+        * command - we will let the NIC sleep once all the host commands
+        * returned.
+        */
+       if (!trans_pcie->cmd_in_flight) {
+               trans_pcie->cmd_in_flight = true;
+               __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
+                                        CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+               ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+                                  CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+                                  (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+                                   CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
+                                  15000);
+               if (ret < 0) {
+                       __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
+                                  CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+                       trans_pcie->cmd_in_flight = false;
+                       idx = -EIO;
+                       goto out;
+               }
+       }
+
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
        iwl_pcie_txq_inc_wr_ptr(trans, txq);
 
+       spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+
  out:
        spin_unlock_bh(&txq->lock);
  free_dup_buf:
@@ -1464,7 +1515,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
 }
 
 #define HOST_COMPLETE_TIMEOUT  (2 * HZ)
-#define COMMAND_POKE_TIMEOUT   (HZ / 10)
 
 static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
                                    struct iwl_host_cmd *cmd)
@@ -1492,7 +1542,6 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int cmd_idx;
        int ret;
-       int timeout = HOST_COMPLETE_TIMEOUT;
 
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                       get_cmd_string(trans_pcie, cmd->id));
@@ -1516,29 +1565,10 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                return ret;
        }
 
-       while (timeout > 0) {
-               unsigned long flags;
-
-               timeout -= COMMAND_POKE_TIMEOUT;
-               ret = wait_event_timeout(trans_pcie->wait_command_queue,
-                                        !test_bit(STATUS_SYNC_HCMD_ACTIVE,
-                                                  &trans->status),
-                                        COMMAND_POKE_TIMEOUT);
-               if (ret)
-                       break;
-               /* poke the device - it may have lost the command */
-               if (iwl_trans_grab_nic_access(trans, true, &flags)) {
-                       iwl_trans_release_nic_access(trans, &flags);
-                       IWL_DEBUG_INFO(trans,
-                                      "Tried to wake NIC for command %s\n",
-                                      get_cmd_string(trans_pcie, cmd->id));
-               } else {
-                       IWL_ERR(trans, "Failed to poke NIC for command %s\n",
-                               get_cmd_string(trans_pcie, cmd->id));
-                       break;
-               }
-       }
-
+       ret = wait_event_timeout(trans_pcie->wait_command_queue,
+                                !test_bit(STATUS_SYNC_HCMD_ACTIVE,
+                                          &trans->status),
+                                HOST_COMPLETE_TIMEOUT);
        if (!ret) {
                struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
                struct iwl_queue *q = &txq->q;
index 9c0cc8d..fa41a77 100644 (file)
@@ -2018,7 +2018,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
           (hwsim_flags & HWSIM_TX_STAT_ACK)) {
                if (skb->len >= 16) {
                        hdr = (struct ieee80211_hdr *) skb->data;
-                       mac80211_hwsim_monitor_ack(txi->rate_driver_data[0],
+                       mac80211_hwsim_monitor_ack(data2->channel,
                                                   hdr->addr2);
                }
                txi->flags |= IEEE80211_TX_STAT_ACK;
index b994679..e7c81ab 100644 (file)
@@ -563,14 +563,7 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
                memcpy(adapter->country_code, request->alpha2,
                       sizeof(request->alpha2));
                mwifiex_send_domain_info_cmd_fw(wiphy);
-
-               if (adapter->dt_node) {
-                       char txpwr[] = {"marvell,00_txpwrlimit"};
-
-                       memcpy(&txpwr[8], adapter->country_code, 2);
-                       mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
-                                               txpwr);
-               }
+               mwifiex_dnld_txpwr_table(priv);
        }
 }
 
index 6bf58ab..4d79761 100644 (file)
@@ -747,9 +747,10 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
 }
 
 static u16
-mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb)
+mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb,
+                               void *accel_priv)
 {
-       skb->priority = cfg80211_classify8021d(skb);
+       skb->priority = cfg80211_classify8021d(skb, NULL);
        return mwifiex_1d_to_wmm_queue[skb->priority];
 }
 
index ab34164..d8ad554 100644 (file)
@@ -1155,6 +1155,7 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
 int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
 int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
                            struct device_node *node, const char *prefix);
+void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv);
 
 extern const struct ethtool_ops mwifiex_ethtool_ops;
 
index 9c2404c..9208a88 100644 (file)
@@ -1170,8 +1170,9 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
                    strncmp(prop->name, prefix, len))
                        continue;
 
-               /* property header is 6 bytes */
-               if (prop && prop->value && prop->length > 6) {
+               /* property header is 6 bytes, data must fit in cmd buffer */
+               if (prop && prop->value && prop->length > 6 &&
+                   prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) {
                        ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
                                                    HostCmd_ACT_GEN_SET, 0,
                                                    prop);
index 3edc92f..c5cb2ed 100644 (file)
@@ -184,6 +184,16 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
 }
 
+void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
+{
+       if (priv->adapter->dt_node) {
+               char txpwr[] = {"marvell,00_txpwrlimit"};
+
+               memcpy(&txpwr[8], priv->adapter->country_code, 2);
+               mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
+       }
+}
+
 static int mwifiex_process_country_ie(struct mwifiex_private *priv,
                                      struct cfg80211_bss *bss)
 {
@@ -234,12 +244,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
                return -1;
        }
 
-       if (priv->adapter->dt_node) {
-               char txpwr[] = {"marvell,00_txpwrlimit"};
-
-               memcpy(&txpwr[8], priv->adapter->country_code, 2);
-               mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
-       }
+       mwifiex_dnld_txpwr_table(priv);
 
        return 0;
 }
index b953ad6..63dbde5 100644 (file)
@@ -9,7 +9,6 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -1258,7 +1257,7 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh)
 {
        return priv->capture_beacon &&
                ieee80211_is_beacon(wh->frame_control) &&
-               ether_addr_equal(wh->addr3, priv->capture_bssid);
+               ether_addr_equal_64bits(wh->addr3, priv->capture_bssid);
 }
 
 static inline void mwl8k_save_beacon(struct ieee80211_hw *hw,
index 75c15bc..43790fb 100644 (file)
@@ -40,7 +40,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 
 #include "hermes.h"
index d21d959..c0a2737 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
index bdfe637..f9805c9 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/poll.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/spinlock.h>
index e2264bc..b60048c 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
index d43e374..0fe67d2 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/sort.h>
index b3879fb..bc065e8 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
index 3837e1e..1f6fd5f 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 
index 067e6f2..80d93cb 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
index f9a07b0..d411de4 100644 (file)
@@ -13,7 +13,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
index e328d30..6e635cf 100644 (file)
@@ -12,7 +12,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
index f95de0d..9c96831 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/export.h>
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <asm/div64.h>
@@ -308,7 +307,7 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
                return;
 
        /* only consider beacons from the associated BSSID */
-       if (!ether_addr_equal(hdr->addr3, priv->bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid))
                return;
 
        tim = p54_find_ie(skb, WLAN_EID_TIM);
index c3cdda1..5028557 100644 (file)
@@ -26,7 +26,6 @@
 // #define     VERBOSE                 // more; success messages
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
index 4ad0de9..4ccfef5 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index 4f61ffb..abc5f56 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index 1bb7693..9f16824 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index 49ff178..5c5c490 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
index 00c3fae..2bde672 100644 (file)
@@ -565,10 +565,10 @@ static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
 
 #undef TID_CHECK
 
-               if (!ether_addr_equal(ba->ra, entry->ta))
+               if (!ether_addr_equal_64bits(ba->ra, entry->ta))
                        continue;
 
-               if (!ether_addr_equal(ba->ta, entry->ra))
+               if (!ether_addr_equal_64bits(ba->ta, entry->ra))
                        continue;
 
                /* Mark BAR since we received the according BA */
index b76f604..2440298 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/crc-itu-t.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index ade88d7..a140170 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/crc-itu-t.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index a91506b..8ec17aa 100644 (file)
@@ -15,7 +15,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
index dc84569..b1bfee7 100644 (file)
@@ -19,7 +19,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index a63c443..eebf239 100644 (file)
@@ -18,7 +18,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index ee638d0..d60a5f3 100644 (file)
@@ -15,7 +15,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index 7614d9c..959b049 100644 (file)
@@ -19,7 +19,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index ec9aa5b..fd78df8 100644 (file)
@@ -20,7 +20,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index a26193a..5ecf18e 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/usb.h>
 #include <net/mac80211.h>
 
index fcf9b62..d63a12c 100644 (file)
@@ -1293,7 +1293,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        rtlpriv->link_info.bcn_rx_inperiod++;
@@ -1781,7 +1781,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        if (rtl_find_221_ie(hw, data, len))
index 0d81f76..deedae3 100644 (file)
@@ -478,7 +478,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        rtlpriv->psc.last_beacon = jiffies;
@@ -923,7 +923,7 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        /* check if this really is a beacon */
index 374268d..5a4ec56 100644 (file)
@@ -194,7 +194,7 @@ out:
        return ret;
 }
 
-int wl1251_acx_feature_cfg(struct wl1251 *wl)
+int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options)
 {
        struct acx_feature_config *feature;
        int ret;
@@ -205,8 +205,8 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl)
        if (!feature)
                return -ENOMEM;
 
-       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
-       feature->data_flow_options = 0;
+       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE can be set */
+       feature->data_flow_options = data_flow_options;
        feature->options = 0;
 
        ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
@@ -381,7 +381,8 @@ out:
        return ret;
 }
 
-int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable,
+                                void *mc_list, u32 mc_list_len)
 {
        struct acx_dot11_grp_addr_tbl *acx;
        int ret;
@@ -393,9 +394,9 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl)
                return -ENOMEM;
 
        /* MAC filtering */
-       acx->enabled = 0;
-       acx->num_groups = 0;
-       memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+       acx->enabled = enable;
+       acx->num_groups = mc_list_len;
+       memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
 
        ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
                                   acx, sizeof(*acx));
@@ -846,12 +847,18 @@ int wl1251_acx_rate_policies(struct wl1251 *wl)
                return -ENOMEM;
 
        /* configure one default (one-size-fits-all) rate class */
-       acx->rate_class_cnt = 1;
+       acx->rate_class_cnt = 2;
        acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
        acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
        acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
        acx->rate_class[0].aflags = 0;
 
+       /* no-retry rate class */
+       acx->rate_class[1].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
+       acx->rate_class[1].short_retry_limit = 0;
+       acx->rate_class[1].long_retry_limit = 0;
+       acx->rate_class[1].aflags = 0;
+
        ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
        if (ret < 0) {
                wl1251_warning("Setting of rate policies failed: %d", ret);
@@ -960,6 +967,32 @@ out:
        return ret;
 }
 
+int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address)
+{
+       struct wl1251_acx_arp_filter *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx)
+               return -ENOMEM;
+
+       acx->version = ACX_IPV4_VERSION;
+       acx->enable = enable;
+
+       if (enable)
+               memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
+
+       ret = wl1251_cmd_configure(wl, ACX_ARP_IP_FILTER,
+                                  acx, sizeof(*acx));
+       if (ret < 0)
+               wl1251_warning("failed to set arp ip filter: %d", ret);
+
+       kfree(acx);
+       return ret;
+}
+
 int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
                      u8 aifs, u16 txop)
 {
index c2ba100..2bdec38 100644 (file)
@@ -350,8 +350,8 @@ struct acx_slot {
 } __packed;
 
 
-#define ADDRESS_GROUP_MAX      (8)
-#define ADDRESS_GROUP_MAX_LEN  (ETH_ALEN * ADDRESS_GROUP_MAX)
+#define ACX_MC_ADDRESS_GROUP_MAX       (8)
+#define ACX_MC_ADDRESS_GROUP_MAX_LEN   (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX)
 
 struct acx_dot11_grp_addr_tbl {
        struct acx_header header;
@@ -359,7 +359,7 @@ struct acx_dot11_grp_addr_tbl {
        u8 enabled;
        u8 num_groups;
        u8 pad[2];
-       u8 mac_table[ADDRESS_GROUP_MAX_LEN];
+       u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN];
 } __packed;
 
 
@@ -1232,6 +1232,20 @@ struct wl1251_acx_bet_enable {
        u8 padding[2];
 } __packed;
 
+#define ACX_IPV4_VERSION 4
+#define ACX_IPV6_VERSION 6
+#define ACX_IPV4_ADDR_SIZE 4
+struct wl1251_acx_arp_filter {
+       struct acx_header header;
+       u8 version;     /* The IP version: 4 - IPv4, 6 - IPv6.*/
+       u8 enable;      /* 1 - ARP filtering is enabled, 0 - disabled */
+       u8 padding[2];
+       u8 address[16]; /* The IP address used to filter ARP packets.
+                          ARP packets that do not match this address are
+                          dropped. When the IP Version is 4, the last 12
+                          bytes of the the address are ignored. */
+} __attribute__((packed));
+
 struct wl1251_acx_ac_cfg {
        struct acx_header header;
 
@@ -1440,7 +1454,7 @@ int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
 int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
 int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
 int wl1251_acx_tx_power(struct wl1251 *wl, int power);
-int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options);
 int wl1251_acx_mem_map(struct wl1251 *wl,
                       struct acx_header *mem_map, size_t len);
 int wl1251_acx_data_path_params(struct wl1251 *wl,
@@ -1449,7 +1463,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
 int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
 int wl1251_acx_pd_threshold(struct wl1251 *wl);
 int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
-int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable,
+                                void *mc_list, u32 mc_list_len);
 int wl1251_acx_service_period_timeout(struct wl1251 *wl);
 int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
 int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter);
@@ -1473,6 +1488,7 @@ int wl1251_acx_mem_cfg(struct wl1251 *wl);
 int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
 int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode,
                          u8 max_consecutive);
+int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address);
 int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
                      u8 aifs, u16 txop);
 int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
index a2e5241..2000cd5 100644 (file)
@@ -299,7 +299,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
                ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
                ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
                REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
-               BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID;
+               BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID |
+               PS_REPORT_EVENT_ID;
 
        ret = wl1251_event_unmask(wl);
        if (ret < 0) {
index 6822b84..223649b 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/crc7.h>
+#include <linux/etherdevice.h>
 
 #include "wl1251.h"
 #include "reg.h"
@@ -203,11 +204,11 @@ out:
        return ret;
 }
 
-int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable)
 {
        struct cmd_enabledisable_path *cmd;
        int ret;
-       u16 cmd_rx, cmd_tx;
+       u16 cmd_rx;
 
        wl1251_debug(DEBUG_CMD, "cmd data path");
 
@@ -219,13 +220,10 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
 
        cmd->channel = channel;
 
-       if (enable) {
+       if (enable)
                cmd_rx = CMD_ENABLE_RX;
-               cmd_tx = CMD_ENABLE_TX;
-       } else {
+       else
                cmd_rx = CMD_DISABLE_RX;
-               cmd_tx = CMD_DISABLE_TX;
-       }
 
        ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
        if (ret < 0) {
@@ -237,17 +235,38 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
        wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
                     enable ? "start" : "stop", channel);
 
+out:
+       kfree(cmd);
+       return ret;
+}
+
+int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable)
+{
+       struct cmd_enabledisable_path *cmd;
+       int ret;
+       u16 cmd_tx;
+
+       wl1251_debug(DEBUG_CMD, "cmd data path");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->channel = channel;
+
+       if (enable)
+               cmd_tx = CMD_ENABLE_TX;
+       else
+               cmd_tx = CMD_DISABLE_TX;
+
        ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
-       if (ret < 0) {
+       if (ret < 0)
                wl1251_error("tx %s cmd for channel %d failed",
                             enable ? "start" : "stop", channel);
-               goto out;
-       }
-
-       wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
-                    enable ? "start" : "stop", channel);
+       else
+               wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+                            enable ? "start" : "stop", channel);
 
-out:
        kfree(cmd);
        return ret;
 }
@@ -410,7 +429,9 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
        struct wl1251_cmd_scan *cmd;
        int i, ret = 0;
 
-       wl1251_debug(DEBUG_CMD, "cmd scan");
+       wl1251_debug(DEBUG_CMD, "cmd scan channels %d", n_channels);
+
+       WARN_ON(n_channels > SCAN_MAX_NUM_OF_CHANNELS);
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (!cmd)
@@ -421,6 +442,13 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
                                                    CFG_RX_MGMT_EN |
                                                    CFG_RX_BCN_EN);
        cmd->params.scan_options = 0;
+       /*
+        * Use high priority scan when not associated to prevent fw issue
+        * causing never-ending scans (sometimes 20+ minutes).
+        * Note: This bug may be caused by the fw's DTIM handling.
+        */
+       if (is_zero_ether_addr(wl->bssid))
+               cmd->params.scan_options |= WL1251_SCAN_OPT_PRIORITY_HIGH;
        cmd->params.num_channels = n_channels;
        cmd->params.num_probe_requests = n_probes;
        cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
index ee4f2b3..d824ff9 100644 (file)
@@ -35,7 +35,8 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
 int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
 int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
                   void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable);
 int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
                    u16 beacon_interval, u8 dtim_interval);
 int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
@@ -167,6 +168,11 @@ struct cmd_read_write_memory {
 #define CMDMBOX_HEADER_LEN 4
 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
 
+#define WL1251_SCAN_OPT_PASSIVE                1
+#define WL1251_SCAN_OPT_5GHZ_BAND      2
+#define WL1251_SCAN_OPT_TRIGGERD_SCAN  4
+#define WL1251_SCAN_OPT_PRIORITY_HIGH  8
+
 #define WL1251_SCAN_MIN_DURATION 30000
 #define WL1251_SCAN_MAX_DURATION 60000
 
index 74ae8e1..db01053 100644 (file)
@@ -46,6 +46,43 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
        return ret;
 }
 
+#define WL1251_PSM_ENTRY_RETRIES  3
+static int wl1251_event_ps_report(struct wl1251 *wl,
+                                 struct event_mailbox *mbox)
+{
+       int ret = 0;
+
+       wl1251_debug(DEBUG_EVENT, "ps status: %x", mbox->ps_status);
+
+       switch (mbox->ps_status) {
+       case EVENT_ENTER_POWER_SAVE_FAIL:
+               wl1251_debug(DEBUG_PSM, "PSM entry failed");
+
+               if (wl->station_mode != STATION_POWER_SAVE_MODE) {
+                       /* remain in active mode */
+                       wl->psm_entry_retry = 0;
+                       break;
+               }
+
+               if (wl->psm_entry_retry < WL1251_PSM_ENTRY_RETRIES) {
+                       wl->psm_entry_retry++;
+                       ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               } else {
+                       wl1251_error("Power save entry failed, giving up");
+                       wl->psm_entry_retry = 0;
+               }
+               break;
+       case EVENT_ENTER_POWER_SAVE_SUCCESS:
+       case EVENT_EXIT_POWER_SAVE_FAIL:
+       case EVENT_EXIT_POWER_SAVE_SUCCESS:
+       default:
+               wl->psm_entry_retry = 0;
+               break;
+       }
+
+       return 0;
+}
+
 static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
 {
        wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
@@ -80,7 +117,14 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
                }
        }
 
-       if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) {
+       if (vector & PS_REPORT_EVENT_ID) {
+               wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
+               ret = wl1251_event_ps_report(wl, mbox);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (wl->vif && vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) {
                wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
 
                /* indicate to the stack, that beacons have been lost */
index 30eb5d1..88570a5 100644 (file)
@@ -112,6 +112,13 @@ struct event_mailbox {
        u8 padding[19];
 } __packed;
 
+enum {
+       EVENT_ENTER_POWER_SAVE_FAIL = 0,
+       EVENT_ENTER_POWER_SAVE_SUCCESS,
+       EVENT_EXIT_POWER_SAVE_FAIL,
+       EVENT_EXIT_POWER_SAVE_SUCCESS,
+};
+
 int wl1251_event_unmask(struct wl1251 *wl);
 void wl1251_event_mbox_config(struct wl1251 *wl);
 int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
index 89b43d3..1d799bf 100644 (file)
@@ -33,7 +33,7 @@ int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl1251_acx_feature_cfg(wl);
+       ret = wl1251_acx_feature_cfg(wl, 0);
        if (ret < 0) {
                wl1251_warning("couldn't set feature config");
                return ret;
@@ -127,7 +127,7 @@ int wl1251_hw_init_phy_config(struct wl1251 *wl)
        if (ret < 0)
                return ret;
 
-       ret = wl1251_acx_group_address_tbl(wl);
+       ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0);
        if (ret < 0)
                return ret;
 
@@ -394,8 +394,13 @@ int wl1251_hw_init(struct wl1251 *wl)
        if (ret < 0)
                goto out_free_data_path;
 
-       /* Enable data path */
-       ret = wl1251_cmd_data_path(wl, wl->channel, 1);
+       /* Enable rx data path */
+       ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
+       if (ret < 0)
+               goto out_free_data_path;
+
+       /* Enable tx data path */
+       ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1);
        if (ret < 0)
                goto out_free_data_path;
 
index b8a360b..119c148 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/netdevice.h>
 
 #include "wl1251.h"
 #include "wl12xx_80211.h"
@@ -479,10 +480,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
        wl->next_tx_complete = 0;
        wl->elp = false;
        wl->station_mode = STATION_ACTIVE_MODE;
+       wl->psm_entry_retry = 0;
        wl->tx_queue_stopped = false;
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
+       wl->joined = false;
 
        wl1251_debugfs_reset(wl);
 
@@ -542,6 +546,7 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
        mutex_lock(&wl->mutex);
        wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
        wl->vif = NULL;
+       memset(wl->bssid, 0, ETH_ALEN);
        mutex_unlock(&wl->mutex);
 }
 
@@ -566,6 +571,11 @@ static int wl1251_build_qos_null_data(struct wl1251 *wl)
                                       sizeof(template));
 }
 
+static bool wl1251_can_do_pm(struct ieee80211_conf *conf, struct wl1251 *wl)
+{
+       return (conf->flags & IEEE80211_CONF_PS) && !wl->monitor_present;
+}
+
 static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct wl1251 *wl = hw->priv;
@@ -575,8 +585,10 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
        channel = ieee80211_frequency_to_channel(
                        conf->chandef.chan->center_freq);
 
-       wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+       wl1251_debug(DEBUG_MAC80211,
+                    "mac80211 config ch %d monitor %s psm %s power %d",
                     channel,
+                    conf->flags & IEEE80211_CONF_MONITOR ? "on" : "off",
                     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
                     conf->power_level);
 
@@ -586,16 +598,44 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
        if (ret < 0)
                goto out;
 
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               u32 mode;
+
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       wl->monitor_present = true;
+                       mode = DF_SNIFF_MODE_ENABLE | DF_ENCRYPTION_DISABLE;
+               } else {
+                       wl->monitor_present = false;
+                       mode = 0;
+               }
+
+               ret = wl1251_acx_feature_cfg(wl, mode);
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
        if (channel != wl->channel) {
                wl->channel = channel;
 
-               ret = wl1251_join(wl, wl->bss_type, wl->channel,
-                                 wl->beacon_int, wl->dtim_period);
+               /*
+                * Use ENABLE_RX command for channel switching when no
+                * interface is present (monitor mode only).
+                * This leaves the tx path disabled in firmware, whereas
+                * the usual JOIN command seems to transmit some frames
+                * at firmware level.
+                */
+               if (wl->vif == NULL) {
+                       wl->joined = false;
+                       ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
+               } else {
+                       ret = wl1251_join(wl, wl->bss_type, wl->channel,
+                                         wl->beacon_int, wl->dtim_period);
+               }
                if (ret < 0)
                        goto out_sleep;
        }
 
-       if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+       if (wl1251_can_do_pm(conf, wl) && !wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm enabled");
 
                wl->psm_requested = true;
@@ -611,8 +651,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
                ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
                if (ret < 0)
                        goto out_sleep;
-       } else if (!(conf->flags & IEEE80211_CONF_PS) &&
-                  wl->psm_requested) {
+       } else if (!wl1251_can_do_pm(conf, wl) && wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm disabled");
 
                wl->psm_requested = false;
@@ -648,6 +687,16 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
                wl->power_level = conf->power_level;
        }
 
+       /*
+        * Tell stack that connection is lost because hw encryption isn't
+        * supported in monitor mode.
+        * This requires temporary enabling of the hw connection monitor flag
+        */
+       if ((changed & IEEE80211_CONF_CHANGE_MONITOR) && wl->vif) {
+               wl->hw->flags |= IEEE80211_HW_CONNECTION_MONITOR;
+               ieee80211_connection_loss(wl->vif);
+       }
+
 out_sleep:
        wl1251_ps_elp_sleep(wl);
 
@@ -657,6 +706,44 @@ out:
        return ret;
 }
 
+struct wl1251_filter_params {
+       bool enabled;
+       int mc_list_length;
+       u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
+};
+
+static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
+                                      struct netdev_hw_addr_list *mc_list)
+{
+       struct wl1251_filter_params *fp;
+       struct netdev_hw_addr *ha;
+       struct wl1251 *wl = hw->priv;
+
+       if (unlikely(wl->state == WL1251_STATE_OFF))
+               return 0;
+
+       fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
+       if (!fp) {
+               wl1251_error("Out of memory setting filters.");
+               return 0;
+       }
+
+       /* update multicast filtering parameters */
+       fp->mc_list_length = 0;
+       if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
+               fp->enabled = false;
+       } else {
+               fp->enabled = true;
+               netdev_hw_addr_list_for_each(ha, mc_list) {
+                       memcpy(fp->mc_list[fp->mc_list_length],
+                                       ha->addr, ETH_ALEN);
+                       fp->mc_list_length++;
+               }
+       }
+
+       return (u64)(unsigned long)fp;
+}
+
 #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
                                  FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
@@ -667,8 +754,9 @@ out:
 
 static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
                                       unsigned int changed,
-                                      unsigned int *total,u64 multicast)
+                                      unsigned int *total, u64 multicast)
 {
+       struct wl1251_filter_params *fp = (void *)(unsigned long)multicast;
        struct wl1251 *wl = hw->priv;
        int ret;
 
@@ -677,9 +765,11 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        *total &= WL1251_SUPPORTED_FILTERS;
        changed &= WL1251_SUPPORTED_FILTERS;
 
-       if (changed == 0)
+       if (changed == 0) {
                /* no filters which we support changed */
+               kfree(fp);
                return;
+       }
 
        mutex_lock(&wl->mutex);
 
@@ -716,6 +806,15 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
+       if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
+               ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
+       else if (fp)
+               ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
+                                                  fp->mc_list,
+                                                  fp->mc_list_length);
+       if (ret < 0)
+               goto out;
+
        /* send filters to firmware */
        wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
 
@@ -723,6 +822,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
 
 out:
        mutex_unlock(&wl->mutex);
+       kfree(fp);
 }
 
 /* HW encryption */
@@ -802,12 +902,12 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        mutex_lock(&wl->mutex);
 
-       ret = wl1251_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out_unlock;
-
        switch (cmd) {
        case SET_KEY:
+               if (wl->monitor_present) {
+                       ret = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
                wl_cmd->key_action = KEY_ADD_OR_REPLACE;
                break;
        case DISABLE_KEY:
@@ -818,6 +918,10 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                break;
        }
 
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out_unlock;
+
        ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
        if (ret < 0) {
                wl1251_error("Set KEY type failed");
@@ -930,6 +1034,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
        ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels,
                              req->n_channels, WL1251_SCAN_NUM_PROBES);
        if (ret < 0) {
+               wl1251_debug(DEBUG_SCAN, "scan failed %d", ret);
                wl->scanning = false;
                goto out_idle;
        }
@@ -977,6 +1082,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct wl1251 *wl = hw->priv;
        struct sk_buff *beacon, *skb;
+       bool enable;
        int ret;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1023,6 +1129,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_ASSOC) {
+               /* Disable temporary enabled hw connection monitor flag */
+               wl->hw->flags &= ~IEEE80211_HW_CONNECTION_MONITOR;
+
                if (bss_conf->assoc) {
                        wl->beacon_int = bss_conf->beacon_int;
 
@@ -1075,6 +1184,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if (changed & BSS_CHANGED_ARP_FILTER) {
+               __be32 addr = bss_conf->arp_addr_list[0];
+               WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+               enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
+               wl1251_acx_arp_ip_filter(wl, enable, addr);
+
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
                if (!beacon)
@@ -1245,6 +1365,7 @@ static const struct ieee80211_ops wl1251_ops = {
        .add_interface = wl1251_op_add_interface,
        .remove_interface = wl1251_op_remove_interface,
        .config = wl1251_op_config,
+       .prepare_multicast = wl1251_op_prepare_multicast,
        .configure_filter = wl1251_op_configure_filter,
        .tx = wl1251_op_tx,
        .set_key = wl1251_op_set_key,
@@ -1401,7 +1522,10 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
+       wl->joined = false;
        wl->scanning = false;
+       wl->bss_type = MAX_BSS_TYPE;
        wl->default_key = 0;
        wl->listen_int = 1;
        wl->rx_counter = 0;
@@ -1413,6 +1537,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
        wl->elp = false;
        wl->station_mode = STATION_ACTIVE_MODE;
        wl->psm_requested = false;
+       wl->psm_entry_retry = 0;
        wl->tx_queue_stopped = false;
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
@@ -1478,3 +1603,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
 MODULE_FIRMWARE(WL1251_FW_NAME);
+MODULE_FIRMWARE(WL1251_NVS_NAME);
index 23289d4..123c4bb 100644 (file)
@@ -83,7 +83,7 @@ static void wl1251_rx_status(struct wl1251 *wl,
 
        status->flag |= RX_FLAG_MACTIME_START;
 
-       if (desc->flags & RX_DESC_ENCRYPTION_MASK) {
+       if (!wl->monitor_present && (desc->flags & RX_DESC_ENCRYPTION_MASK)) {
                status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
 
                if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL)))
index 28121c5..81de83c 100644 (file)
@@ -28,6 +28,7 @@
 #include "tx.h"
 #include "ps.h"
 #include "io.h"
+#include "event.h"
 
 static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
 {
@@ -89,8 +90,12 @@ static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
        /* 802.11 packets */
        tx_hdr->control.packet_type = 0;
 
-       if (control->flags & IEEE80211_TX_CTL_NO_ACK)
+       /* Also disable retry and ACK policy for injected packets */
+       if ((control->flags & IEEE80211_TX_CTL_NO_ACK) ||
+           (control->flags & IEEE80211_TX_CTL_INJECTED)) {
+               tx_hdr->control.rate_policy = 1;
                tx_hdr->control.ack_policy = 1;
+       }
 
        tx_hdr->control.tx_complete = 1;
 
@@ -277,6 +282,26 @@ static void wl1251_tx_trigger(struct wl1251 *wl)
                TX_STATUS_DATA_OUT_COUNT_MASK;
 }
 
+static void enable_tx_for_packet_injection(struct wl1251 *wl)
+{
+       int ret;
+
+       ret = wl1251_cmd_join(wl, BSS_TYPE_STA_BSS, wl->channel,
+                             wl->beacon_int, wl->dtim_period);
+       if (ret < 0) {
+               wl1251_warning("join failed");
+               return;
+       }
+
+       ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100);
+       if (ret < 0) {
+               wl1251_warning("join timeout");
+               return;
+       }
+
+       wl->joined = true;
+}
+
 /* caller must hold wl->mutex */
 static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
 {
@@ -287,6 +312,9 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
        info = IEEE80211_SKB_CB(skb);
 
        if (info->control.hw_key) {
+               if (unlikely(wl->monitor_present))
+                       return -EINVAL;
+
                idx = info->control.hw_key->hw_key_idx;
                if (unlikely(wl->default_key != idx)) {
                        ret = wl1251_acx_default_key(wl, idx);
@@ -295,6 +323,10 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
                }
        }
 
+       /* Enable tx path in monitor mode for packet injection */
+       if ((wl->vif == NULL) && !wl->joined)
+               enable_tx_for_packet_injection(wl);
+
        ret = wl1251_tx_path_status(wl);
        if (ret < 0)
                return ret;
@@ -394,6 +426,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
        info = IEEE80211_SKB_CB(skb);
 
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
            (result->status == TX_SUCCESS))
                info->flags |= IEEE80211_TX_STAT_ACK;
 
index 2c3bd1b..235617a 100644 (file)
@@ -93,6 +93,7 @@ enum {
        } while (0)
 
 #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN |  \
+                                 CFG_MC_FILTER_EN |    \
                                  CFG_BSSID_FILTER_EN)
 
 #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN |  \
@@ -303,6 +304,8 @@ struct wl1251 {
        u8 bss_type;
        u8 listen_int;
        int channel;
+       bool monitor_present;
+       bool joined;
 
        void *target_mem_map;
        struct acx_data_path_params_resp *data_path;
@@ -368,6 +371,9 @@ struct wl1251 {
        /* PSM mode requested */
        bool psm_requested;
 
+       /* retry counter for PSM entries */
+       u8 psm_entry_retry;
+
        u16 beacon_int;
        u8 dtim_period;
 
index 1477d7f..d24d4a9 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/delay.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
index 2738563..6b62c3e 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/udp.h>
 
 #include <net/tcp.h>
-#include <net/ip6_checksum.h>
 
 #include <xen/xen.h>
 #include <xen/events.h>
@@ -1051,257 +1050,9 @@ static int xenvif_set_skb_gso(struct xenvif *vif,
        return 0;
 }
 
-static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len,
-                                 unsigned int max)
-{
-       if (skb_headlen(skb) >= len)
-               return 0;
-
-       /* If we need to pullup then pullup to the max, so we
-        * won't need to do it again.
-        */
-       if (max > skb->len)
-               max = skb->len;
-
-       if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
-               return -ENOMEM;
-
-       if (skb_headlen(skb) < len)
-               return -EPROTO;
-
-       return 0;
-}
-
-/* This value should be large enough to cover a tagged ethernet header plus
- * maximally sized IP and TCP or UDP headers.
- */
-#define MAX_IP_HDR_LEN 128
-
-static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
-                            int recalculate_partial_csum)
-{
-       unsigned int off;
-       bool fragment;
-       int err;
-
-       fragment = false;
-
-       err = maybe_pull_tail(skb,
-                             sizeof(struct iphdr),
-                             MAX_IP_HDR_LEN);
-       if (err < 0)
-               goto out;
-
-       if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF))
-               fragment = true;
-
-       off = ip_hdrlen(skb);
-
-       err = -EPROTO;
-
-       if (fragment)
-               goto out;
-
-       switch (ip_hdr(skb)->protocol) {
-       case IPPROTO_TCP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct tcphdr),
-                                     MAX_IP_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct tcphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate_partial_csum)
-                       tcp_hdr(skb)->check =
-                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                  ip_hdr(skb)->daddr,
-                                                  skb->len - off,
-                                                  IPPROTO_TCP, 0);
-               break;
-       case IPPROTO_UDP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct udphdr),
-                                     MAX_IP_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct udphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate_partial_csum)
-                       udp_hdr(skb)->check =
-                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                  ip_hdr(skb)->daddr,
-                                                  skb->len - off,
-                                                  IPPROTO_UDP, 0);
-               break;
-       default:
-               goto out;
-       }
-
-       err = 0;
-
-out:
-       return err;
-}
-
-/* This value should be large enough to cover a tagged ethernet header plus
- * an IPv6 header, all options, and a maximal TCP or UDP header.
- */
-#define MAX_IPV6_HDR_LEN 256
-
-#define OPT_HDR(type, skb, off) \
-       (type *)(skb_network_header(skb) + (off))
-
-static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
-                              int recalculate_partial_csum)
-{
-       int err;
-       u8 nexthdr;
-       unsigned int off;
-       unsigned int len;
-       bool fragment;
-       bool done;
-
-       fragment = false;
-       done = false;
-
-       off = sizeof(struct ipv6hdr);
-
-       err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN);
-       if (err < 0)
-               goto out;
-
-       nexthdr = ipv6_hdr(skb)->nexthdr;
-
-       len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
-       while (off <= len && !done) {
-               switch (nexthdr) {
-               case IPPROTO_DSTOPTS:
-               case IPPROTO_HOPOPTS:
-               case IPPROTO_ROUTING: {
-                       struct ipv6_opt_hdr *hp;
-
-                       err = maybe_pull_tail(skb,
-                                             off +
-                                             sizeof(struct ipv6_opt_hdr),
-                                             MAX_IPV6_HDR_LEN);
-                       if (err < 0)
-                               goto out;
-
-                       hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
-                       nexthdr = hp->nexthdr;
-                       off += ipv6_optlen(hp);
-                       break;
-               }
-               case IPPROTO_AH: {
-                       struct ip_auth_hdr *hp;
-
-                       err = maybe_pull_tail(skb,
-                                             off +
-                                             sizeof(struct ip_auth_hdr),
-                                             MAX_IPV6_HDR_LEN);
-                       if (err < 0)
-                               goto out;
-
-                       hp = OPT_HDR(struct ip_auth_hdr, skb, off);
-                       nexthdr = hp->nexthdr;
-                       off += ipv6_authlen(hp);
-                       break;
-               }
-               case IPPROTO_FRAGMENT: {
-                       struct frag_hdr *hp;
-
-                       err = maybe_pull_tail(skb,
-                                             off +
-                                             sizeof(struct frag_hdr),
-                                             MAX_IPV6_HDR_LEN);
-                       if (err < 0)
-                               goto out;
-
-                       hp = OPT_HDR(struct frag_hdr, skb, off);
-
-                       if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
-                               fragment = true;
-
-                       nexthdr = hp->nexthdr;
-                       off += sizeof(struct frag_hdr);
-                       break;
-               }
-               default:
-                       done = true;
-                       break;
-               }
-       }
-
-       err = -EPROTO;
-
-       if (!done || fragment)
-               goto out;
-
-       switch (nexthdr) {
-       case IPPROTO_TCP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct tcphdr),
-                                     MAX_IPV6_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct tcphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate_partial_csum)
-                       tcp_hdr(skb)->check =
-                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                &ipv6_hdr(skb)->daddr,
-                                                skb->len - off,
-                                                IPPROTO_TCP, 0);
-               break;
-       case IPPROTO_UDP:
-               err = maybe_pull_tail(skb,
-                                     off + sizeof(struct udphdr),
-                                     MAX_IPV6_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct udphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate_partial_csum)
-                       udp_hdr(skb)->check =
-                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                &ipv6_hdr(skb)->daddr,
-                                                skb->len - off,
-                                                IPPROTO_UDP, 0);
-               break;
-       default:
-               goto out;
-       }
-
-       err = 0;
-
-out:
-       return err;
-}
-
 static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
 {
-       int err = -EPROTO;
-       int recalculate_partial_csum = 0;
+       bool recalculate_partial_csum = false;
 
        /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
         * peers can fail to set NETRXF_csum_blank when sending a GSO
@@ -1311,19 +1062,14 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb)
        if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {
                vif->rx_gso_checksum_fixup++;
                skb->ip_summed = CHECKSUM_PARTIAL;
-               recalculate_partial_csum = 1;
+               recalculate_partial_csum = true;
        }
 
        /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
 
-       if (skb->protocol == htons(ETH_P_IP))
-               err = checksum_setup_ip(vif, skb, recalculate_partial_csum);
-       else if (skb->protocol == htons(ETH_P_IPV6))
-               err = checksum_setup_ipv6(vif, skb, recalculate_partial_csum);
-
-       return err;
+       return skb_checksum_setup(skb, recalculate_partial_csum);
 }
 
 static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
index e59acb1..c41537b 100644 (file)
@@ -859,9 +859,7 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
 
 static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
 {
-       struct iphdr *iph;
-       int err = -EPROTO;
-       int recalculate_partial_csum = 0;
+       bool recalculate_partial_csum = false;
 
        /*
         * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy
@@ -873,54 +871,14 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
                struct netfront_info *np = netdev_priv(dev);
                np->rx_gso_checksum_fixup++;
                skb->ip_summed = CHECKSUM_PARTIAL;
-               recalculate_partial_csum = 1;
+               recalculate_partial_csum = true;
        }
 
        /* A non-CHECKSUM_PARTIAL SKB does not require setup. */
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
 
-       if (skb->protocol != htons(ETH_P_IP))
-               goto out;
-
-       iph = (void *)skb->data;
-
-       switch (iph->protocol) {
-       case IPPROTO_TCP:
-               if (!skb_partial_csum_set(skb, 4 * iph->ihl,
-                                         offsetof(struct tcphdr, check)))
-                       goto out;
-
-               if (recalculate_partial_csum) {
-                       struct tcphdr *tcph = tcp_hdr(skb);
-                       tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                        skb->len - iph->ihl*4,
-                                                        IPPROTO_TCP, 0);
-               }
-               break;
-       case IPPROTO_UDP:
-               if (!skb_partial_csum_set(skb, 4 * iph->ihl,
-                                         offsetof(struct udphdr, check)))
-                       goto out;
-
-               if (recalculate_partial_csum) {
-                       struct udphdr *udph = udp_hdr(skb);
-                       udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
-                                                        skb->len - iph->ihl*4,
-                                                        IPPROTO_UDP, 0);
-               }
-               break;
-       default:
-               if (net_ratelimit())
-                       pr_err("Attempting to checksum a non-TCP/UDP packet, dropping a protocol %d packet\n",
-                              iph->protocol);
-               goto out;
-       }
-
-       err = 0;
-
-out:
-       return err;
+       return skb_checksum_setup(skb, recalculate_partial_csum);
 }
 
 static int handle_incoming_queue(struct net_device *dev,
index a43b852..875b7b6 100644 (file)
@@ -254,3 +254,23 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
        return IS_ERR(phy) ? NULL : phy;
 }
 EXPORT_SYMBOL(of_phy_connect_fixed_link);
+
+/**
+ * of_phy_attach - Attach to a PHY without starting the state machine
+ * @dev: pointer to net_device claiming the phy
+ * @phy_np: Node pointer for the PHY
+ * @flags: flags to pass to the PHY
+ * @iface: PHY data interface type
+ */
+struct phy_device *of_phy_attach(struct net_device *dev,
+                                struct device_node *phy_np, u32 flags,
+                                phy_interface_t iface)
+{
+       struct phy_device *phy = of_phy_find_device(phy_np);
+
+       if (!phy)
+               return NULL;
+
+       return phy_attach_direct(dev, phy, flags, iface) ? NULL : phy;
+}
+EXPORT_SYMBOL(of_phy_attach);
index 8f9be2e..a208a45 100644 (file)
@@ -30,6 +30,7 @@ static const char *phy_modes[] = {
        [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
        [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
        [PHY_INTERFACE_MODE_SMII]       = "smii",
+       [PHY_INTERFACE_MODE_XGMII]      = "xgmii",
 };
 
 /**
index 1cf605f..e864392 100644 (file)
@@ -279,7 +279,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
 
        status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
        if (ACPI_FAILURE(status)) {
-               acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status);
+               if (status != AE_NOT_FOUND)
+                       acpi_handle_warn(handle,
+                               "can't evaluate _ADR (%#x)\n", status);
                return AE_OK;
        }
 
@@ -643,6 +645,24 @@ static void disable_slot(struct acpiphp_slot *slot)
        slot->flags &= (~SLOT_ENABLED);
 }
 
+static bool acpiphp_no_hotplug(acpi_handle handle)
+{
+       struct acpi_device *adev = NULL;
+
+       acpi_bus_get_device(handle, &adev);
+       return adev && adev->flags.no_hotplug;
+}
+
+static bool slot_no_hotplug(struct acpiphp_slot *slot)
+{
+       struct acpiphp_func *func;
+
+       list_for_each_entry(func, &slot->funcs, sibling)
+               if (acpiphp_no_hotplug(func_to_handle(func)))
+                       return true;
+
+       return false;
+}
 
 /**
  * get_slot_status - get ACPI slot status
@@ -701,7 +721,8 @@ static void trim_stale_devices(struct pci_dev *dev)
                unsigned long long sta;
 
                status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-               alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL;
+               alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL)
+                       || acpiphp_no_hotplug(handle);
        }
        if (!alive) {
                u32 v;
@@ -741,8 +762,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                struct pci_dev *dev, *tmp;
 
                mutex_lock(&slot->crit_sect);
-               /* wake up all functions */
-               if (get_slot_status(slot) == ACPI_STA_ALL) {
+               if (slot_no_hotplug(slot)) {
+                       ; /* do nothing */
+               } else if (get_slot_status(slot) == ACPI_STA_ALL) {
                        /* remove stale devices if any */
                        list_for_each_entry_safe(dev, tmp, &bus->devices,
                                                 bus_list)
index 577074e..f7ebdba 100644 (file)
@@ -330,29 +330,32 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
 static void pci_acpi_setup(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
-       acpi_handle handle = ACPI_HANDLE(dev);
-       struct acpi_device *adev;
+       struct acpi_device *adev = ACPI_COMPANION(dev);
 
-       if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid)
+       if (!adev)
+               return;
+
+       pci_acpi_add_pm_notifier(adev, pci_dev);
+       if (!adev->wakeup.flags.valid)
                return;
 
        device_set_wakeup_capable(dev, true);
        acpi_pci_sleep_wake(pci_dev, false);
-
-       pci_acpi_add_pm_notifier(adev, pci_dev);
        if (adev->wakeup.flags.run_wake)
                device_set_run_wake(dev, true);
 }
 
 static void pci_acpi_cleanup(struct device *dev)
 {
-       acpi_handle handle = ACPI_HANDLE(dev);
-       struct acpi_device *adev;
+       struct acpi_device *adev = ACPI_COMPANION(dev);
+
+       if (!adev)
+               return;
 
-       if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) {
+       pci_acpi_remove_pm_notifier(adev);
+       if (adev->wakeup.flags.valid) {
                device_set_wakeup_capable(dev, false);
                device_set_run_wake(dev, false);
-               pci_acpi_remove_pm_notifier(adev);
        }
 }
 
index 330ef2d..a8b17ce 100644 (file)
@@ -16,6 +16,7 @@ config GENERIC_PHY
          framework should select this config.
 
 config PHY_EXYNOS_MIPI_VIDEO
+       depends on HAS_IOMEM
        tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
        help
          Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
index 5e2054a..32c6294 100644 (file)
@@ -196,6 +196,7 @@ config BATTERY_MAX17040
 config BATTERY_MAX17042
        tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge"
        depends on I2C
+       select REGMAP_I2C
        help
          MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries
          in handheld and portable equipment. The MAX17042 is configured
@@ -376,6 +377,7 @@ config AB8500_BM
 config BATTERY_GOLDFISH
        tristate "Goldfish battery driver"
        depends on GOLDFISH || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Say Y to enable support for the battery and AC power in the
          Goldfish emulator.
index 00e6672..557af94 100644 (file)
@@ -511,6 +511,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        dev_set_drvdata(dev, psy);
        psy->dev = dev;
 
+       rc = dev_set_name(dev, "%s", psy->name);
+       if (rc)
+               goto dev_set_name_failed;
+
        INIT_WORK(&psy->changed_work, power_supply_changed_work);
 
        rc = power_supply_check_supplies(psy);
@@ -524,10 +528,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        if (rc)
                goto wakeup_init_failed;
 
-       rc = kobject_set_name(&dev->kobj, "%s", psy->name);
-       if (rc)
-               goto kobject_set_name_failed;
-
        rc = device_add(dev);
        if (rc)
                goto device_add_failed;
@@ -553,11 +553,11 @@ create_triggers_failed:
 register_cooler_failed:
        psy_unregister_thermal(psy);
 register_thermal_failed:
-wakeup_init_failed:
        device_del(dev);
-kobject_set_name_failed:
 device_add_failed:
+wakeup_init_failed:
 check_supplies_failed:
+dev_set_name_failed:
        put_device(dev);
 success:
        return rc;
index 5be73ba..5a7910e 100644 (file)
@@ -73,6 +73,7 @@ config DP83640_PHY
 config PTP_1588_CLOCK_PCH
        tristate "Intel PCH EG20T as PTP clock"
        depends on X86 || COMPILE_TEST
+       depends on HAS_IOMEM
        select PTP_1588_CLOCK
        help
          This driver adds support for using the PCH EG20T as a PTP
index 3f4ca4e..34629ea 100644 (file)
@@ -942,7 +942,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
                return rc;
        }
 
-       tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows);
+       tp->screen = tty3270_alloc_screen(tp->view.rows, tp->view.cols);
        if (IS_ERR(tp->screen)) {
                rc = PTR_ERR(tp->screen);
                raw3270_put_view(&tp->view);
index 13299f9..d24b367 100644 (file)
@@ -55,6 +55,7 @@ int chsc_error_from_response(int response)
        case 0x0004:
                return -EOPNOTSUPP;
        case 0x000b:
+       case 0x0107:            /* "Channel busy" for the op 0x003d */
                return -EBUSY;
        case 0x0100:
        case 0x0102:
@@ -1234,3 +1235,35 @@ out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(chsc_scm_info);
+
+/**
+ * chsc_pnso_brinfo() - Perform Network-Subchannel Operation, Bridge Info.
+ * @schid:             id of the subchannel on which PNSO is performed
+ * @brinfo_area:       request and response block for the operation
+ * @resume_token:      resume token for multiblock response
+ * @cnc:               Boolean change-notification control
+ *
+ * brinfo_area must be allocated by the caller with get_zeroed_page(GFP_KERNEL)
+ *
+ * Returns 0 on success.
+ */
+int chsc_pnso_brinfo(struct subchannel_id schid,
+               struct chsc_pnso_area *brinfo_area,
+               struct chsc_brinfo_resume_token resume_token,
+               int cnc)
+{
+       memset(brinfo_area, 0, sizeof(*brinfo_area));
+       brinfo_area->request.length = 0x0030;
+       brinfo_area->request.code = 0x003d; /* network-subchannel operation */
+       brinfo_area->m     = schid.m;
+       brinfo_area->ssid  = schid.ssid;
+       brinfo_area->sch   = schid.sch_no;
+       brinfo_area->cssid = schid.cssid;
+       brinfo_area->oc    = 0; /* Store-network-bridging-information list */
+       brinfo_area->resume_token = resume_token;
+       brinfo_area->n     = (cnc != 0);
+       if (chsc(brinfo_area))
+               return -EIO;
+       return chsc_error_from_response(brinfo_area->response.code);
+}
+EXPORT_SYMBOL_GPL(chsc_pnso_brinfo);
index 23d072e..7e53a9c 100644 (file)
@@ -61,7 +61,9 @@ struct css_chsc_char {
        u32 : 20;
        u32 scssc : 1;  /* bit 107 */
        u32 scsscf : 1; /* bit 108 */
-       u32 : 19;
+       u32:7;
+       u32 pnso:1; /* bit 116 */
+       u32:11;
 }__attribute__((packed));
 
 extern struct css_chsc_char css_chsc_characteristics;
@@ -188,6 +190,53 @@ struct chsc_scm_info {
 
 int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token);
 
+struct chsc_brinfo_resume_token {
+       u64 t1;
+       u64 t2;
+} __packed;
+
+struct chsc_brinfo_naihdr {
+       struct chsc_brinfo_resume_token resume_token;
+       u32:32;
+       u32 instance;
+       u32:24;
+       u8 naids;
+       u32 reserved[3];
+} __packed;
+
+struct chsc_pnso_area {
+       struct chsc_header request;
+       u8:2;
+       u8 m:1;
+       u8:5;
+       u8:2;
+       u8 ssid:2;
+       u8 fmt:4;
+       u16 sch;
+       u8:8;
+       u8 cssid;
+       u16:16;
+       u8 oc;
+       u32:24;
+       struct chsc_brinfo_resume_token resume_token;
+       u32 n:1;
+       u32:31;
+       u32 reserved[3];
+       struct chsc_header response;
+       u32:32;
+       struct chsc_brinfo_naihdr naihdr;
+       union {
+               struct qdio_brinfo_entry_l3_ipv6 l3_ipv6[0];
+               struct qdio_brinfo_entry_l3_ipv4 l3_ipv4[0];
+               struct qdio_brinfo_entry_l2      l2[0];
+       } entries;
+} __packed;
+
+int chsc_pnso_brinfo(struct subchannel_id schid,
+               struct chsc_pnso_area *brinfo_area,
+               struct chsc_brinfo_resume_token resume_token,
+               int cnc);
+
 #ifdef CONFIG_SCM_BUS
 int scm_update_information(void);
 int scm_process_availability_information(void);
index 3e602e8..5f99af4 100644 (file)
@@ -1752,6 +1752,97 @@ int qdio_stop_irq(struct ccw_device *cdev, int nr)
 }
 EXPORT_SYMBOL(qdio_stop_irq);
 
+/**
+ * qdio_pnso_brinfo() - perform network subchannel op #0 - bridge info.
+ * @schid:             Subchannel ID.
+ * @cnc:               Boolean Change-Notification Control
+ * @response:          Response code will be stored at this address
+ * @cb:                        Callback function will be executed for each element
+ *                     of the address list
+ * @priv:              Pointer passed from the caller to qdio_pnso_brinfo()
+ * @type:              Type of the address entry passed to the callback
+ * @entry:             Entry containg the address of the specified type
+ * @priv:              Pointer to pass to the callback function.
+ *
+ * Performs "Store-network-bridging-information list" operation and calls
+ * the callback function for every entry in the list. If "change-
+ * notification-control" is set, further changes in the address list
+ * will be reported via the IPA command.
+ */
+int qdio_pnso_brinfo(struct subchannel_id schid,
+               int cnc, u16 *response,
+               void (*cb)(void *priv, enum qdio_brinfo_entry_type type,
+                               void *entry),
+               void *priv)
+{
+       struct chsc_pnso_area *rr;
+       int rc;
+       u32 prev_instance = 0;
+       int isfirstblock = 1;
+       int i, size, elems;
+
+       rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL);
+       if (rr == NULL)
+               return -ENOMEM;
+       do {
+               /* on the first iteration, naihdr.resume_token will be zero */
+               rc = chsc_pnso_brinfo(schid, rr, rr->naihdr.resume_token, cnc);
+               if (rc != 0 && rc != -EBUSY)
+                       goto out;
+               if (rr->response.code != 1) {
+                       rc = -EIO;
+                       continue;
+               } else
+                       rc = 0;
+
+               if (cb == NULL)
+                       continue;
+
+               size = rr->naihdr.naids;
+               elems = (rr->response.length -
+                               sizeof(struct chsc_header) -
+                               sizeof(struct chsc_brinfo_naihdr)) /
+                               size;
+
+               if (!isfirstblock && (rr->naihdr.instance != prev_instance)) {
+                       /* Inform the caller that they need to scrap */
+                       /* the data that was already reported via cb */
+                               rc = -EAGAIN;
+                               break;
+               }
+               isfirstblock = 0;
+               prev_instance = rr->naihdr.instance;
+               for (i = 0; i < elems; i++)
+                       switch (size) {
+                       case sizeof(struct qdio_brinfo_entry_l3_ipv6):
+                               (*cb)(priv, l3_ipv6_addr,
+                                               &rr->entries.l3_ipv6[i]);
+                               break;
+                       case sizeof(struct qdio_brinfo_entry_l3_ipv4):
+                               (*cb)(priv, l3_ipv4_addr,
+                                               &rr->entries.l3_ipv4[i]);
+                               break;
+                       case sizeof(struct qdio_brinfo_entry_l2):
+                               (*cb)(priv, l2_addr_lnid,
+                                               &rr->entries.l2[i]);
+                               break;
+                       default:
+                               WARN_ON_ONCE(1);
+                               rc = -EIO;
+                               goto out;
+                       }
+       } while (rr->response.code == 0x0107 ||  /* channel busy */
+                 (rr->response.code == 1 && /* list stored */
+                  /* resume token is non-zero => list incomplete */
+                  (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2)));
+       (*response) = rr->response.code;
+
+out:
+       free_page((unsigned long)rr);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(qdio_pnso_brinfo);
+
 static int __init init_QDIO(void)
 {
        int rc;
index 4dfe8c1..d28f05d 100644 (file)
@@ -11,7 +11,7 @@ obj-$(CONFIG_LCS) += lcs.o
 obj-$(CONFIG_CLAW) += claw.o
 qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o
 obj-$(CONFIG_QETH) += qeth.o
-qeth_l2-y += qeth_l2_main.o
+qeth_l2-y += qeth_l2_main.o qeth_l2_sys.o
 obj-$(CONFIG_QETH_L2) += qeth_l2.o
 qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o
 obj-$(CONFIG_QETH_L3) += qeth_l3.o
index d45427c..ac0bdde 100644 (file)
@@ -156,6 +156,27 @@ struct qeth_ipa_info {
        __u32 enabled_funcs;
 };
 
+/* SETBRIDGEPORT stuff */
+enum qeth_sbp_roles {
+       QETH_SBP_ROLE_NONE      = 0,
+       QETH_SBP_ROLE_PRIMARY   = 1,
+       QETH_SBP_ROLE_SECONDARY = 2,
+};
+
+enum qeth_sbp_states {
+       QETH_SBP_STATE_INACTIVE = 0,
+       QETH_SBP_STATE_STANDBY  = 1,
+       QETH_SBP_STATE_ACTIVE   = 2,
+};
+
+#define QETH_SBP_HOST_NOTIFICATION 1
+
+struct qeth_sbp_info {
+       __u32 supported_funcs;
+       enum qeth_sbp_roles role;
+       __u32 hostnotification:1;
+};
+
 static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa,
                enum qeth_ipa_funcs func)
 {
@@ -672,6 +693,7 @@ struct qeth_card_options {
        struct qeth_ipa_info adp; /*Adapter parameters*/
        struct qeth_routing_info route6;
        struct qeth_ipa_info ipa6;
+       struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */
        int fake_broadcast;
        int add_hhlen;
        int layer2;
@@ -857,6 +879,7 @@ extern struct qeth_discipline qeth_l2_discipline;
 extern struct qeth_discipline qeth_l3_discipline;
 extern const struct attribute_group *qeth_generic_attr_groups[];
 extern const struct attribute_group *qeth_osn_attr_groups[];
+extern struct workqueue_struct *qeth_wq;
 
 const char *qeth_get_cardname_short(struct qeth_card *);
 int qeth_realloc_buffer_pool(struct qeth_card *, int);
@@ -925,6 +948,13 @@ int qeth_query_card_info(struct qeth_card *card,
 int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
        int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
        void *reply_param);
+void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd);
+void qeth_bridgeport_query_support(struct qeth_card *card);
+int qeth_bridgeport_query_ports(struct qeth_card *card,
+       enum qeth_sbp_roles *role, enum qeth_sbp_states *state);
+int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
+int qeth_bridgeport_an_set(struct qeth_card *card, int enable);
+void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd);
 int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
 int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int);
 int qeth_get_elements_for_frags(struct sk_buff *);
index f9a85b4..c05dacb 100644 (file)
@@ -68,7 +68,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
                enum qeth_qdio_buffer_states newbufstate);
 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 
-static struct workqueue_struct *qeth_wq;
+struct workqueue_struct *qeth_wq;
 
 static void qeth_close_dev_handler(struct work_struct *work)
 {
@@ -615,6 +615,16 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
                                        card->info.hwtrap = 2;
                                qeth_schedule_recovery(card);
                                return NULL;
+                       case IPA_CMD_SETBRIDGEPORT:
+                               if (cmd->data.sbp.hdr.command_code ==
+                                       IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
+                                       qeth_bridge_state_change(card, cmd);
+                                       return NULL;
+                               } else
+                                       return cmd;
+                       case IPA_CMD_ADDRESS_CHANGE_NOTIF:
+                               qeth_bridge_host_event(card, cmd);
+                               return NULL;
                        case IPA_CMD_MODCCID:
                                return cmd;
                        case IPA_CMD_REGISTER_LOCAL_ADDR:
@@ -4956,12 +4966,17 @@ retriable:
 
        card->options.ipa4.supported_funcs = 0;
        card->options.adp.supported_funcs = 0;
+       card->options.sbp.supported_funcs = 0;
        card->info.diagass_support = 0;
        qeth_query_ipassists(card, QETH_PROT_IPV4);
        if (qeth_is_supported(card, IPA_SETADAPTERPARMS))
                qeth_query_setadapterparms(card);
        if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
                qeth_query_setdiagass(card);
+       qeth_bridgeport_query_support(card);
+       if (card->options.sbp.supported_funcs)
+               dev_info(&card->gdev->dev,
+               "The device represents a HiperSockets Bridge Capable Port\n");
        return 0;
 out:
        dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
index 06c5578..7b55768 100644 (file)
@@ -249,10 +249,12 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
        {IPA_CMD_DELIP,         "delip"},
        {IPA_CMD_SETADAPTERPARMS, "setadapterparms"},
        {IPA_CMD_SET_DIAG_ASS,  "set_diag_ass"},
+       {IPA_CMD_SETBRIDGEPORT, "set_bridge_port"},
        {IPA_CMD_CREATE_ADDR,   "create_addr"},
        {IPA_CMD_DESTROY_ADDR,  "destroy_addr"},
        {IPA_CMD_REGISTER_LOCAL_ADDR,   "register_local_addr"},
        {IPA_CMD_UNREGISTER_LOCAL_ADDR, "unregister_local_addr"},
+       {IPA_CMD_ADDRESS_CHANGE_NOTIF, "address_change_notification"},
        {IPA_CMD_UNKNOWN,       "unknown"},
 };
 
index 0a6e695..cf6a90e 100644 (file)
@@ -104,10 +104,12 @@ enum qeth_ipa_cmds {
        IPA_CMD_DELIP                   = 0xb7,
        IPA_CMD_SETADAPTERPARMS         = 0xb8,
        IPA_CMD_SET_DIAG_ASS            = 0xb9,
+       IPA_CMD_SETBRIDGEPORT           = 0xbe,
        IPA_CMD_CREATE_ADDR             = 0xc3,
        IPA_CMD_DESTROY_ADDR            = 0xc4,
        IPA_CMD_REGISTER_LOCAL_ADDR     = 0xd1,
        IPA_CMD_UNREGISTER_LOCAL_ADDR   = 0xd2,
+       IPA_CMD_ADDRESS_CHANGE_NOTIF    = 0xd3,
        IPA_CMD_UNKNOWN                 = 0x00
 };
 
@@ -500,6 +502,124 @@ struct qeth_ipacmd_diagass {
        __u8   cdata[64];
 } __attribute__ ((packed));
 
+/* SETBRIDGEPORT IPA Command:   *********************************************/
+enum qeth_ipa_sbp_cmd {
+       IPA_SBP_QUERY_COMMANDS_SUPPORTED        = 0x00000000L,
+       IPA_SBP_RESET_BRIDGE_PORT_ROLE          = 0x00000001L,
+       IPA_SBP_SET_PRIMARY_BRIDGE_PORT         = 0x00000002L,
+       IPA_SBP_SET_SECONDARY_BRIDGE_PORT       = 0x00000004L,
+       IPA_SBP_QUERY_BRIDGE_PORTS              = 0x00000008L,
+       IPA_SBP_BRIDGE_PORT_STATE_CHANGE        = 0x00000010L,
+};
+
+struct net_if_token {
+       __u16 devnum;
+       __u8 cssid;
+       __u8 iid;
+       __u8 ssid;
+       __u8 chpid;
+       __u16 chid;
+} __packed;
+
+struct mac_addr_lnid {
+       __u8 mac[6];
+       __u16 lnid;
+} __packed;
+
+struct qeth_ipacmd_sbp_hdr {
+       __u32 supported_sbp_cmds;
+       __u32 enabled_sbp_cmds;
+       __u16 cmdlength;
+       __u16 reserved1;
+       __u32 command_code;
+       __u16 return_code;
+       __u8  used_total;
+       __u8  seq_no;
+       __u32 reserved2;
+} __packed;
+
+struct qeth_sbp_query_cmds_supp {
+       __u32 supported_cmds;
+       __u32 reserved;
+} __packed;
+
+struct qeth_sbp_reset_role {
+} __packed;
+
+struct qeth_sbp_set_primary {
+       struct net_if_token token;
+} __packed;
+
+struct qeth_sbp_set_secondary {
+} __packed;
+
+struct qeth_sbp_port_entry {
+               __u8 role;
+               __u8 state;
+               __u8 reserved1;
+               __u8 reserved2;
+               struct net_if_token token;
+} __packed;
+
+struct qeth_sbp_query_ports {
+       __u8 primary_bp_supported;
+       __u8 secondary_bp_supported;
+       __u8 num_entries;
+       __u8 entry_length;
+       struct qeth_sbp_port_entry entry[];
+} __packed;
+
+struct qeth_sbp_state_change {
+       __u8 primary_bp_supported;
+       __u8 secondary_bp_supported;
+       __u8 num_entries;
+       __u8 entry_length;
+       struct qeth_sbp_port_entry entry[];
+} __packed;
+
+struct qeth_ipacmd_setbridgeport {
+       struct qeth_ipacmd_sbp_hdr hdr;
+       union {
+               struct qeth_sbp_query_cmds_supp query_cmds_supp;
+               struct qeth_sbp_reset_role reset_role;
+               struct qeth_sbp_set_primary set_primary;
+               struct qeth_sbp_set_secondary set_secondary;
+               struct qeth_sbp_query_ports query_ports;
+               struct qeth_sbp_state_change state_change;
+       } data;
+} __packed;
+
+/* ADDRESS_CHANGE_NOTIFICATION adapter-initiated "command" *******************/
+/* Bitmask for entry->change_code. Both bits may be raised.                 */
+enum qeth_ipa_addr_change_code {
+       IPA_ADDR_CHANGE_CODE_VLANID             = 0x01,
+       IPA_ADDR_CHANGE_CODE_MACADDR            = 0x02,
+       IPA_ADDR_CHANGE_CODE_REMOVAL            = 0x80, /* else addition */
+};
+enum qeth_ipa_addr_change_retcode {
+       IPA_ADDR_CHANGE_RETCODE_OK              = 0x0000,
+       IPA_ADDR_CHANGE_RETCODE_LOSTEVENTS      = 0x0010,
+};
+enum qeth_ipa_addr_change_lostmask {
+       IPA_ADDR_CHANGE_MASK_OVERFLOW           = 0x01,
+       IPA_ADDR_CHANGE_MASK_STATECHANGE        = 0x02,
+};
+
+struct qeth_ipacmd_addr_change_entry {
+       struct net_if_token token;
+       struct mac_addr_lnid addr_lnid;
+       __u8 change_code;
+       __u8 reserved1;
+       __u16 reserved2;
+} __packed;
+
+struct qeth_ipacmd_addr_change {
+       __u8 lost_event_mask;
+       __u8 reserved;
+       __u16 num_entries;
+       struct qeth_ipacmd_addr_change_entry entry[];
+} __packed;
+
 /* Header for each IPA command */
 struct qeth_ipacmd_hdr {
        __u8   command;
@@ -529,6 +649,8 @@ struct qeth_ipa_cmd {
                struct qeth_ipacmd_setadpparms          setadapterparms;
                struct qeth_set_routing                 setrtg;
                struct qeth_ipacmd_diagass              diagass;
+               struct qeth_ipacmd_setbridgeport        sbp;
+               struct qeth_ipacmd_addr_change          addrchange;
        } data;
 } __attribute__ ((packed));
 
diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h
new file mode 100644 (file)
index 0000000..0767556
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com>
+ */
+
+#ifndef __QETH_L2_H__
+#define __QETH_L2_H__
+
+#include "qeth_core.h"
+
+int qeth_l2_create_device_attributes(struct device *);
+void qeth_l2_remove_device_attributes(struct device *);
+void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
+
+#endif /* __QETH_L2_H__ */
index ec8ccda..914d2c1 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/list.h>
 
 #include "qeth_core.h"
+#include "qeth_l2.h"
 
 static int qeth_l2_set_offline(struct ccwgroup_device *);
 static int qeth_l2_stop(struct net_device *);
@@ -880,6 +881,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
 {
        struct qeth_card *card = dev_get_drvdata(&gdev->dev);
 
+       qeth_l2_create_device_attributes(&gdev->dev);
        INIT_LIST_HEAD(&card->vid_list);
        INIT_LIST_HEAD(&card->mc_list);
        card->options.layer2 = 1;
@@ -891,6 +893,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
 {
        struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
 
+       qeth_l2_remove_device_attributes(&cgdev->dev);
        qeth_set_allowed_threads(card, 0, 1);
        wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
 
@@ -1003,6 +1006,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        } else
                card->info.hwtrap = 0;
 
+       qeth_l2_setup_bridgeport_attrs(card);
+
        card->state = CARD_STATE_HARDSETUP;
        memset(&card->rx, 0, sizeof(struct qeth_rx));
        qeth_print_status_message(card);
@@ -1347,6 +1352,595 @@ void qeth_osn_deregister(struct net_device *dev)
 }
 EXPORT_SYMBOL(qeth_osn_deregister);
 
+/* SETBRIDGEPORT support, async notifications */
+
+enum qeth_an_event_type {anev_reg_unreg, anev_abort, anev_reset};
+
+/**
+ * qeth_bridge_emit_host_event() - bridgeport address change notification
+ * @card:  qeth_card structure pointer, for udev events.
+ * @evtype:  "normal" register/unregister, or abort, or reset. For abort
+ *           and reset token and addr_lnid are unused and may be NULL.
+ * @code:  event bitmask: high order bit 0x80 value 1 means removal of an
+ *                       object, 0 - addition of an object.
+ *                       0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC.
+ * @token: "network token" structure identifying physical address of the port.
+ * @addr_lnid: pointer to structure with MAC address and VLAN ID.
+ *
+ * This function is called when registrations and deregistrations are
+ * reported by the hardware, and also when notifications are enabled -
+ * for all currently registered addresses.
+ */
+static void qeth_bridge_emit_host_event(struct qeth_card *card,
+       enum qeth_an_event_type evtype,
+       u8 code, struct net_if_token *token, struct mac_addr_lnid *addr_lnid)
+{
+       char str[7][32];
+       char *env[8];
+       int i = 0;
+
+       switch (evtype) {
+       case anev_reg_unreg:
+               snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s",
+                               (code & IPA_ADDR_CHANGE_CODE_REMOVAL)
+                               ? "deregister" : "register");
+               env[i] = str[i]; i++;
+               if (code & IPA_ADDR_CHANGE_CODE_VLANID) {
+                       snprintf(str[i], sizeof(str[i]), "VLAN=%d",
+                               addr_lnid->lnid);
+                       env[i] = str[i]; i++;
+               }
+               if (code & IPA_ADDR_CHANGE_CODE_MACADDR) {
+                       snprintf(str[i], sizeof(str[i]), "MAC=%pM6",
+                               &addr_lnid->mac);
+                       env[i] = str[i]; i++;
+               }
+               snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x",
+                       token->cssid, token->ssid, token->devnum);
+               env[i] = str[i]; i++;
+               snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid);
+               env[i] = str[i]; i++;
+               snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x",
+                               token->chpid);
+               env[i] = str[i]; i++;
+               snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid);
+               env[i] = str[i]; i++;
+               break;
+       case anev_abort:
+               snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort");
+               env[i] = str[i]; i++;
+               break;
+       case anev_reset:
+               snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset");
+               env[i] = str[i]; i++;
+               break;
+       }
+       env[i] = NULL;
+       kobject_uevent_env(&card->gdev->dev.kobj, KOBJ_CHANGE, env);
+}
+
+struct qeth_bridge_state_data {
+       struct work_struct worker;
+       struct qeth_card *card;
+       struct qeth_sbp_state_change qports;
+};
+
+static void qeth_bridge_state_change_worker(struct work_struct *work)
+{
+       struct qeth_bridge_state_data *data =
+               container_of(work, struct qeth_bridge_state_data, worker);
+       /* We are only interested in the first entry - local port */
+       struct qeth_sbp_port_entry *entry = &data->qports.entry[0];
+       char env_locrem[32];
+       char env_role[32];
+       char env_state[32];
+       char *env[] = {
+               env_locrem,
+               env_role,
+               env_state,
+               NULL
+       };
+
+       /* Role should not change by itself, but if it did, */
+       /* information from the hardware is authoritative.  */
+       mutex_lock(&data->card->conf_mutex);
+       data->card->options.sbp.role = entry->role;
+       mutex_unlock(&data->card->conf_mutex);
+
+       snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange");
+       snprintf(env_role, sizeof(env_role), "ROLE=%s",
+               (entry->role == QETH_SBP_ROLE_NONE) ? "none" :
+               (entry->role == QETH_SBP_ROLE_PRIMARY) ? "primary" :
+               (entry->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" :
+               "<INVALID>");
+       snprintf(env_state, sizeof(env_state), "STATE=%s",
+               (entry->state == QETH_SBP_STATE_INACTIVE) ? "inactive" :
+               (entry->state == QETH_SBP_STATE_STANDBY) ? "standby" :
+               (entry->state == QETH_SBP_STATE_ACTIVE) ? "active" :
+               "<INVALID>");
+       kobject_uevent_env(&data->card->gdev->dev.kobj,
+                               KOBJ_CHANGE, env);
+       kfree(data);
+}
+
+void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
+{
+       struct qeth_sbp_state_change *qports =
+                &cmd->data.sbp.data.state_change;
+       struct qeth_bridge_state_data *data;
+       int extrasize;
+
+       QETH_CARD_TEXT(card, 2, "brstchng");
+       if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
+               QETH_CARD_TEXT_(card, 2, "BPsz%.8d", qports->entry_length);
+               return;
+       }
+       extrasize = sizeof(struct qeth_sbp_port_entry) * qports->num_entries;
+       data = kzalloc(sizeof(struct qeth_bridge_state_data) + extrasize,
+               GFP_ATOMIC);
+       if (!data) {
+               QETH_CARD_TEXT(card, 2, "BPSalloc");
+               return;
+       }
+       INIT_WORK(&data->worker, qeth_bridge_state_change_worker);
+       data->card = card;
+       memcpy(&data->qports, qports,
+                       sizeof(struct qeth_sbp_state_change) + extrasize);
+       queue_work(qeth_wq, &data->worker);
+}
+EXPORT_SYMBOL(qeth_bridge_state_change);
+
+struct qeth_bridge_host_data {
+       struct work_struct worker;
+       struct qeth_card *card;
+       struct qeth_ipacmd_addr_change hostevs;
+};
+
+static void qeth_bridge_host_event_worker(struct work_struct *work)
+{
+       struct qeth_bridge_host_data *data =
+               container_of(work, struct qeth_bridge_host_data, worker);
+       int i;
+
+       if (data->hostevs.lost_event_mask) {
+               dev_info(&data->card->gdev->dev,
+"Address notification from the HiperSockets Bridge Port stopped %s (%s)\n",
+                       data->card->dev->name,
+                       (data->hostevs.lost_event_mask == 0x01)
+                       ? "Overflow"
+                       : (data->hostevs.lost_event_mask == 0x02)
+                       ? "Bridge port state change"
+                       : "Unknown reason");
+               mutex_lock(&data->card->conf_mutex);
+               data->card->options.sbp.hostnotification = 0;
+               mutex_unlock(&data->card->conf_mutex);
+               qeth_bridge_emit_host_event(data->card, anev_abort,
+                       0, NULL, NULL);
+       } else
+               for (i = 0; i < data->hostevs.num_entries; i++) {
+                       struct qeth_ipacmd_addr_change_entry *entry =
+                                       &data->hostevs.entry[i];
+                       qeth_bridge_emit_host_event(data->card,
+                                       anev_reg_unreg,
+                                       entry->change_code,
+                                       &entry->token, &entry->addr_lnid);
+               }
+       kfree(data);
+}
+
+void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
+{
+       struct qeth_ipacmd_addr_change *hostevs =
+                &cmd->data.addrchange;
+       struct qeth_bridge_host_data *data;
+       int extrasize;
+
+       QETH_CARD_TEXT(card, 2, "brhostev");
+       if (cmd->hdr.return_code != 0x0000) {
+               if (cmd->hdr.return_code == 0x0010) {
+                       if (hostevs->lost_event_mask == 0x00)
+                               hostevs->lost_event_mask = 0xff;
+               } else {
+                       QETH_CARD_TEXT_(card, 2, "BPHe%04x",
+                               cmd->hdr.return_code);
+                       return;
+               }
+       }
+       extrasize = sizeof(struct qeth_ipacmd_addr_change_entry) *
+                                               hostevs->num_entries;
+       data = kzalloc(sizeof(struct qeth_bridge_host_data) + extrasize,
+               GFP_ATOMIC);
+       if (!data) {
+               QETH_CARD_TEXT(card, 2, "BPHalloc");
+               return;
+       }
+       INIT_WORK(&data->worker, qeth_bridge_host_event_worker);
+       data->card = card;
+       memcpy(&data->hostevs, hostevs,
+                       sizeof(struct qeth_ipacmd_addr_change) + extrasize);
+       queue_work(qeth_wq, &data->worker);
+}
+EXPORT_SYMBOL(qeth_bridge_host_event);
+
+/* SETBRIDGEPORT support; sending commands */
+
+struct _qeth_sbp_cbctl {
+       u16 ipa_rc;
+       u16 cmd_rc;
+       union {
+               u32 supported;
+               struct {
+                       enum qeth_sbp_roles *role;
+                       enum qeth_sbp_states *state;
+               } qports;
+       } data;
+};
+
+/**
+ * qeth_bridgeport_makerc() - derive "traditional" error from hardware codes.
+ * @card:                    qeth_card structure pointer, for debug messages.
+ * @cbctl:                   state structure with hardware return codes.
+ * @setcmd:                  IPA command code
+ *
+ * Returns negative errno-compatible error indication or 0 on success.
+ */
+static int qeth_bridgeport_makerc(struct qeth_card *card,
+       struct _qeth_sbp_cbctl *cbctl, enum qeth_ipa_sbp_cmd setcmd)
+{
+       int rc;
+
+       switch (cbctl->ipa_rc) {
+       case IPA_RC_SUCCESS:
+               switch (cbctl->cmd_rc) {
+               case 0x0000:
+                       rc = 0;
+                       break;
+               case 0x0004:
+                       rc = -ENOSYS;
+                       break;
+               case 0x000C: /* Not configured as bridge Port */
+                       rc = -ENODEV; /* maybe not the best code here? */
+                       dev_err(&card->gdev->dev,
+       "The HiperSockets device is not configured as a Bridge Port\n");
+                       break;
+               case 0x0014: /* Another device is Primary */
+                       switch (setcmd) {
+                       case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
+                               rc = -EEXIST;
+                               dev_err(&card->gdev->dev,
+       "The HiperSockets LAN already has a primary Bridge Port\n");
+                               break;
+                       case IPA_SBP_SET_SECONDARY_BRIDGE_PORT:
+                               rc = -EBUSY;
+                               dev_err(&card->gdev->dev,
+       "The HiperSockets device is already a primary Bridge Port\n");
+                               break;
+                       default:
+                               rc = -EIO;
+                       }
+                       break;
+               case 0x0018: /* This device is currently Secondary */
+                       rc = -EBUSY;
+                       dev_err(&card->gdev->dev,
+       "The HiperSockets device is already a secondary Bridge Port\n");
+                       break;
+               case 0x001C: /* Limit for Secondary devices reached */
+                       rc = -EEXIST;
+                       dev_err(&card->gdev->dev,
+       "The HiperSockets LAN cannot have more secondary Bridge Ports\n");
+                       break;
+               case 0x0024: /* This device is currently Primary */
+                       rc = -EBUSY;
+                       dev_err(&card->gdev->dev,
+       "The HiperSockets device is already a primary Bridge Port\n");
+                       break;
+               case 0x0020: /* Not authorized by zManager */
+                       rc = -EACCES;
+                       dev_err(&card->gdev->dev,
+       "The HiperSockets device is not authorized to be a Bridge Port\n");
+                       break;
+               default:
+                       rc = -EIO;
+               }
+               break;
+       case IPA_RC_NOTSUPP:
+               rc = -ENOSYS;
+               break;
+       case IPA_RC_UNSUPPORTED_COMMAND:
+               rc = -ENOSYS;
+               break;
+       default:
+               rc = -EIO;
+       }
+       if (rc) {
+               QETH_CARD_TEXT_(card, 2, "SBPi%04x", cbctl->ipa_rc);
+               QETH_CARD_TEXT_(card, 2, "SBPc%04x", cbctl->cmd_rc);
+       }
+       return rc;
+}
+
+static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
+       struct qeth_reply *reply, unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
+       struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
+       QETH_CARD_TEXT(card, 2, "brqsupcb");
+       cbctl->ipa_rc = cmd->hdr.return_code;
+       cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
+       if ((cbctl->ipa_rc == 0) && (cbctl->cmd_rc == 0)) {
+               cbctl->data.supported =
+                       cmd->data.sbp.data.query_cmds_supp.supported_cmds;
+       } else {
+               cbctl->data.supported = 0;
+       }
+       return 0;
+}
+
+/**
+ * qeth_bridgeport_query_support() - store bitmask of supported subfunctions.
+ * @card:                           qeth_card structure pointer.
+ *
+ * Sets bitmask of supported setbridgeport subfunctions in the qeth_card
+ * strucutre: card->options.sbp.supported_funcs.
+ */
+void qeth_bridgeport_query_support(struct qeth_card *card)
+{
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       struct _qeth_sbp_cbctl cbctl;
+
+       QETH_CARD_TEXT(card, 2, "brqsuppo");
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       cmd->data.sbp.hdr.cmdlength =
+               sizeof(struct qeth_ipacmd_sbp_hdr) +
+               sizeof(struct qeth_sbp_query_cmds_supp);
+       cmd->data.sbp.hdr.command_code =
+               IPA_SBP_QUERY_COMMANDS_SUPPORTED;
+       cmd->data.sbp.hdr.used_total = 1;
+       cmd->data.sbp.hdr.seq_no = 1;
+       if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb,
+                                                       (void *)&cbctl) ||
+           qeth_bridgeport_makerc(card, &cbctl,
+                                       IPA_SBP_QUERY_COMMANDS_SUPPORTED)) {
+               /* non-zero makerc signifies failure, and produce messages */
+               card->options.sbp.role = QETH_SBP_ROLE_NONE;
+               return;
+       }
+       card->options.sbp.supported_funcs = cbctl.data.supported;
+}
+EXPORT_SYMBOL_GPL(qeth_bridgeport_query_support);
+
+static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
+       struct qeth_reply *reply, unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
+       struct qeth_sbp_query_ports *qports = &cmd->data.sbp.data.query_ports;
+       struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
+
+       QETH_CARD_TEXT(card, 2, "brqprtcb");
+       cbctl->ipa_rc = cmd->hdr.return_code;
+       cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
+       if ((cbctl->ipa_rc != 0) || (cbctl->cmd_rc != 0))
+               return 0;
+       if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
+               cbctl->cmd_rc = 0xffff;
+               QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length);
+               return 0;
+       }
+       /* first entry contains the state of the local port */
+       if (qports->num_entries > 0) {
+               if (cbctl->data.qports.role)
+                       *cbctl->data.qports.role = qports->entry[0].role;
+               if (cbctl->data.qports.state)
+                       *cbctl->data.qports.state = qports->entry[0].state;
+       }
+       return 0;
+}
+
+/**
+ * qeth_bridgeport_query_ports() - query local bridgeport status.
+ * @card:                         qeth_card structure pointer.
+ * @role:   Role of the port: 0-none, 1-primary, 2-secondary.
+ * @state:  State of the port: 0-inactive, 1-standby, 2-active.
+ *
+ * Returns negative errno-compatible error indication or 0 on success.
+ *
+ * 'role' and 'state' are not updated in case of hardware operation failure.
+ */
+int qeth_bridgeport_query_ports(struct qeth_card *card,
+       enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
+{
+       int rc = 0;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       struct _qeth_sbp_cbctl cbctl = {
+               .data = {
+                       .qports = {
+                               .role = role,
+                               .state = state,
+                       },
+               },
+       };
+
+       QETH_CARD_TEXT(card, 2, "brqports");
+       if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS))
+               return -EOPNOTSUPP;
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       cmd->data.sbp.hdr.cmdlength =
+               sizeof(struct qeth_ipacmd_sbp_hdr);
+       cmd->data.sbp.hdr.command_code =
+               IPA_SBP_QUERY_BRIDGE_PORTS;
+       cmd->data.sbp.hdr.used_total = 1;
+       cmd->data.sbp.hdr.seq_no = 1;
+       rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
+                               (void *)&cbctl);
+       if (rc)
+               return rc;
+       rc = qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
+       if (rc)
+               return rc;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports);
+
+static int qeth_bridgeport_set_cb(struct qeth_card *card,
+       struct qeth_reply *reply, unsigned long data)
+{
+       struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
+       struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
+       QETH_CARD_TEXT(card, 2, "brsetrcb");
+       cbctl->ipa_rc = cmd->hdr.return_code;
+       cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
+       return 0;
+}
+
+/**
+ * qeth_bridgeport_setrole() - Assign primary role to the port.
+ * @card:                     qeth_card structure pointer.
+ * @role:                     Role to assign.
+ *
+ * Returns negative errno-compatible error indication or 0 on success.
+ */
+int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
+{
+       int rc = 0;
+       int cmdlength;
+       struct qeth_cmd_buffer *iob;
+       struct qeth_ipa_cmd *cmd;
+       struct _qeth_sbp_cbctl cbctl;
+       enum qeth_ipa_sbp_cmd setcmd;
+
+       QETH_CARD_TEXT(card, 2, "brsetrol");
+       switch (role) {
+       case QETH_SBP_ROLE_NONE:
+               setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE;
+               cmdlength =  sizeof(struct qeth_ipacmd_sbp_hdr) +
+                       sizeof(struct qeth_sbp_reset_role);
+               break;
+       case QETH_SBP_ROLE_PRIMARY:
+               setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT;
+               cmdlength =  sizeof(struct qeth_ipacmd_sbp_hdr) +
+                       sizeof(struct qeth_sbp_set_primary);
+               break;
+       case QETH_SBP_ROLE_SECONDARY:
+               setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT;
+               cmdlength =  sizeof(struct qeth_ipacmd_sbp_hdr) +
+                       sizeof(struct qeth_sbp_set_secondary);
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (!(card->options.sbp.supported_funcs & setcmd))
+               return -EOPNOTSUPP;
+       iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+       cmd->data.sbp.hdr.cmdlength = cmdlength;
+       cmd->data.sbp.hdr.command_code = setcmd;
+       cmd->data.sbp.hdr.used_total = 1;
+       cmd->data.sbp.hdr.seq_no = 1;
+       rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb,
+                               (void *)&cbctl);
+       if (rc)
+               return rc;
+       rc = qeth_bridgeport_makerc(card, &cbctl, setcmd);
+       return rc;
+}
+
+/**
+ * qeth_anset_makerc() - derive "traditional" error from hardware codes.
+ * @card:                    qeth_card structure pointer, for debug messages.
+ *
+ * Returns negative errno-compatible error indication or 0 on success.
+ */
+static int qeth_anset_makerc(struct qeth_card *card, int pnso_rc, u16 response)
+{
+       int rc;
+
+       if (pnso_rc == 0)
+               switch (response) {
+               case 0x0001:
+                       rc = 0;
+                       break;
+               case 0x0004:
+               case 0x0100:
+               case 0x0106:
+                       rc = -ENOSYS;
+                       dev_err(&card->gdev->dev,
+                               "Setting address notification failed\n");
+                       break;
+               case 0x0107:
+                       rc = -EAGAIN;
+                       break;
+               default:
+                       rc = -EIO;
+               }
+       else
+               rc = -EIO;
+
+       if (rc) {
+               QETH_CARD_TEXT_(card, 2, "SBPp%04x", pnso_rc);
+               QETH_CARD_TEXT_(card, 2, "SBPr%04x", response);
+       }
+       return rc;
+}
+
+static void qeth_bridgeport_an_set_cb(void *priv,
+               enum qdio_brinfo_entry_type type, void *entry)
+{
+       struct qeth_card *card = (struct qeth_card *)priv;
+       struct qdio_brinfo_entry_l2 *l2entry;
+       u8 code;
+
+       if (type != l2_addr_lnid) {
+               WARN_ON_ONCE(1);
+               return;
+       }
+
+       l2entry = (struct qdio_brinfo_entry_l2 *)entry;
+       code = IPA_ADDR_CHANGE_CODE_MACADDR;
+       if (l2entry->addr_lnid.lnid)
+               code |= IPA_ADDR_CHANGE_CODE_VLANID;
+       qeth_bridge_emit_host_event(card, anev_reg_unreg, code,
+               (struct net_if_token *)&l2entry->nit,
+               (struct mac_addr_lnid *)&l2entry->addr_lnid);
+}
+
+/**
+ * qeth_bridgeport_an_set() - Enable or disable bridgeport address notification
+ * @card:                    qeth_card structure pointer.
+ * @enable:                  0 - disable, non-zero - enable notifications
+ *
+ * Returns negative errno-compatible error indication or 0 on success.
+ *
+ * On enable, emits a series of address notifications udev events for all
+ * currently registered hosts.
+ */
+int qeth_bridgeport_an_set(struct qeth_card *card, int enable)
+{
+       int rc;
+       u16 response;
+       struct ccw_device *ddev;
+       struct subchannel_id schid;
+
+       if (!card)
+               return -EINVAL;
+       if (!card->options.sbp.supported_funcs)
+               return -EOPNOTSUPP;
+       ddev = CARD_DDEV(card);
+       ccw_device_get_schid(ddev, &schid);
+
+       if (enable) {
+               qeth_bridge_emit_host_event(card, anev_reset, 0, NULL, NULL);
+               rc = qdio_pnso_brinfo(schid, 1, &response,
+                       qeth_bridgeport_an_set_cb, card);
+       } else
+               rc = qdio_pnso_brinfo(schid, 0, &response, NULL, NULL);
+       return qeth_anset_makerc(card, rc, response);
+}
+EXPORT_SYMBOL_GPL(qeth_bridgeport_an_set);
+
 module_init(qeth_l2_init);
 module_exit(qeth_l2_exit);
 MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c
new file mode 100644 (file)
index 0000000..ae1bc04
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com>
+ */
+
+#include <linux/slab.h>
+#include <asm/ebcdic.h>
+#include "qeth_l2.h"
+
+#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
+
+static int qeth_card_hw_is_reachable(struct qeth_card *card)
+{
+       return (card->state == CARD_STATE_SOFTSETUP) ||
+               (card->state == CARD_STATE_UP);
+}
+
+static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
+                               struct device_attribute *attr, char *buf,
+                               int show_state)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE;
+       int rc = 0;
+       char *word;
+
+       if (!card)
+               return -EINVAL;
+
+       mutex_lock(&card->conf_mutex);
+
+       if (qeth_card_hw_is_reachable(card) &&
+                                       card->options.sbp.supported_funcs)
+               rc = qeth_bridgeport_query_ports(card,
+                       &card->options.sbp.role, &state);
+       if (!rc) {
+               if (show_state)
+                       switch (state) {
+                       case QETH_SBP_STATE_INACTIVE:
+                               word = "inactive"; break;
+                       case QETH_SBP_STATE_STANDBY:
+                               word = "standby"; break;
+                       case QETH_SBP_STATE_ACTIVE:
+                               word = "active"; break;
+                       default:
+                               rc = -EIO;
+                       }
+               else
+                       switch (card->options.sbp.role) {
+                       case QETH_SBP_ROLE_NONE:
+                               word = "none"; break;
+                       case QETH_SBP_ROLE_PRIMARY:
+                               word = "primary"; break;
+                       case QETH_SBP_ROLE_SECONDARY:
+                               word = "secondary"; break;
+                       default:
+                               rc = -EIO;
+                       }
+               if (rc)
+                       QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
+                               card->options.sbp.role, state);
+               else
+                       rc = sprintf(buf, "%s\n", word);
+       }
+
+       mutex_unlock(&card->conf_mutex);
+
+       return rc;
+}
+
+static ssize_t qeth_bridge_port_role_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
+}
+
+static ssize_t qeth_bridge_port_role_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       int rc = 0;
+       enum qeth_sbp_roles role;
+
+       if (!card)
+               return -EINVAL;
+       if (sysfs_streq(buf, "primary"))
+               role = QETH_SBP_ROLE_PRIMARY;
+       else if (sysfs_streq(buf, "secondary"))
+               role = QETH_SBP_ROLE_SECONDARY;
+       else if (sysfs_streq(buf, "none"))
+               role = QETH_SBP_ROLE_NONE;
+       else
+               return -EINVAL;
+
+       mutex_lock(&card->conf_mutex);
+
+       if (qeth_card_hw_is_reachable(card)) {
+               rc = qeth_bridgeport_setrole(card, role);
+               if (!rc)
+                       card->options.sbp.role = role;
+       } else
+               card->options.sbp.role = role;
+
+       mutex_unlock(&card->conf_mutex);
+
+       return rc ? rc : count;
+}
+
+static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
+                  qeth_bridge_port_role_store);
+
+static ssize_t qeth_bridge_port_state_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
+}
+
+static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show,
+                  NULL);
+
+static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       int enabled;
+
+       if (!card)
+               return -EINVAL;
+
+       mutex_lock(&card->conf_mutex);
+
+       enabled = card->options.sbp.hostnotification;
+
+       mutex_unlock(&card->conf_mutex);
+
+       return sprintf(buf, "%d\n", enabled);
+}
+
+static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct qeth_card *card = dev_get_drvdata(dev);
+       int rc = 0;
+       int enable;
+
+       if (!card)
+               return -EINVAL;
+
+       if (sysfs_streq(buf, "0"))
+               enable = 0;
+       else if (sysfs_streq(buf, "1"))
+               enable = 1;
+       else
+               return -EINVAL;
+
+       mutex_lock(&card->conf_mutex);
+
+       if (qeth_card_hw_is_reachable(card)) {
+               rc = qeth_bridgeport_an_set(card, enable);
+               if (!rc)
+                       card->options.sbp.hostnotification = enable;
+       } else
+               card->options.sbp.hostnotification = enable;
+
+       mutex_unlock(&card->conf_mutex);
+
+       return rc ? rc : count;
+}
+
+static DEVICE_ATTR(bridge_hostnotify, 0644,
+                       qeth_bridgeport_hostnotification_show,
+                       qeth_bridgeport_hostnotification_store);
+
+static struct attribute *qeth_l2_bridgeport_attrs[] = {
+       &dev_attr_bridge_role.attr,
+       &dev_attr_bridge_state.attr,
+       &dev_attr_bridge_hostnotify.attr,
+       NULL,
+};
+
+static struct attribute_group qeth_l2_bridgeport_attr_group = {
+       .attrs = qeth_l2_bridgeport_attrs,
+};
+
+int qeth_l2_create_device_attributes(struct device *dev)
+{
+       return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
+}
+
+void qeth_l2_remove_device_attributes(struct device *dev)
+{
+       sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
+}
+
+/**
+ * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
+ * @card:                            qeth_card structure pointer
+ *
+ * Note: this function is called with conf_mutex held by the caller
+ */
+void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
+{
+       int rc;
+
+       if (!card)
+               return;
+       if (!card->options.sbp.supported_funcs)
+               return;
+       if (card->options.sbp.role != QETH_SBP_ROLE_NONE) {
+               /* Conditional to avoid spurious error messages */
+               qeth_bridgeport_setrole(card, card->options.sbp.role);
+               /* Let the callback function refresh the stored role value. */
+               qeth_bridgeport_query_ports(card,
+                       &card->options.sbp.role, NULL);
+       }
+       if (card->options.sbp.hostnotification) {
+               rc = qeth_bridgeport_an_set(card, 1);
+               if (rc)
+                       card->options.sbp.hostnotification = 0;
+       } else
+               qeth_bridgeport_an_set(card, 0);
+}
index 50328de..937fc31 100644 (file)
@@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
        { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
-       { 0 },
+       { NULL },
 };
 
 static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
@@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
        { "SST25VF016", 0x41, 0x1000, 512, },
        { "SST25VF032", 0x4a, 0x1000, 1024, },
        { "SST25VF064", 0x4b, 0x1000, 2048, },
-       { 0 },
+       { NULL },
 };
 
 static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
@@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
        { "AT45DB161", 0x2c, 512, 4096, },
        { "AT45DB321", 0x34, 512, 8192, },
        { "AT45DB642", 0x3c, 1024, 8192, },
-       { 0 },
+       { NULL },
 };
 
 static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
index 53fee2f..8dfdd27 100644 (file)
@@ -39,7 +39,8 @@ static INT bcm_close(struct net_device *dev)
        return 0;
 }
 
-static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb,
+                           void *accel_priv)
 {
        return ClassifyPacket(netdev_priv(dev), skb);
 }
index 9b48373..4a08e16 100644 (file)
@@ -770,9 +770,9 @@ do_del_chan (struct net_device *musycc_dev, void *data)
     if (cp.channum > 999)
         return -EINVAL;
     snprintf (buf, sizeof(buf), CHANNAME "%d", cp.channum);
-    if (!(dev = dev_get_by_name (&init_net, buf)))
-        return -ENOENT;
-    dev_put (dev);
+       dev = __dev_get_by_name(&init_net, buf);
+       if (!dev)
+               return -ENODEV;
     ret = do_deluser (dev, 1);
     if (ret)
         return ret;
@@ -792,19 +792,18 @@ do_reset (struct net_device *musycc_dev, void *data)
         char        buf[sizeof (CHANNAME) + 3];
 
         sprintf (buf, CHANNAME "%d", i);
-        if (!(ndev = dev_get_by_name(&init_net, buf)))
-            continue;
+       ndev = __dev_get_by_name(&init_net, buf);
+       if (!ndev)
+               continue;
         priv = dev_to_hdlc (ndev)->priv;
 
         if ((unsigned long) (priv->ci) ==
             (unsigned long) (netdev_priv(musycc_dev)))
         {
             ndev->flags &= ~IFF_UP;
-            dev_put (ndev);
             netif_stop_queue (ndev);
             do_deluser (ndev, 1);
-        } else
-            dev_put (ndev);
+       }
     }
     return 0;
 }
index 31f1d75..3bbe9e1 100644 (file)
@@ -1,6 +1,6 @@
 config DGAP
        tristate "Digi EPCA PCI products"
        default n
-       depends on TTY
+       depends on TTY && HAS_IOMEM
        ---help---
        Driver for the Digi International EPCA PCI based product line
index e3d6430..3633298 100644 (file)
@@ -103,6 +103,7 @@ config AD7280
 config LPC32XX_ADC
        tristate "NXP LPC32XX ADC"
        depends on ARCH_LPC32XX || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Say yes here to build support for the integrated ADC inside the
          LPC32XX SoC. Note that this feature uses the same hardware as the
@@ -128,6 +129,7 @@ config MXS_LRADC
 config SPEAR_ADC
        tristate "ST SPEAr ADC"
        depends on PLAT_SPEAR || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Say yes here to build support for the integrated ADC inside the
          ST SPEAr SoC. Provides direct access via sysfs.
index 235d2b1..eedffed 100644 (file)
@@ -306,7 +306,8 @@ static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb,
        return NETDEV_TX_OK;
 }
 
-static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb)
+static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb,
+                               void *accel_priv)
 {
        return (u16)smp_processor_id();
 }
index 17659bb..dd69e34 100644 (file)
@@ -652,7 +652,8 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb)
        return dscp >> 5;
 }
 
-static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb)
+static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb,
+                           void *accel_priv)
 {
        struct adapter  *padapter = rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
index aa33976..2c29db6 100644 (file)
@@ -477,9 +477,10 @@ extern int CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
                        const int netfid, __u64 *pExtAttrBits, __u64 *pMask);
 extern void cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb);
 extern bool CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr);
-extern int CIFSCheckMFSymlink(struct cifs_fattr *fattr,
-               const unsigned char *path,
-               struct cifs_sb_info *cifs_sb, unsigned int xid);
+extern int CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
+                             struct cifs_sb_info *cifs_sb,
+                             struct cifs_fattr *fattr,
+                             const unsigned char *path);
 extern int mdfour(unsigned char *, unsigned char *, int);
 extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
                        const struct nls_table *codepage);
index 124aa02..d707edb 100644 (file)
@@ -4010,7 +4010,7 @@ QFileInfoRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
-               cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
+               cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
@@ -4179,7 +4179,7 @@ UnixQFileInfoRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
-               cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
+               cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
@@ -4263,7 +4263,7 @@ UnixQPathInfoRetry:
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
-               cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
+               cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
        } else {                /* decode response */
                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
 
index 11ff5f1..a514e0a 100644 (file)
@@ -193,7 +193,7 @@ check_name(struct dentry *direntry)
 static int
 cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
               struct tcon_link *tlink, unsigned oflags, umode_t mode,
-              __u32 *oplock, struct cifs_fid *fid, int *created)
+              __u32 *oplock, struct cifs_fid *fid)
 {
        int rc = -ENOENT;
        int create_options = CREATE_NOT_DIR;
@@ -349,7 +349,6 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
                                .device = 0,
                };
 
-               *created |= FILE_CREATED;
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
                        args.uid = current_fsuid();
                        if (inode->i_mode & S_ISGID)
@@ -480,13 +479,16 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
        cifs_add_pending_open(&fid, tlink, &open);
 
        rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-                           &oplock, &fid, opened);
+                           &oplock, &fid);
 
        if (rc) {
                cifs_del_pending_open(&open);
                goto out;
        }
 
+       if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+               *opened |= FILE_CREATED;
+
        rc = finish_open(file, direntry, generic_file_open, opened);
        if (rc) {
                if (server->ops->close)
@@ -529,7 +531,6 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
        struct TCP_Server_Info *server;
        struct cifs_fid fid;
        __u32 oplock;
-       int created = FILE_CREATED;
 
        cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p\n",
                 inode, direntry->d_name.name, direntry);
@@ -546,7 +547,7 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
                server->ops->new_lease_key(&fid);
 
        rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-                           &oplock, &fid, &created);
+                           &oplock, &fid);
        if (!rc && server->ops->close)
                server->ops->close(xid, tcon, &fid);
 
index 36f9ebb..49719b8 100644 (file)
@@ -383,7 +383,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 
        /* check for Minshall+French symlinks */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
-               int tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
+               int tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr,
+                                              full_path);
                if (tmprc)
                        cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc);
        }
@@ -799,7 +800,8 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
 
        /* check for Minshall+French symlinks */
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) {
-               tmprc = CIFSCheckMFSymlink(&fattr, full_path, cifs_sb, xid);
+               tmprc = CIFSCheckMFSymlink(xid, tcon, cifs_sb, &fattr,
+                                          full_path);
                if (tmprc)
                        cifs_dbg(FYI, "CIFSCheckMFSymlink: %d\n", tmprc);
        }
index cc02347..92aee08 100644 (file)
@@ -354,34 +354,30 @@ open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
 
 
 int
-CIFSCheckMFSymlink(struct cifs_fattr *fattr,
-                  const unsigned char *path,
-                  struct cifs_sb_info *cifs_sb, unsigned int xid)
+CIFSCheckMFSymlink(unsigned int xid, struct cifs_tcon *tcon,
+                  struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
+                  const unsigned char *path)
 {
-       int rc = 0;
+       int rc;
        u8 *buf = NULL;
        unsigned int link_len = 0;
        unsigned int bytes_read = 0;
-       struct cifs_tcon *ptcon;
 
        if (!CIFSCouldBeMFSymlink(fattr))
                /* it's not a symlink */
                return 0;
 
        buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
-       if (!buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!buf)
+               return -ENOMEM;
 
-       ptcon = tlink_tcon(cifs_sb_tlink(cifs_sb));
-       if ((ptcon->ses) && (ptcon->ses->server->ops->query_mf_symlink))
-               rc = ptcon->ses->server->ops->query_mf_symlink(path, buf,
-                                                &bytes_read, cifs_sb, xid);
+       if (tcon->ses->server->ops->query_mf_symlink)
+               rc = tcon->ses->server->ops->query_mf_symlink(path, buf,
+                                               &bytes_read, cifs_sb, xid);
        else
-               goto out;
+               rc = -ENOSYS;
 
-       if (rc != 0)
+       if (rc)
                goto out;
 
        if (bytes_read == 0) /* not a symlink */
index 8b5e258..af90312 100644 (file)
@@ -1907,10 +1907,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
                        }
                }
        }
-       if (op == EPOLL_CTL_DEL && is_file_epoll(tf.file)) {
-               tep = tf.file->private_data;
-               mutex_lock_nested(&tep->mtx, 1);
-       }
 
        /*
         * Try to lookup the file inside our RB tree, Since we grabbed "mtx"
index 4410cc3..3384dc4 100644 (file)
@@ -4218,7 +4218,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
         */
        map->m_flags &= ~EXT4_MAP_FROM_CLUSTER;
        newex.ee_block = cpu_to_le32(map->m_lblk);
-       cluster_offset = EXT4_LBLK_CMASK(sbi, map->m_lblk);
+       cluster_offset = EXT4_LBLK_COFF(sbi, map->m_lblk);
 
        /*
         * If we are doing bigalloc, check to see if the extent returned
index b7fc035..73f3e4e 100644 (file)
@@ -986,6 +986,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
+       struct address_space *mapping = inode->i_mapping;
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_holder gh;
        int rv;
@@ -1006,6 +1007,35 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
        if (rv != 1)
                goto out; /* dio not valid, fall back to buffered i/o */
 
+       /*
+        * Now since we are holding a deferred (CW) lock at this point, you
+        * might be wondering why this is ever needed. There is a case however
+        * where we've granted a deferred local lock against a cached exclusive
+        * glock. That is ok provided all granted local locks are deferred, but
+        * it also means that it is possible to encounter pages which are
+        * cached and possibly also mapped. So here we check for that and sort
+        * them out ahead of the dio. The glock state machine will take care of
+        * everything else.
+        *
+        * If in fact the cached glock state (gl->gl_state) is deferred (CW) in
+        * the first place, mapping->nr_pages will always be zero.
+        */
+       if (mapping->nrpages) {
+               loff_t lstart = offset & (PAGE_CACHE_SIZE - 1);
+               loff_t len = iov_length(iov, nr_segs);
+               loff_t end = PAGE_ALIGN(offset + len) - 1;
+
+               rv = 0;
+               if (len == 0)
+                       goto out;
+               if (test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags))
+                       unmap_shared_mapping_range(ip->i_inode.i_mapping, offset, len);
+               rv = filemap_write_and_wait_range(mapping, lstart, end);
+               if (rv)
+                       return rv;
+               truncate_inode_pages_range(mapping, lstart, end);
+       }
+
        rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
                                  offset, nr_segs, gfs2_get_block_direct,
                                  NULL, NULL, 0);
index c8420f7..6f7a47c 100644 (file)
@@ -1655,6 +1655,7 @@ static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh)
        struct task_struct *gh_owner = NULL;
        char flags_buf[32];
 
+       rcu_read_lock();
        if (gh->gh_owner_pid)
                gh_owner = pid_task(gh->gh_owner_pid, PIDTYPE_PID);
        gfs2_print_dbg(seq, " H: s:%s f:%s e:%d p:%ld [%s] %pS\n",
@@ -1664,6 +1665,7 @@ static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh)
                       gh->gh_owner_pid ? (long)pid_nr(gh->gh_owner_pid) : -1,
                       gh_owner ? gh_owner->comm : "(ended)",
                       (void *)gh->gh_ip);
+       rcu_read_unlock();
        return 0;
 }
 
index db908f6..f88dcd9 100644 (file)
@@ -192,8 +192,11 @@ static void inode_go_sync(struct gfs2_glock *gl)
 
        if (ip && !S_ISREG(ip->i_inode.i_mode))
                ip = NULL;
-       if (ip && test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags))
-               unmap_shared_mapping_range(ip->i_inode.i_mapping, 0, 0);
+       if (ip) {
+               if (test_and_clear_bit(GIF_SW_PAGED, &ip->i_flags))
+                       unmap_shared_mapping_range(ip->i_inode.i_mapping, 0, 0);
+               inode_dio_wait(&ip->i_inode);
+       }
        if (!test_and_clear_bit(GLF_DIRTY, &gl->gl_flags))
                return;
 
@@ -410,6 +413,9 @@ static int inode_go_lock(struct gfs2_holder *gh)
                        return error;
        }
 
+       if (gh->gh_state != LM_ST_DEFERRED)
+               inode_dio_wait(&ip->i_inode);
+
        if ((ip->i_diskflags & GFS2_DIF_TRUNC_IN_PROG) &&
            (gl->gl_state == LM_ST_EXCLUSIVE) &&
            (gh->gh_state == LM_ST_EXCLUSIVE)) {
index 610613f..9dcb977 100644 (file)
@@ -551,10 +551,10 @@ void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
        struct buffer_head *bh = bd->bd_bh;
        struct gfs2_glock *gl = bd->bd_gl;
 
-       gfs2_remove_from_ail(bd);
-       bd->bd_bh = NULL;
        bh->b_private = NULL;
        bd->bd_blkno = bh->b_blocknr;
+       gfs2_remove_from_ail(bd); /* drops ref on bh */
+       bd->bd_bh = NULL;
        bd->bd_ops = &gfs2_revoke_lops;
        sdp->sd_log_num_revoke++;
        atomic_inc(&gl->gl_revokes);
index 9324150..52f177b 100644 (file)
@@ -258,6 +258,7 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int
        struct address_space *mapping = bh->b_page->mapping;
        struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
        struct gfs2_bufdata *bd = bh->b_private;
+       int was_pinned = 0;
 
        if (test_clear_buffer_pinned(bh)) {
                trace_gfs2_pin(bd, 0);
@@ -273,12 +274,16 @@ void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int
                        tr->tr_num_databuf_rm++;
                }
                tr->tr_touched = 1;
+               was_pinned = 1;
                brelse(bh);
        }
        if (bd) {
                spin_lock(&sdp->sd_ail_lock);
                if (bd->bd_tr) {
                        gfs2_trans_add_revoke(sdp, bd);
+               } else if (was_pinned) {
+                       bh->b_private = NULL;
+                       kmem_cache_free(gfs2_bufdata_cachep, bd);
                }
                spin_unlock(&sdp->sd_ail_lock);
        }
index 82303b4..52fa883 100644 (file)
@@ -1366,8 +1366,18 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
        if (IS_ERR(s))
                goto error_bdev;
 
-       if (s->s_root)
+       if (s->s_root) {
+               /*
+                * s_umount nests inside bd_mutex during
+                * __invalidate_device().  blkdev_put() acquires
+                * bd_mutex and can't be called under s_umount.  Drop
+                * s_umount temporarily.  This is safe as we're
+                * holding an active reference.
+                */
+               up_write(&s->s_umount);
                blkdev_put(bdev, mode);
+               down_write(&s->s_umount);
+       }
 
        memset(&args, 0, sizeof(args));
        args.ar_quota = GFS2_QUOTA_DEFAULT;
index 739e0a5..5549d69 100644 (file)
@@ -110,7 +110,7 @@ xfs_attr3_rmt_verify(
        if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
                return false;
        if (be32_to_cpu(rmt->rm_offset) +
-                               be32_to_cpu(rmt->rm_bytes) >= XATTR_SIZE_MAX)
+                               be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX)
                return false;
        if (rmt->rm_owner == 0)
                return false;
index 1394106..82e0dab 100644 (file)
@@ -287,6 +287,7 @@ xfs_bmapi_allocate(
        INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker);
        queue_work(xfs_alloc_wq, &args->work);
        wait_for_completion(&done);
+       destroy_work_on_stack(&args->work);
        return args->result;
 }
 
index c602c77..ddabed1 100644 (file)
@@ -169,7 +169,8 @@ struct acpi_device_flags {
        u32 ejectable:1;
        u32 power_manageable:1;
        u32 match_driver:1;
-       u32 reserved:27;
+       u32 no_hotplug:1;
+       u32 reserved:26;
 };
 
 /* File System */
@@ -344,6 +345,7 @@ extern struct kobject *acpi_kobj;
 extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
 void acpi_bus_private_data_handler(acpi_handle, void *);
 int acpi_bus_get_private_data(acpi_handle, void **);
+void acpi_bus_no_hotplug(acpi_handle handle);
 extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
 extern int register_acpi_notifier(struct notifier_block *);
 extern int unregister_acpi_notifier(struct notifier_block *);
index 87578c1..49376ae 100644 (file)
        {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
        {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
-       {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
+       {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\
        {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
index f344ac0..9c5529d 100644 (file)
@@ -218,6 +218,28 @@ static inline void eth_hw_addr_random(struct net_device *dev)
 }
 
 /**
+ * ether_addr_copy - Copy an Ethernet address
+ * @dst: Pointer to a six-byte array Ethernet address destination
+ * @src: Pointer to a six-byte array Ethernet address source
+ *
+ * Please note: dst & src must both be aligned to u16.
+ */
+static inline void ether_addr_copy(u8 *dst, const u8 *src)
+{
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+       *(u32 *)dst = *(const u32 *)src;
+       *(u16 *)(dst + 4) = *(const u16 *)(src + 4);
+#else
+       u16 *a = (u16 *)dst;
+       const u16 *b = (const u16 *)src;
+
+       a[0] = b[0];
+       a[1] = b[1];
+       a[2] = b[2];
+#endif
+}
+
+/**
  * eth_hw_addr_inherit - Copy dev_addr from another net_device
  * @dst: pointer to net_device to copy dev_addr to
  * @src: pointer to net_device to copy dev_addr from
@@ -229,7 +251,7 @@ static inline void eth_hw_addr_inherit(struct net_device *dst,
                                       struct net_device *src)
 {
        dst->addr_assign_type = src->addr_assign_type;
-       memcpy(dst->dev_addr, src->dev_addr, ETH_ALEN);
+       ether_addr_copy(dst->dev_addr, src->dev_addr);
 }
 
 /**
index 9f03fee..d883662 100644 (file)
 /*
  * Vendors and devices.  Sort key: vendor first, device next.
  */
+#define SDIO_VENDOR_ID_BROADCOM                        0x02d0
+#define SDIO_DEVICE_ID_BROADCOM_43143          43143
+#define SDIO_DEVICE_ID_BROADCOM_43241          0x4324
+#define SDIO_DEVICE_ID_BROADCOM_4329           0x4329
+#define SDIO_DEVICE_ID_BROADCOM_4330           0x4330
+#define SDIO_DEVICE_ID_BROADCOM_4334           0x4334
+#define SDIO_DEVICE_ID_BROADCOM_4335_4339      0x4335
+#define SDIO_DEVICE_ID_BROADCOM_43362          43362
+
 #define SDIO_VENDOR_ID_INTEL                   0x0089
 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX     0x1402
 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI      0x1403
index 69be3e6..94734a6 100644 (file)
@@ -245,9 +245,6 @@ do {                                                                \
 #define net_dbg_ratelimited(fmt, ...)                          \
        net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__)
 
-#define net_random()           prandom_u32()
-#define net_srandom(seed)      prandom_seed((__force u32)(seed))
-
 bool __net_get_random_once(void *buf, int nbytes, bool *done,
                           struct static_key *done_key);
 
index a2a70cc..30f6513 100644 (file)
@@ -769,7 +769,8 @@ struct netdev_phys_port_id {
  *        (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX)
  *     Required can not be NULL.
  *
- * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb);
+ * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb,
+ *                         void *accel_priv);
  *     Called to decide which queue to when device supports multiple
  *     transmit queues.
  *
@@ -990,7 +991,8 @@ struct net_device_ops {
        netdev_tx_t             (*ndo_start_xmit) (struct sk_buff *skb,
                                                   struct net_device *dev);
        u16                     (*ndo_select_queue)(struct net_device *dev,
-                                                   struct sk_buff *skb);
+                                                   struct sk_buff *skb,
+                                                   void *accel_priv);
        void                    (*ndo_change_rx_flags)(struct net_device *dev,
                                                       int flags);
        void                    (*ndo_set_rx_mode)(struct net_device *dev);
@@ -1532,7 +1534,8 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
 }
 
 struct netdev_queue *netdev_pick_tx(struct net_device *dev,
-                                   struct sk_buff *skb);
+                                   struct sk_buff *skb,
+                                   void *accel_priv);
 u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb);
 
 /*
@@ -1834,6 +1837,7 @@ int dev_close(struct net_device *dev);
 void dev_disable_lro(struct net_device *dev);
 int dev_loopback_xmit(struct sk_buff *newskb);
 int dev_queue_xmit(struct sk_buff *skb);
+int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv);
 int register_netdevice(struct net_device *dev);
 void unregister_netdevice_queue(struct net_device *dev, struct list_head *head);
 void unregister_netdevice_many(struct list_head *head);
@@ -2486,7 +2490,7 @@ int dev_change_carrier(struct net_device *, bool new_carrier);
 int dev_get_phys_port_id(struct net_device *dev,
                         struct netdev_phys_port_id *ppid);
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
-                       struct netdev_queue *txq, void *accel_priv);
+                       struct netdev_queue *txq);
 int dev_forward_skb(struct net_device *dev, struct sk_buff *skb);
 
 extern int             netdev_budget;
@@ -2937,6 +2941,7 @@ int netdev_master_upper_dev_link_private(struct net_device *dev,
                                         void *private);
 void netdev_upper_dev_unlink(struct net_device *dev,
                             struct net_device *upper_dev);
+void netdev_adjacent_rename_links(struct net_device *dev, char *oldname);
 void *netdev_lower_dev_get_private(struct net_device *dev,
                                   struct net_device *lower_dev);
 int skb_checksum_help(struct sk_buff *skb);
index 8163107..6fe8464 100644 (file)
@@ -19,6 +19,9 @@ extern struct phy_device *of_phy_connect(struct net_device *dev,
                                         struct device_node *phy_np,
                                         void (*hndlr)(struct net_device *),
                                         u32 flags, phy_interface_t iface);
+struct phy_device *of_phy_attach(struct net_device *dev,
+                                struct device_node *phy_np, u32 flags,
+                                phy_interface_t iface);
 extern struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
                                         void (*hndlr)(struct net_device *),
                                         phy_interface_t iface);
@@ -44,6 +47,13 @@ static inline struct phy_device *of_phy_connect(struct net_device *dev,
        return NULL;
 }
 
+static inline struct phy_device *of_phy_attach(struct net_device *dev,
+                                              struct device_node *phy_np,
+                                              u32 flags, phy_interface_t iface)
+{
+       return NULL;
+}
+
 static inline struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
                                                           void (*hndlr)(struct net_device *),
                                                           phy_interface_t iface)
index 7c81dd8..565188c 100644 (file)
@@ -73,6 +73,7 @@ typedef enum {
        PHY_INTERFACE_MODE_RGMII_TXID,
        PHY_INTERFACE_MODE_RTBI,
        PHY_INTERFACE_MODE_SMII,
+       PHY_INTERFACE_MODE_XGMII,
 } phy_interface_t;
 
 
@@ -488,6 +489,24 @@ struct phy_fixup {
 };
 
 /**
+ * phy_read_mmd - Convenience function for reading a register
+ * from an MMD on a given PHY.
+ * @phydev: The phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: The register on the MMD to read
+ *
+ * Same rules as for phy_read();
+ */
+static inline int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
+{
+       if (!phydev->is_c45)
+               return -EOPNOTSUPP;
+
+       return mdiobus_read(phydev->bus, phydev->addr,
+                           MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff));
+}
+
+/**
  * phy_read - Convenience function for reading a given PHY register
  * @phydev: the phy_device struct
  * @regnum: register number to read
@@ -537,6 +556,27 @@ static inline bool phy_is_internal(struct phy_device *phydev)
        return phydev->is_internal;
 }
 
+/**
+ * phy_write_mmd - Convenience function for writing a register
+ * on an MMD on a given PHY.
+ * @phydev: The phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: The register on the MMD to read
+ * @val: value to write to @regnum
+ *
+ * Same rules as for phy_write();
+ */
+static inline int phy_write_mmd(struct phy_device *phydev, int devad,
+                               u32 regnum, u16 val)
+{
+       if (!phydev->is_c45)
+               return -EOPNOTSUPP;
+
+       regnum = MII_ADDR_C45 | ((devad & 0x1f) << 16) | (regnum & 0xffff);
+
+       return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
+}
+
 struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
                                     bool is_c45,
                                     struct phy_c45_device_ids *c45_ids);
@@ -548,6 +588,8 @@ int phy_resume(struct phy_device *phydev);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
                              phy_interface_t interface);
 struct phy_device *phy_find_first(struct mii_bus *bus);
+int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
+                     u32 flags, phy_interface_t interface);
 int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
                       void (*handler)(struct net_device *),
                       phy_interface_t interface);
index d97f2d0..48b7605 100644 (file)
@@ -2893,6 +2893,8 @@ static inline void skb_checksum_none_assert(const struct sk_buff *skb)
 
 bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
 
+int skb_checksum_setup(struct sk_buff *skb, bool recalculate);
+
 u32 __skb_get_poff(const struct sk_buff *skb);
 
 /**
index d34e1f4..e171387 100644 (file)
@@ -39,6 +39,7 @@ struct tcf_hashinfo {
        struct hlist_head       *htab;
        unsigned int            hmask;
        spinlock_t              lock;
+       u32                     index;
 };
 
 static inline unsigned int tcf_hash(u32 index, unsigned int hmask)
@@ -51,6 +52,7 @@ static inline int tcf_hashinfo_init(struct tcf_hashinfo *hf, unsigned int mask)
        int i;
 
        spin_lock_init(&hf->lock);
+       hf->index = 0;
        hf->hmask = mask;
        hf->htab = kzalloc((mask + 1) * sizeof(struct hlist_head),
                           GFP_KERNEL);
@@ -71,10 +73,6 @@ static inline void tcf_hashinfo_destroy(struct tcf_hashinfo *hf)
 #define ACT_P_CREATED 1
 #define ACT_P_DELETED 1
 
-struct tcf_act_hdr {
-       struct tcf_common       common;
-};
-
 struct tc_action {
        void                    *priv;
        const struct tc_action_ops      *ops;
@@ -105,13 +103,12 @@ struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo);
 void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo);
 int tcf_hash_release(struct tcf_common *p, int bind,
                     struct tcf_hashinfo *hinfo);
-u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo);
+u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
 struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a,
                                  int bind, struct tcf_hashinfo *hinfo);
 struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
                                   struct tc_action *a, int size,
-                                  int bind, u32 *idx_gen,
-                                  struct tcf_hashinfo *hinfo);
+                                  int bind, struct tcf_hashinfo *hinfo);
 void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo);
 
 int tcf_register_action(struct tc_action_ops *a);
index cc2da73..66c1cd8 100644 (file)
@@ -83,7 +83,8 @@
 enum {
        HCI_QUIRK_RESET_ON_CLOSE,
        HCI_QUIRK_RAW_DEVICE,
-       HCI_QUIRK_FIXUP_BUFFER_SIZE
+       HCI_QUIRK_FIXUP_BUFFER_SIZE,
+       HCI_QUIRK_BROKEN_STORED_LINK_KEY,
 };
 
 /* HCI device flags */
@@ -131,6 +132,7 @@ enum {
        HCI_PERIODIC_INQ,
        HCI_FAST_CONNECTABLE,
        HCI_BREDR_ENABLED,
+       HCI_6LOWPAN_ENABLED,
 };
 
 /* A mask for the flags that are supposed to remain when a reset happens
index b796161..f2f0cf5 100644 (file)
@@ -448,6 +448,7 @@ enum {
        HCI_CONN_SSP_ENABLED,
        HCI_CONN_POWER_SAVE,
        HCI_CONN_REMOTE_OOB,
+       HCI_CONN_6LOWPAN,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
index e149e99..dbc4a89 100644 (file)
@@ -136,6 +136,7 @@ struct l2cap_conninfo {
 #define L2CAP_FC_L2CAP         0x02
 #define L2CAP_FC_CONNLESS      0x04
 #define L2CAP_FC_A2MP          0x08
+#define L2CAP_FC_6LOWPAN        0x3e /* reserved and temporary value */
 
 /* L2CAP Control Field bit masks */
 #define L2CAP_CTRL_SAR                 0xC000
index 80a1021..56c5977 100644 (file)
@@ -1972,6 +1972,50 @@ struct cfg80211_mgmt_tx_params {
 };
 
 /**
+ * struct cfg80211_dscp_exception - DSCP exception
+ *
+ * @dscp: DSCP value that does not adhere to the user priority range definition
+ * @up: user priority value to which the corresponding DSCP value belongs
+ */
+struct cfg80211_dscp_exception {
+       u8 dscp;
+       u8 up;
+};
+
+/**
+ * struct cfg80211_dscp_range - DSCP range definition for user priority
+ *
+ * @low: lowest DSCP value of this user priority range, inclusive
+ * @high: highest DSCP value of this user priority range, inclusive
+ */
+struct cfg80211_dscp_range {
+       u8 low;
+       u8 high;
+};
+
+/* QoS Map Set element length defined in IEEE Std 802.11-2012, 8.4.2.97 */
+#define IEEE80211_QOS_MAP_MAX_EX       21
+#define IEEE80211_QOS_MAP_LEN_MIN      16
+#define IEEE80211_QOS_MAP_LEN_MAX \
+       (IEEE80211_QOS_MAP_LEN_MIN + 2 * IEEE80211_QOS_MAP_MAX_EX)
+
+/**
+ * struct cfg80211_qos_map - QoS Map Information
+ *
+ * This struct defines the Interworking QoS map setting for DSCP values
+ *
+ * @num_des: number of DSCP exceptions (0..21)
+ * @dscp_exception: optionally up to maximum of 21 DSCP exceptions from
+ *     the user priority DSCP range definition
+ * @up: DSCP range definition for a particular user priority
+ */
+struct cfg80211_qos_map {
+       u8 num_des;
+       struct cfg80211_dscp_exception dscp_exception[IEEE80211_QOS_MAP_MAX_EX];
+       struct cfg80211_dscp_range up[8];
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2213,6 +2257,8 @@ struct cfg80211_mgmt_tx_params {
  * @set_coalesce: Set coalesce parameters.
  *
  * @channel_switch: initiate channel-switch procedure (with CSA)
+ *
+ * @set_qos_map: Set QoS mapping information to the driver
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2454,6 +2500,9 @@ struct cfg80211_ops {
        int     (*channel_switch)(struct wiphy *wiphy,
                                  struct net_device *dev,
                                  struct cfg80211_csa_settings *params);
+       int     (*set_qos_map)(struct wiphy *wiphy,
+                              struct net_device *dev,
+                              struct cfg80211_qos_map *qos_map);
 };
 
 /*
@@ -2824,6 +2873,8 @@ struct wiphy_vendor_command {
  *
  * @vendor_commands: array of vendor commands supported by the hardware
  * @n_vendor_commands: number of vendor commands
+ * @vendor_events: array of vendor events supported by the hardware
+ * @n_vendor_events: number of vendor events
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -2936,7 +2987,8 @@ struct wiphy {
        const struct wiphy_coalesce_support *coalesce;
 
        const struct wiphy_vendor_command *vendor_commands;
-       int n_vendor_commands;
+       const struct nl80211_vendor_cmd_info *vendor_events;
+       int n_vendor_commands, n_vendor_events;
 
        char priv[0] __aligned(NETDEV_ALIGN);
 };
@@ -3429,9 +3481,11 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
+ * @qos_map: Interworking QoS mapping or %NULL if not in use
  * Return: The 802.1p/1d tag.
  */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb);
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+                                   struct cfg80211_qos_map *qos_map);
 
 /**
  * cfg80211_find_ie - find information element in data
@@ -3907,6 +3961,14 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
                                           enum nl80211_attrs attr,
                                           int approxlen);
 
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int vendor_event_idx,
+                                          int approxlen, gfp_t gfp);
+
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp);
+
 /**
  * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
  * @wiphy: the wiphy
@@ -3951,6 +4013,44 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
  */
 int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
 
+/**
+ * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
+ * @wiphy: the wiphy
+ * @event_idx: index of the vendor event in the wiphy's vendor_events
+ * @approxlen: an upper bound of the length of the data that will
+ *     be put into the skb
+ * @gfp: allocation flags
+ *
+ * This function allocates and pre-fills an skb for an event on the
+ * vendor-specific multicast group.
+ *
+ * When done filling the skb, call cfg80211_vendor_event() with the
+ * skb to send the event.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
+                           int event_idx, gfp_t gfp)
+{
+       return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
+                                         NL80211_ATTR_VENDOR_DATA,
+                                         event_idx, approxlen, gfp);
+}
+
+/**
+ * cfg80211_vendor_event - send the event
+ * @skb: The skb, must have been allocated with cfg80211_vendor_event_alloc()
+ * @gfp: allocation flags
+ *
+ * This function sends the given @skb, which must have been allocated
+ * by cfg80211_vendor_event_alloc(), as an event. It always consumes it.
+ */
+static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp)
+{
+       __cfg80211_send_event_skb(skb, gfp);
+}
+
 #ifdef CONFIG_NL80211_TESTMODE
 /**
  * DOC: Test mode
@@ -4031,8 +4131,13 @@ static inline int cfg80211_testmode_reply(struct sk_buff *skb)
  *
  * Return: An allocated and pre-filled skb. %NULL if any errors happen.
  */
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
-                                                 int approxlen, gfp_t gfp);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
+{
+       return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
+                                         NL80211_ATTR_TESTDATA, -1,
+                                         approxlen, gfp);
+}
 
 /**
  * cfg80211_testmode_event - send the event
@@ -4044,7 +4149,10 @@ struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
  * by cfg80211_testmode_alloc_event_skb(), as an event. It always
  * consumes it.
  */
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
+static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+{
+       __cfg80211_send_event_skb(skb, gfp);
+}
 
 #define CFG80211_TESTMODE_CMD(cmd)     .testmode_cmd = (cmd),
 #define CFG80211_TESTMODE_DUMP(cmd)    .testmode_dump = (cmd),
index 5356644..7876e3b 100644 (file)
@@ -90,7 +90,7 @@ struct packet_type;
 struct rtable;
 struct sockaddr;
 
-int igmp_mc_proc_init(void);
+int igmp_mc_init(void);
 
 /*
  *     Functions provided by ip.c
@@ -263,6 +263,39 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
                 !(dst_metric_locked(dst, RTAX_MTU)));
 }
 
+static inline bool ip_sk_accept_pmtu(const struct sock *sk)
+{
+       return inet_sk(sk)->pmtudisc != IP_PMTUDISC_INTERFACE;
+}
+
+static inline bool ip_sk_use_pmtu(const struct sock *sk)
+{
+       return inet_sk(sk)->pmtudisc < IP_PMTUDISC_PROBE;
+}
+
+static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
+                                                   bool forwarding)
+{
+       struct net *net = dev_net(dst->dev);
+
+       if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
+           dst_metric_locked(dst, RTAX_MTU) ||
+           !forwarding)
+               return dst_mtu(dst);
+
+       return min(dst->dev->mtu, IP_MAX_MTU);
+}
+
+static inline unsigned int ip_skb_dst_mtu(const struct sk_buff *skb)
+{
+       if (!skb->sk || ip_sk_use_pmtu(skb->sk)) {
+               bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
+               return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding);
+       } else {
+               return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU);
+       }
+}
+
 void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
 
 static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk)
index 12079c6..6d80f51 100644 (file)
@@ -239,6 +239,7 @@ struct ip6_flowlabel {
 #define IPV6_FLOWINFO_MASK     cpu_to_be32(0x0FFFFFFF)
 #define IPV6_FLOWLABEL_MASK    cpu_to_be32(0x000FFFFF)
 #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+#define IPV6_TCLASS_SHIFT      20
 
 struct ipv6_fl_socklist {
        struct ipv6_fl_socklist __rcu   *next;
@@ -681,6 +682,10 @@ static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr)
        return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK;
 }
 
+static inline u8 ip6_tclass(__be32 flowinfo)
+{
+       return ntohl(flowinfo & IPV6_TCLASS_MASK) >> IPV6_TCLASS_SHIFT;
+}
 /*
  *     Prototypes exported by ipv6
  */
index 531785f..f838af8 100644 (file)
@@ -4652,4 +4652,51 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif, struct sk_buff *skb,
                              int band, struct ieee80211_sta **sta);
 
+/**
+ * struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state
+ *
+ * @next_tsf: TSF timestamp of the next absent state change
+ * @has_next_tsf: next absent state change event pending
+ *
+ * @absent: descriptor bitmask, set if GO is currently absent
+ *
+ * private:
+ *
+ * @count: count fields from the NoA descriptors
+ * @desc: adjusted data from the NoA
+ */
+struct ieee80211_noa_data {
+       u32 next_tsf;
+       bool has_next_tsf;
+
+       u8 absent;
+
+       u8 count[IEEE80211_P2P_NOA_DESC_MAX];
+       struct {
+               u32 start;
+               u32 duration;
+               u32 interval;
+       } desc[IEEE80211_P2P_NOA_DESC_MAX];
+};
+
+/**
+ * ieee80211_parse_p2p_noa - initialize NoA tracking data from P2P IE
+ *
+ * @attr: P2P NoA IE
+ * @data: NoA tracking data
+ * @tsf: current TSF timestamp
+ *
+ * Return: number of successfully parsed descriptors
+ */
+int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
+                           struct ieee80211_noa_data *data, u32 tsf);
+
+/**
+ * ieee80211_update_p2p_noa - get next pending P2P GO absent state change
+ *
+ * @data: NoA tracking data
+ * @tsf: current TSF timestamp
+ */
+void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf);
+
 #endif /* MAC80211_H */
index 4c09bd2..7277caf 100644 (file)
@@ -92,6 +92,11 @@ static inline void neigh_var_set(struct neigh_parms *p, int index, int val)
 }
 
 #define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr])
+
+/* In ndo_neigh_setup, NEIGH_VAR_INIT should be used.
+ * In other cases, NEIGH_VAR_SET should be used.
+ */
+#define NEIGH_VAR_INIT(p, attr, val) (NEIGH_VAR(p, attr) = val)
 #define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val)
 
 static inline void neigh_parms_data_state_setall(struct neigh_parms *p)
index 929a668..80f500a 100644 (file)
@@ -70,6 +70,7 @@ struct netns_ipv4 {
 
        int sysctl_tcp_ecn;
        int sysctl_ip_no_pmtu_disc;
+       int sysctl_ip_fwd_use_pmtu;
 
        kgid_t sysctl_ping_group_range[2];
 
index 76fc7d1..592fecd 100644 (file)
@@ -28,6 +28,7 @@ struct netns_sysctl_ipv6 {
        int ip6_rt_mtu_expires;
        int ip6_rt_min_advmss;
        int icmpv6_time;
+       int anycast_src_echo_reply;
 };
 
 struct netns_ipv6 {
@@ -73,7 +74,6 @@ struct netns_ipv6 {
 #endif
        atomic_t                dev_addr_genid;
        atomic_t                rt_genid;
-       int                     anycast_src_echo_reply;
 };
 
 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
index 50ea079..a2441fb 100644 (file)
@@ -338,27 +338,27 @@ static inline int tcf_valid_offset(const struct sk_buff *skb,
 #include <net/net_namespace.h>
 
 static inline int
-tcf_change_indev(struct tcf_proto *tp, char *indev, struct nlattr *indev_tlv)
+tcf_change_indev(struct net *net, struct nlattr *indev_tlv)
 {
+       char indev[IFNAMSIZ];
+       struct net_device *dev;
+
        if (nla_strlcpy(indev, indev_tlv, IFNAMSIZ) >= IFNAMSIZ)
                return -EINVAL;
-       return 0;
+       dev = __dev_get_by_name(net, indev);
+       if (!dev)
+               return -ENODEV;
+       return dev->ifindex;
 }
 
-static inline int
-tcf_match_indev(struct sk_buff *skb, char *indev)
+static inline bool
+tcf_match_indev(struct sk_buff *skb, int ifindex)
 {
-       struct net_device *dev;
-
-       if (indev[0]) {
-               if  (!skb->skb_iif)
-                       return 0;
-               dev = __dev_get_by_index(dev_net(skb->dev), skb->skb_iif);
-               if (!dev || strcmp(indev, dev->name))
-                       return 0;
-       }
-
-       return 1;
+       if (!ifindex)
+               return true;
+       if  (!skb->skb_iif)
+               return false;
+       return ifindex == skb->skb_iif;
 }
 #endif /* CONFIG_NET_CLS_IND */
 
index fbf7676..0e5f866 100644 (file)
@@ -43,7 +43,12 @@ struct net_protocol {
        int                     (*handler)(struct sk_buff *skb);
        void                    (*err_handler)(struct sk_buff *skb, u32 info);
        unsigned int            no_policy:1,
-                               netns_ok:1;
+                               netns_ok:1,
+                               /* does the protocol do more stringent
+                                * icmp tag validation than simple
+                                * socket lookup?
+                                */
+                               icmp_strict_tag_validation:1;
 };
 
 #if IS_ENABLED(CONFIG_IPV6)
index ef46058..168bb2f 100644 (file)
@@ -303,7 +303,7 @@ static inline unsigned long red_calc_qavg(const struct red_parms *p,
 
 static inline u32 red_random(const struct red_parms *p)
 {
-       return reciprocal_divide(net_random(), p->max_P_reciprocal);
+       return reciprocal_divide(prandom_u32(), p->max_P_reciprocal);
 }
 
 static inline int red_mark_probability(const struct red_parms *p,
index 638e3eb..9d1f423 100644 (file)
@@ -36,6 +36,9 @@
 #include <linux/cache.h>
 #include <linux/security.h>
 
+/* IPv4 datagram length is stored into 16bit field (tot_len) */
+#define IP_MAX_MTU     0xFFFFU
+
 #define RTO_ONLINK     0x01
 
 #define RT_CONN_FLAGS(sk)   (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE))
@@ -311,20 +314,4 @@ static inline int ip4_dst_hoplimit(const struct dst_entry *dst)
        return hoplimit;
 }
 
-static inline bool ip_sk_accept_pmtu(const struct sock *sk)
-{
-       return inet_sk(sk)->pmtudisc != IP_PMTUDISC_INTERFACE;
-}
-
-static inline bool ip_sk_use_pmtu(const struct sock *sk)
-{
-       return inet_sk(sk)->pmtudisc < IP_PMTUDISC_PROBE;
-}
-
-static inline int ip_skb_dst_mtu(const struct sk_buff *skb)
-{
-       return (!skb->sk || ip_sk_use_pmtu(skb->sk)) ?
-              dst_mtu(skb_dst(skb)) : skb_dst(skb)->dev->mtu;
-}
-
 #endif /* _ROUTE_H */
index 013d96d..d062f81 100644 (file)
@@ -204,7 +204,7 @@ struct tcf_proto_ops {
        void                    (*walk)(struct tcf_proto*, struct tcf_walker *arg);
 
        /* rtnetlink specific */
-       int                     (*dump)(struct tcf_proto*, unsigned long,
+       int                     (*dump)(struct net*, struct tcf_proto*, unsigned long,
                                        struct sk_buff *skb, struct tcmsg*);
 
        struct module           *owner;
index e9f732f..d992ca3 100644 (file)
@@ -649,7 +649,6 @@ int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
                          struct iovec *data);
 void sctp_chunk_free(struct sctp_chunk *);
 void  *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
-void  *sctp_addto_chunk_fixed(struct sctp_chunk *, int len, const void *data);
 struct sctp_chunk *sctp_chunkify(struct sk_buff *,
                                 const struct sctp_association *,
                                 struct sock *);
index b7635ef..cd7c46f 100644 (file)
@@ -1421,6 +1421,8 @@ struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark,
                                       xfrm_address_t *saddr,
                                       unsigned short family,
                                       u8 mode, u8 proto, u32 reqid);
+struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
+                                             unsigned short family);
 int xfrm_state_check_expire(struct xfrm_state *x);
 void xfrm_state_insert(struct xfrm_state *x);
 int xfrm_state_add(struct xfrm_state *x);
index f99645d..a34f27b 100644 (file)
@@ -6,9 +6,67 @@
 
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <linux/if_vlan.h>
 #include <linux/ip.h>
 #include <linux/tracepoint.h>
 
+TRACE_EVENT(net_dev_start_xmit,
+
+       TP_PROTO(const struct sk_buff *skb, const struct net_device *dev),
+
+       TP_ARGS(skb, dev),
+
+       TP_STRUCT__entry(
+               __string(       name,                   dev->name       )
+               __field(        u16,                    queue_mapping   )
+               __field(        const void *,           skbaddr         )
+               __field(        bool,                   vlan_tagged     )
+               __field(        u16,                    vlan_proto      )
+               __field(        u16,                    vlan_tci        )
+               __field(        u16,                    protocol        )
+               __field(        u8,                     ip_summed       )
+               __field(        unsigned int,           len             )
+               __field(        unsigned int,           data_len        )
+               __field(        int,                    network_offset  )
+               __field(        bool,                   transport_offset_valid)
+               __field(        int,                    transport_offset)
+               __field(        u8,                     tx_flags        )
+               __field(        u16,                    gso_size        )
+               __field(        u16,                    gso_segs        )
+               __field(        u16,                    gso_type        )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, dev->name);
+               __entry->queue_mapping = skb->queue_mapping;
+               __entry->skbaddr = skb;
+               __entry->vlan_tagged = vlan_tx_tag_present(skb);
+               __entry->vlan_proto = ntohs(skb->vlan_proto);
+               __entry->vlan_tci = vlan_tx_tag_get(skb);
+               __entry->protocol = ntohs(skb->protocol);
+               __entry->ip_summed = skb->ip_summed;
+               __entry->len = skb->len;
+               __entry->data_len = skb->data_len;
+               __entry->network_offset = skb_network_offset(skb);
+               __entry->transport_offset_valid =
+                       skb_transport_header_was_set(skb);
+               __entry->transport_offset = skb_transport_offset(skb);
+               __entry->tx_flags = skb_shinfo(skb)->tx_flags;
+               __entry->gso_size = skb_shinfo(skb)->gso_size;
+               __entry->gso_segs = skb_shinfo(skb)->gso_segs;
+               __entry->gso_type = skb_shinfo(skb)->gso_type;
+       ),
+
+       TP_printk("dev=%s queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d len=%u data_len=%u network_offset=%d transport_offset_valid=%d transport_offset=%d tx_flags=%d gso_size=%d gso_segs=%d gso_type=%#x",
+                 __get_str(name), __entry->queue_mapping, __entry->skbaddr,
+                 __entry->vlan_tagged, __entry->vlan_proto, __entry->vlan_tci,
+                 __entry->protocol, __entry->ip_summed, __entry->len,
+                 __entry->data_len,
+                 __entry->network_offset, __entry->transport_offset_valid,
+                 __entry->transport_offset, __entry->tx_flags,
+                 __entry->gso_size, __entry->gso_segs, __entry->gso_type)
+);
+
 TRACE_EVENT(net_dev_xmit,
 
        TP_PROTO(struct sk_buff *skb,
@@ -78,6 +136,106 @@ DEFINE_EVENT(net_dev_template, netif_rx,
 
        TP_ARGS(skb)
 );
+
+DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,
+
+       TP_PROTO(const struct sk_buff *skb),
+
+       TP_ARGS(skb),
+
+       TP_STRUCT__entry(
+               __string(       name,                   skb->dev->name  )
+               __field(        unsigned int,           napi_id         )
+               __field(        u16,                    queue_mapping   )
+               __field(        const void *,           skbaddr         )
+               __field(        bool,                   vlan_tagged     )
+               __field(        u16,                    vlan_proto      )
+               __field(        u16,                    vlan_tci        )
+               __field(        u16,                    protocol        )
+               __field(        u8,                     ip_summed       )
+               __field(        u32,                    rxhash          )
+               __field(        bool,                   l4_rxhash       )
+               __field(        unsigned int,           len             )
+               __field(        unsigned int,           data_len        )
+               __field(        unsigned int,           truesize        )
+               __field(        bool,                   mac_header_valid)
+               __field(        int,                    mac_header      )
+               __field(        unsigned char,          nr_frags        )
+               __field(        u16,                    gso_size        )
+               __field(        u16,                    gso_type        )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, skb->dev->name);
+#ifdef CONFIG_NET_RX_BUSY_POLL
+               __entry->napi_id = skb->napi_id;
+#else
+               __entry->napi_id = 0;
+#endif
+               __entry->queue_mapping = skb->queue_mapping;
+               __entry->skbaddr = skb;
+               __entry->vlan_tagged = vlan_tx_tag_present(skb);
+               __entry->vlan_proto = ntohs(skb->vlan_proto);
+               __entry->vlan_tci = vlan_tx_tag_get(skb);
+               __entry->protocol = ntohs(skb->protocol);
+               __entry->ip_summed = skb->ip_summed;
+               __entry->rxhash = skb->rxhash;
+               __entry->l4_rxhash = skb->l4_rxhash;
+               __entry->len = skb->len;
+               __entry->data_len = skb->data_len;
+               __entry->truesize = skb->truesize;
+               __entry->mac_header_valid = skb_mac_header_was_set(skb);
+               __entry->mac_header = skb_mac_header(skb) - skb->data;
+               __entry->nr_frags = skb_shinfo(skb)->nr_frags;
+               __entry->gso_size = skb_shinfo(skb)->gso_size;
+               __entry->gso_type = skb_shinfo(skb)->gso_type;
+       ),
+
+       TP_printk("dev=%s napi_id=%#x queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d rxhash=0x%08x l4_rxhash=%d len=%u data_len=%u truesize=%u mac_header_valid=%d mac_header=%d nr_frags=%d gso_size=%d gso_type=%#x",
+                 __get_str(name), __entry->napi_id, __entry->queue_mapping,
+                 __entry->skbaddr, __entry->vlan_tagged, __entry->vlan_proto,
+                 __entry->vlan_tci, __entry->protocol, __entry->ip_summed,
+                 __entry->rxhash, __entry->l4_rxhash, __entry->len,
+                 __entry->data_len, __entry->truesize,
+                 __entry->mac_header_valid, __entry->mac_header,
+                 __entry->nr_frags, __entry->gso_size, __entry->gso_type)
+);
+
+DEFINE_EVENT(net_dev_rx_verbose_template, napi_gro_frags_entry,
+
+       TP_PROTO(const struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
+DEFINE_EVENT(net_dev_rx_verbose_template, napi_gro_receive_entry,
+
+       TP_PROTO(const struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
+DEFINE_EVENT(net_dev_rx_verbose_template, netif_receive_skb_entry,
+
+       TP_PROTO(const struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
+DEFINE_EVENT(net_dev_rx_verbose_template, netif_rx_entry,
+
+       TP_PROTO(const struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
+DEFINE_EVENT(net_dev_rx_verbose_template, netif_rx_ni_entry,
+
+       TP_PROTO(const struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
 #endif /* _TRACE_NET_H */
 
 /* This part must be outside protection */
index 2f3f7ea..fe421e8 100644 (file)
@@ -983,6 +983,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_SI_CP_DMA_COMPUTE  0x17
 /* CIK macrotile mode array */
 #define RADEON_INFO_CIK_MACROTILE_MODE_ARRAY   0x18
+/* query the number of render backends */
+#define RADEON_INFO_SI_BACKEND_ENABLED_MASK    0x19
 
 
 struct drm_radeon_info {
index cfed10b..dea10a8 100644 (file)
@@ -49,6 +49,7 @@ enum {
 #define IFA_F_TENTATIVE                0x40
 #define IFA_F_PERMANENT                0x80
 #define IFA_F_MANAGETEMPADDR   0x100
+#define IFA_F_NOPREFIXROUTE    0x200
 
 struct ifa_cacheinfo {
        __u32   ifa_prefered;
index d7fea34..4d024d7 100644 (file)
@@ -94,6 +94,7 @@
 #define ARPHRD_CAIF    822             /* CAIF media type              */
 #define ARPHRD_IP6GRE  823             /* GRE over IPv6                */
 #define ARPHRD_NETLINK 824             /* Netlink header               */
+#define ARPHRD_6LOWPAN 825             /* IPv6 over LoWPAN             */
 
 #define ARPHRD_VOID      0xFFFF        /* Void type, nothing is known */
 #define ARPHRD_NONE      0xFFFE        /* zero header length */
index ecc8859..bd24470 100644 (file)
@@ -464,7 +464,8 @@ struct input_keymap_entry {
 #define KEY_BRIGHTNESS_ZERO    244     /* brightness off, use ambient */
 #define KEY_DISPLAY_OFF                245     /* display device to off state */
 
-#define KEY_WIMAX              246
+#define KEY_WWAN               246     /* Wireless WAN (LTE, UMTS, GSM, etc.) */
+#define KEY_WIMAX              KEY_WWAN
 #define KEY_RFKILL             247     /* Key that controls all radios */
 
 #define KEY_MICMUTE            248     /* Mute / unmute the microphone */
index 2344f5a..1d973d2 100644 (file)
@@ -58,6 +58,7 @@ header-y += xt_helper.h
 header-y += xt_ipcomp.h
 header-y += xt_iprange.h
 header-y += xt_ipvs.h
+header-y += xt_l2tp.h
 header-y += xt_length.h
 header-y += xt_limit.h
 header-y += xt_mac.h
diff --git a/include/uapi/linux/netfilter/xt_l2tp.h b/include/uapi/linux/netfilter/xt_l2tp.h
new file mode 100644 (file)
index 0000000..7dccfa0
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _LINUX_NETFILTER_XT_L2TP_H
+#define _LINUX_NETFILTER_XT_L2TP_H
+
+#include <linux/types.h>
+
+enum xt_l2tp_type {
+       XT_L2TP_TYPE_CONTROL,
+       XT_L2TP_TYPE_DATA,
+};
+
+/* L2TP matching stuff */
+struct xt_l2tp_info {
+       __u32 tid;                      /* tunnel id */
+       __u32 sid;                      /* session id */
+       __u8 version;                   /* L2TP protocol version */
+       __u8 type;                      /* L2TP packet type */
+       __u8 flags;                     /* which fields to match */
+};
+
+enum {
+       XT_L2TP_TID     = (1 << 0),     /* match L2TP tunnel id */
+       XT_L2TP_SID     = (1 << 1),     /* match L2TP session id */
+       XT_L2TP_VERSION = (1 << 2),     /* match L2TP protocol version */
+       XT_L2TP_TYPE    = (1 << 3),     /* match L2TP packet type */
+};
+
+#endif /* _LINUX_NETFILTER_XT_L2TP_H */
index e130790..91054fd 100644 (file)
  *     (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
  *     This may also be sent as an event with the same attributes.
  *
+ * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
+ *     The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
+ *     that attribute is not included, QoS mapping is disabled. Since this
+ *     QoS mapping is relevant for IP packets, it is only valid during an
+ *     association. This is cleared on disassociation and AP restart.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -871,6 +877,8 @@ enum nl80211_commands {
 
        NL80211_CMD_VENDOR,
 
+       NL80211_CMD_SET_QOS_MAP,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1540,6 +1548,12 @@ enum nl80211_commands {
  * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
  * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
  *     attribute is also used for vendor command feature advertisement
+ * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
+ *     info, containing a nested array of possible events
+ *
+ * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
+ *     data is in the format defined for the payload of the QoS Map Set element
+ *     in IEEE Std 802.11-2012, 8.4.2.97.
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1865,6 +1879,9 @@ enum nl80211_attrs {
        NL80211_ATTR_VENDOR_ID,
        NL80211_ATTR_VENDOR_SUBCMD,
        NL80211_ATTR_VENDOR_DATA,
+       NL80211_ATTR_VENDOR_EVENTS,
+
+       NL80211_ATTR_QOS_MAP,
 
        /* add attributes here, update the policy in nl80211.c */
 
index cb5157b..54a37b1 100644 (file)
@@ -35,6 +35,8 @@ enum {
        TCP_METRICS_ATTR_FOPEN_SYN_DROPS,       /* u16, count of drops */
        TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS,     /* msecs age */
        TCP_METRICS_ATTR_FOPEN_COOKIE,          /* binary */
+       TCP_METRICS_ATTR_SADDR_IPV4,            /* u32 */
+       TCP_METRICS_ATTR_SADDR_IPV6,            /* binary */
 
        __TCP_METRICS_ATTR_MAX,
 };
index 5bff081..bbc4d66 100644 (file)
@@ -208,9 +208,10 @@ get_write_lock:
                if (mapping_cap_account_dirty(mapping)) {
                        unsigned long addr;
                        struct file *file = get_file(vma->vm_file);
+                       /* mmap_region may free vma; grab the info now */
+                       vm_flags = vma->vm_flags;
 
-                       addr = mmap_region(file, start, size,
-                                       vma->vm_flags, pgoff);
+                       addr = mmap_region(file, start, size, vm_flags, pgoff);
                        fput(file);
                        if (IS_ERR_VALUE(addr)) {
                                err = addr;
@@ -218,7 +219,7 @@ get_write_lock:
                                BUG_ON(addr != start);
                                err = 0;
                        }
-                       goto out;
+                       goto out_freed;
                }
                mutex_lock(&mapping->i_mmap_mutex);
                flush_dcache_mmap_lock(mapping);
@@ -253,6 +254,7 @@ get_write_lock:
 out:
        if (vma)
                vm_flags = vma->vm_flags;
+out_freed:
        if (likely(!has_write_lock))
                up_read(&mm->mmap_sem);
        else
index 7de1bf8..9c0b172 100644 (file)
@@ -883,9 +883,6 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                goto out_unlock;
        }
 
-       /* mmap_sem prevents this happening but warn if that changes */
-       WARN_ON(pmd_trans_migrating(pmd));
-
        if (unlikely(pmd_trans_splitting(pmd))) {
                /* split huge page running from under us */
                spin_unlock(src_ptl);
index bf5e894..7f1a356 100644 (file)
@@ -338,7 +338,7 @@ struct mem_cgroup {
 static size_t memcg_size(void)
 {
        return sizeof(struct mem_cgroup) +
-               nr_node_ids * sizeof(struct mem_cgroup_per_node);
+               nr_node_ids * sizeof(struct mem_cgroup_per_node *);
 }
 
 /* internal only representation about the status of kmem accounting. */
index db08af9..fabe550 100644 (file)
@@ -938,6 +938,16 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
                                BUG_ON(!PageHWPoison(p));
                                return SWAP_FAIL;
                        }
+                       /*
+                        * We pinned the head page for hwpoison handling,
+                        * now we split the thp and we are interested in
+                        * the hwpoisoned raw page, so move the refcount
+                        * to it.
+                        */
+                       if (hpage != p) {
+                               put_page(hpage);
+                               get_page(p);
+                       }
                        /* THP is split, so ppage should be the real poisoned page. */
                        ppage = p;
                }
index d480cd6..192e6ee 100644 (file)
@@ -133,7 +133,10 @@ static void __munlock_isolation_failed(struct page *page)
 
 /**
  * munlock_vma_page - munlock a vma page
- * @page - page to be unlocked
+ * @page - page to be unlocked, either a normal page or THP page head
+ *
+ * returns the size of the page as a page mask (0 for normal page,
+ *         HPAGE_PMD_NR - 1 for THP head page)
  *
  * called from munlock()/munmap() path with page supposedly on the LRU.
  * When we munlock a page, because the vma where we found the page is being
@@ -148,21 +151,30 @@ static void __munlock_isolation_failed(struct page *page)
  */
 unsigned int munlock_vma_page(struct page *page)
 {
-       unsigned int page_mask = 0;
+       unsigned int nr_pages;
 
        BUG_ON(!PageLocked(page));
 
        if (TestClearPageMlocked(page)) {
-               unsigned int nr_pages = hpage_nr_pages(page);
+               nr_pages = hpage_nr_pages(page);
                mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages);
-               page_mask = nr_pages - 1;
                if (!isolate_lru_page(page))
                        __munlock_isolated_page(page);
                else
                        __munlock_isolation_failed(page);
+       } else {
+               nr_pages = hpage_nr_pages(page);
        }
 
-       return page_mask;
+       /*
+        * Regardless of the original PageMlocked flag, we determine nr_pages
+        * after touching the flag. This leaves a possible race with a THP page
+        * split, such that a whole THP page was munlocked, but nr_pages == 1.
+        * Returning a smaller mask due to that is OK, the worst that can
+        * happen is subsequent useless scanning of the former tail pages.
+        * The NR_MLOCK accounting can however become broken.
+        */
+       return nr_pages - 1;
 }
 
 /**
@@ -286,10 +298,12 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
 {
        int i;
        int nr = pagevec_count(pvec);
-       int delta_munlocked = -nr;
+       int delta_munlocked;
        struct pagevec pvec_putback;
        int pgrescued = 0;
 
+       pagevec_init(&pvec_putback, 0);
+
        /* Phase 1: page isolation */
        spin_lock_irq(&zone->lru_lock);
        for (i = 0; i < nr; i++) {
@@ -318,18 +332,21 @@ skip_munlock:
                        /*
                         * We won't be munlocking this page in the next phase
                         * but we still need to release the follow_page_mask()
-                        * pin.
+                        * pin. We cannot do it under lru_lock however. If it's
+                        * the last pin, __page_cache_release would deadlock.
                         */
+                       pagevec_add(&pvec_putback, pvec->pages[i]);
                        pvec->pages[i] = NULL;
-                       put_page(page);
-                       delta_munlocked++;
                }
        }
+       delta_munlocked = -nr + pagevec_count(&pvec_putback);
        __mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
        spin_unlock_irq(&zone->lru_lock);
 
+       /* Now we can release pins of pages that we are not munlocking */
+       pagevec_release(&pvec_putback);
+
        /* Phase 2: page munlock */
-       pagevec_init(&pvec_putback, 0);
        for (i = 0; i < nr; i++) {
                struct page *page = pvec->pages[i];
 
@@ -440,7 +457,8 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
 
        while (start < end) {
                struct page *page = NULL;
-               unsigned int page_mask, page_increm;
+               unsigned int page_mask;
+               unsigned long page_increm;
                struct pagevec pvec;
                struct zone *zone;
                int zoneid;
@@ -490,7 +508,9 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
                                goto next;
                        }
                }
-               page_increm = 1 + (~(start >> PAGE_SHIFT) & page_mask);
+               /* It's a bug to munlock in the middle of a THP page */
+               VM_BUG_ON((start >> PAGE_SHIFT) & page_mask);
+               page_increm = 1 + page_mask;
                start += page_increm * PAGE_SIZE;
 next:
                cond_resched();
index 5d9630a..b38ee6d 100644 (file)
@@ -397,7 +397,7 @@ static void garp_join_timer_arm(struct garp_applicant *app)
 {
        unsigned long delay;
 
-       delay = (u64)msecs_to_jiffies(garp_join_time) * net_random() >> 32;
+       delay = (u64)msecs_to_jiffies(garp_join_time) * prandom_u32() >> 32;
        mod_timer(&app->join_timer, jiffies + delay);
 }
 
index a97a3bd..5ff2a71 100644 (file)
@@ -172,14 +172,14 @@ EXPORT_SYMBOL(hippi_mac_addr);
 int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
 {
        /* Never send broadcast/multicast ARP messages */
-       NEIGH_VAR_SET(p, MCAST_PROBES, 0);
+       NEIGH_VAR_INIT(p, MCAST_PROBES, 0);
 
        /* In IPv6 unicast probes are valid even on NBMA,
        * because they are encapsulated in normal IPv6 protocol.
        * Should be a generic flag.
        */
        if (p->tbl->family != AF_INET6)
-               NEIGH_VAR_SET(p, UCAST_PROBES, 0);
+               NEIGH_VAR_INIT(p, UCAST_PROBES, 0);
        return 0;
 }
 EXPORT_SYMBOL(hippi_neigh_setup_dev);
index 3ed6162..72db278 100644 (file)
@@ -583,7 +583,7 @@ static void mrp_join_timer_arm(struct mrp_applicant *app)
 {
        unsigned long delay;
 
-       delay = (u64)msecs_to_jiffies(mrp_join_time) * net_random() >> 32;
+       delay = (u64)msecs_to_jiffies(mrp_join_time) * prandom_u32() >> 32;
        mod_timer(&app->join_timer, jiffies + delay);
 }
 
index 8fa2f91..cbbbe6d 100644 (file)
@@ -57,7 +57,7 @@ obj-$(CONFIG_CAIF)            += caif/
 ifneq ($(CONFIG_DCB),)
 obj-y                          += dcb/
 endif
-obj-$(CONFIG_IEEE802154)       += ieee802154/
+obj-y                          += ieee802154/
 obj-$(CONFIG_MAC802154)                += mac802154/
 
 ifeq ($(CONFIG_NET),y)
index 4f4aabb..42df18f 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+# Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
 #
 # Marek Lindner, Simon Wunderlich
 #
@@ -13,9 +13,7 @@
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 
 obj-$(CONFIG_BATMAN_ADV) += batman-adv.o
index a4808c2..4e49666 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_BAT_ALGO_H_
index b9c8a6e..921ac20 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -274,7 +272,14 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
        if (!neigh_node)
                goto out;
 
-       spin_lock_init(&neigh_node->bat_iv.lq_update_lock);
+       if (!atomic_inc_not_zero(&hard_iface->refcount)) {
+               kfree(neigh_node);
+               neigh_node = NULL;
+               goto out;
+       }
+
+       neigh_node->orig_node = orig_neigh;
+       neigh_node->if_incoming = hard_iface;
 
        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                   "Creating new neighbor %pM for orig_node %pM on interface %s\n",
@@ -461,17 +466,9 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
 /* send a batman ogm packet */
 static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
 {
-       struct batadv_hard_iface *hard_iface;
        struct net_device *soft_iface;
        struct batadv_priv *bat_priv;
        struct batadv_hard_iface *primary_if = NULL;
-       struct batadv_ogm_packet *batadv_ogm_packet;
-       unsigned char directlink;
-       uint8_t *packet_pos;
-
-       packet_pos = forw_packet->skb->data;
-       batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
-       directlink = (batadv_ogm_packet->flags & BATADV_DIRECTLINK ? 1 : 0);
 
        if (!forw_packet->if_incoming) {
                pr_err("Error - can't forward packet: incoming iface not specified\n");
@@ -481,59 +478,48 @@ static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
        soft_iface = forw_packet->if_incoming->soft_iface;
        bat_priv = netdev_priv(soft_iface);
 
-       if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
+       if (WARN_ON(!forw_packet->if_outgoing))
                goto out;
 
-       primary_if = batadv_primary_if_get_selected(bat_priv);
-       if (!primary_if)
+       if (WARN_ON(forw_packet->if_outgoing->soft_iface != soft_iface))
                goto out;
 
-       /* multihomed peer assumed
-        * non-primary OGMs are only broadcasted on their interface
-        */
-       if ((directlink && (batadv_ogm_packet->ttl == 1)) ||
-           (forw_packet->own && (forw_packet->if_incoming != primary_if))) {
-               /* FIXME: what about aggregated packets ? */
-               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                          "%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
-                          (forw_packet->own ? "Sending own" : "Forwarding"),
-                          batadv_ogm_packet->orig,
-                          ntohl(batadv_ogm_packet->seqno),
-                          batadv_ogm_packet->ttl,
-                          forw_packet->if_incoming->net_dev->name,
-                          forw_packet->if_incoming->net_dev->dev_addr);
-
-               /* skb is only used once and than forw_packet is free'd */
-               batadv_send_skb_packet(forw_packet->skb,
-                                      forw_packet->if_incoming,
-                                      batadv_broadcast_addr);
-               forw_packet->skb = NULL;
-
+       if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
                goto out;
-       }
 
-       /* broadcast on every interface */
-       rcu_read_lock();
-       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
-               if (hard_iface->soft_iface != soft_iface)
-                       continue;
+       primary_if = batadv_primary_if_get_selected(bat_priv);
+       if (!primary_if)
+               goto out;
 
-               batadv_iv_ogm_send_to_if(forw_packet, hard_iface);
-       }
-       rcu_read_unlock();
+       /* only for one specific outgoing interface */
+       batadv_iv_ogm_send_to_if(forw_packet, forw_packet->if_outgoing);
 
 out:
        if (primary_if)
                batadv_hardif_free_ref(primary_if);
 }
 
-/* return true if new_packet can be aggregated with forw_packet */
+/**
+ * batadv_iv_ogm_can_aggregate - find out if an OGM can be aggregated on an
+ *  existing forward packet
+ * @new_bat_ogm_packet: OGM packet to be aggregated
+ * @bat_priv: the bat priv with all the soft interface information
+ * @packet_len: (total) length of the OGM
+ * @send_time: timestamp (jiffies) when the packet is to be sent
+ * @direktlink: true if this is a direct link packet
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @forw_packet: the forwarded packet which should be checked
+ *
+ * Returns true if new_packet can be aggregated with forw_packet
+ */
 static bool
 batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
                            struct batadv_priv *bat_priv,
                            int packet_len, unsigned long send_time,
                            bool directlink,
                            const struct batadv_hard_iface *if_incoming,
+                           const struct batadv_hard_iface *if_outgoing,
                            const struct batadv_forw_packet *forw_packet)
 {
        struct batadv_ogm_packet *batadv_ogm_packet;
@@ -567,6 +553,10 @@ batadv_iv_ogm_can_aggregate(const struct batadv_ogm_packet *new_bat_ogm_packet,
                if (!primary_if)
                        goto out;
 
+               /* packet is not leaving on the same interface. */
+               if (forw_packet->if_outgoing != if_outgoing)
+                       goto out;
+
                /* packets without direct link flag and high TTL
                 * are flooded through the net
                 */
@@ -608,11 +598,21 @@ out:
        return res;
 }
 
-/* create a new aggregated packet and add this packet to it */
+/* batadv_iv_ogm_aggregate_new - create a new aggregated packet and add this
+ *  packet to it.
+ * @packet_buff: pointer to the OGM
+ * @packet_len: (total) length of the OGM
+ * @send_time: timestamp (jiffies) when the packet is to be sent
+ * @direct_link: whether this OGM has direct link status
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @own_packet: true if it is a self-generated ogm
+ */
 static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
                                        int packet_len, unsigned long send_time,
                                        bool direct_link,
                                        struct batadv_hard_iface *if_incoming,
+                                       struct batadv_hard_iface *if_outgoing,
                                        int own_packet)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
@@ -623,6 +623,9 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
        if (!atomic_inc_not_zero(&if_incoming->refcount))
                return;
 
+       if (!atomic_inc_not_zero(&if_outgoing->refcount))
+               goto out_free_incoming;
+
        /* own packet should always be scheduled */
        if (!own_packet) {
                if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
@@ -663,6 +666,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 
        forw_packet_aggr->own = own_packet;
        forw_packet_aggr->if_incoming = if_incoming;
+       forw_packet_aggr->if_outgoing = if_outgoing;
        forw_packet_aggr->num_packets = 0;
        forw_packet_aggr->direct_link_flags = BATADV_NO_FLAGS;
        forw_packet_aggr->send_time = send_time;
@@ -685,6 +689,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
 
        return;
 out:
+       batadv_hardif_free_ref(if_outgoing);
+out_free_incoming:
        batadv_hardif_free_ref(if_incoming);
 }
 
@@ -708,10 +714,21 @@ static void batadv_iv_ogm_aggregate(struct batadv_forw_packet *forw_packet_aggr,
        }
 }
 
+/**
+ * batadv_iv_ogm_queue_add - queue up an OGM for transmission
+ * @bat_priv: the bat priv with all the soft interface information
+ * @packet_buff: pointer to the OGM
+ * @packet_len: (total) length of the OGM
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @own_packet: true if it is a self-generated ogm
+ * @send_time: timestamp (jiffies) when the packet is to be sent
+ */
 static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
                                    unsigned char *packet_buff,
                                    int packet_len,
                                    struct batadv_hard_iface *if_incoming,
+                                   struct batadv_hard_iface *if_outgoing,
                                    int own_packet, unsigned long send_time)
 {
        /* _aggr -> pointer to the packet we want to aggregate with
@@ -737,6 +754,7 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
                                                        bat_priv, packet_len,
                                                        send_time, direct_link,
                                                        if_incoming,
+                                                       if_outgoing,
                                                        forw_packet_pos)) {
                                forw_packet_aggr = forw_packet_pos;
                                break;
@@ -760,7 +778,8 @@ static void batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv,
 
                batadv_iv_ogm_aggregate_new(packet_buff, packet_len,
                                            send_time, direct_link,
-                                           if_incoming, own_packet);
+                                           if_incoming, if_outgoing,
+                                           own_packet);
        } else {
                batadv_iv_ogm_aggregate(forw_packet_aggr, packet_buff,
                                        packet_len, direct_link);
@@ -773,7 +792,8 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
                                  struct batadv_ogm_packet *batadv_ogm_packet,
                                  bool is_single_hop_neigh,
                                  bool is_from_best_next_hop,
-                                 struct batadv_hard_iface *if_incoming)
+                                 struct batadv_hard_iface *if_incoming,
+                                 struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        uint16_t tvlv_len;
@@ -818,7 +838,8 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
 
        batadv_iv_ogm_queue_add(bat_priv, (unsigned char *)batadv_ogm_packet,
                                BATADV_OGM_HLEN + tvlv_len,
-                               if_incoming, 0, batadv_iv_ogm_fwd_send_time());
+                               if_incoming, if_outgoing, 0,
+                               batadv_iv_ogm_fwd_send_time());
 }
 
 /**
@@ -863,10 +884,11 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
        unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
        struct batadv_ogm_packet *batadv_ogm_packet;
-       struct batadv_hard_iface *primary_if;
+       struct batadv_hard_iface *primary_if, *tmp_hard_iface;
        int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
        uint32_t seqno;
        uint16_t tvlv_len = 0;
+       unsigned long send_time;
 
        primary_if = batadv_primary_if_get_selected(bat_priv);
 
@@ -889,23 +911,60 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
        atomic_inc(&hard_iface->bat_iv.ogm_seqno);
 
        batadv_iv_ogm_slide_own_bcast_window(hard_iface);
-       batadv_iv_ogm_queue_add(bat_priv, hard_iface->bat_iv.ogm_buff,
-                               hard_iface->bat_iv.ogm_buff_len, hard_iface, 1,
-                               batadv_iv_ogm_emit_send_time(bat_priv));
 
+       send_time = batadv_iv_ogm_emit_send_time(bat_priv);
+
+       if (hard_iface != primary_if) {
+               /* OGMs from secondary interfaces are only scheduled on their
+                * respective interfaces.
+                */
+               batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len,
+                                       hard_iface, hard_iface, 1, send_time);
+               goto out;
+       }
+
+       /* OGMs from primary interfaces are scheduled on all
+        * interfaces.
+        */
+       rcu_read_lock();
+       list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) {
+               if (tmp_hard_iface->soft_iface != hard_iface->soft_iface)
+                               continue;
+               batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
+                                       *ogm_buff_len, hard_iface,
+                                       tmp_hard_iface, 1, send_time);
+       }
+       rcu_read_unlock();
+
+out:
        if (primary_if)
                batadv_hardif_free_ref(primary_if);
 }
 
+/**
+ * batadv_iv_ogm_orig_update - use OGM to update corresponding data in an
+ *  originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the orig node who originally emitted the ogm packet
+ * @orig_ifinfo: ifinfo for the outgoing interface of the orig_node
+ * @ethhdr: Ethernet header of the OGM
+ * @batadv_ogm_packet: the ogm packet
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ * @dup_status: the duplicate status of this ogm packet.
+ */
 static void
 batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                          struct batadv_orig_node *orig_node,
+                         struct batadv_orig_ifinfo *orig_ifinfo,
                          const struct ethhdr *ethhdr,
                          const struct batadv_ogm_packet *batadv_ogm_packet,
                          struct batadv_hard_iface *if_incoming,
-                         const unsigned char *tt_buff,
+                         struct batadv_hard_iface *if_outgoing,
                          enum batadv_dup_status dup_status)
 {
+       struct batadv_neigh_ifinfo *neigh_ifinfo = NULL;
+       struct batadv_neigh_ifinfo *router_ifinfo = NULL;
        struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
        struct batadv_neigh_node *router = NULL;
        struct batadv_orig_node *orig_node_tmp;
@@ -933,12 +992,21 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                if (dup_status != BATADV_NO_DUP)
                        continue;
 
-               spin_lock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
-               batadv_ring_buffer_set(tmp_neigh_node->bat_iv.tq_recv,
-                                      &tmp_neigh_node->bat_iv.tq_index, 0);
-               tq_avg = batadv_ring_buffer_avg(tmp_neigh_node->bat_iv.tq_recv);
-               tmp_neigh_node->bat_iv.tq_avg = tq_avg;
-               spin_unlock_bh(&tmp_neigh_node->bat_iv.lq_update_lock);
+               /* only update the entry for this outgoing interface */
+               neigh_ifinfo = batadv_neigh_ifinfo_get(tmp_neigh_node,
+                                                      if_outgoing);
+               if (!neigh_ifinfo)
+                       continue;
+
+               spin_lock_bh(&tmp_neigh_node->ifinfo_lock);
+               batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
+                                      &neigh_ifinfo->bat_iv.tq_index, 0);
+               tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
+               neigh_ifinfo->bat_iv.tq_avg = tq_avg;
+               spin_unlock_bh(&tmp_neigh_node->ifinfo_lock);
+
+               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+               neigh_ifinfo = NULL;
        }
 
        if (!neigh_node) {
@@ -960,39 +1028,49 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                           "Updating existing last-hop neighbor of originator\n");
 
        rcu_read_unlock();
+       neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
+       if (!neigh_ifinfo)
+               goto out;
 
        neigh_node->last_seen = jiffies;
 
-       spin_lock_bh(&neigh_node->bat_iv.lq_update_lock);
-       batadv_ring_buffer_set(neigh_node->bat_iv.tq_recv,
-                              &neigh_node->bat_iv.tq_index,
+       spin_lock_bh(&neigh_node->ifinfo_lock);
+       batadv_ring_buffer_set(neigh_ifinfo->bat_iv.tq_recv,
+                              &neigh_ifinfo->bat_iv.tq_index,
                               batadv_ogm_packet->tq);
-       tq_avg = batadv_ring_buffer_avg(neigh_node->bat_iv.tq_recv);
-       neigh_node->bat_iv.tq_avg = tq_avg;
-       spin_unlock_bh(&neigh_node->bat_iv.lq_update_lock);
+       tq_avg = batadv_ring_buffer_avg(neigh_ifinfo->bat_iv.tq_recv);
+       neigh_ifinfo->bat_iv.tq_avg = tq_avg;
+       spin_unlock_bh(&neigh_node->ifinfo_lock);
 
        if (dup_status == BATADV_NO_DUP) {
-               orig_node->last_ttl = batadv_ogm_packet->ttl;
-               neigh_node->last_ttl = batadv_ogm_packet->ttl;
+               orig_ifinfo->last_ttl = batadv_ogm_packet->ttl;
+               neigh_ifinfo->last_ttl = batadv_ogm_packet->ttl;
        }
 
-       batadv_bonding_candidate_add(bat_priv, orig_node, neigh_node);
-
        /* if this neighbor already is our next hop there is nothing
         * to change
         */
-       router = batadv_orig_node_get_router(orig_node);
+       router = batadv_orig_router_get(orig_node, if_outgoing);
        if (router == neigh_node)
                goto out;
 
-       /* if this neighbor does not offer a better TQ we won't consider it */
-       if (router && (router->bat_iv.tq_avg > neigh_node->bat_iv.tq_avg))
-               goto out;
+       if (router) {
+               router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
+               if (!router_ifinfo)
+                       goto out;
+
+               /* if this neighbor does not offer a better TQ we won't
+                * consider it
+                */
+               if (router_ifinfo->bat_iv.tq_avg > neigh_ifinfo->bat_iv.tq_avg)
+                       goto out;
+       }
 
        /* if the TQ is the same and the link not more symmetric we
         * won't consider it either
         */
-       if (router && (neigh_node->bat_iv.tq_avg == router->bat_iv.tq_avg)) {
+       if (router_ifinfo &&
+           (neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg)) {
                orig_node_tmp = router->orig_node;
                spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
                if_num = router->if_incoming->if_num;
@@ -1009,7 +1087,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
                        goto out;
        }
 
-       batadv_update_route(bat_priv, orig_node, neigh_node);
+       batadv_update_route(bat_priv, orig_node, if_outgoing, neigh_node);
        goto out;
 
 unlock:
@@ -1019,20 +1097,37 @@ out:
                batadv_neigh_node_free_ref(neigh_node);
        if (router)
                batadv_neigh_node_free_ref(router);
+       if (neigh_ifinfo)
+               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+       if (router_ifinfo)
+               batadv_neigh_ifinfo_free_ref(router_ifinfo);
 }
 
+/**
+ * batadv_iv_ogm_calc_tq - calculate tq for current received ogm packet
+ * @orig_node: the orig node who originally emitted the ogm packet
+ * @orig_neigh_node: the orig node struct of the neighbor who sent the packet
+ * @batadv_ogm_packet: the ogm packet
+ * @if_incoming: interface where the packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
+ *
+ * Returns 1 if the link can be considered bidirectional, 0 otherwise
+ */
 static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
                                 struct batadv_orig_node *orig_neigh_node,
                                 struct batadv_ogm_packet *batadv_ogm_packet,
-                                struct batadv_hard_iface *if_incoming)
+                                struct batadv_hard_iface *if_incoming,
+                                struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
+       struct batadv_neigh_ifinfo *neigh_ifinfo;
        uint8_t total_count;
        uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
        unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
        int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0;
        unsigned int combined_tq;
+       int tq_iface_penalty;
 
        /* find corresponding one hop neighbor */
        rcu_read_lock();
@@ -1072,7 +1167,13 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
        if_num = if_incoming->if_num;
        orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num];
-       neigh_rq_count = neigh_node->bat_iv.real_packet_count;
+       neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
+       if (neigh_ifinfo) {
+               neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
+               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
+       } else {
+               neigh_rq_count = 0;
+       }
        spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
 
        /* pay attention to not get a value bigger than 100 % */
@@ -1108,15 +1209,31 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        inv_asym_penalty /= neigh_rq_max_cube;
        tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty;
 
-       combined_tq = batadv_ogm_packet->tq * tq_own * tq_asym_penalty;
-       combined_tq /= BATADV_TQ_MAX_VALUE * BATADV_TQ_MAX_VALUE;
+       /* penalize if the OGM is forwarded on the same interface. WiFi
+        * interfaces and other half duplex devices suffer from throughput
+        * drops as they can't send and receive at the same time.
+        */
+       tq_iface_penalty = BATADV_TQ_MAX_VALUE;
+       if (if_outgoing && (if_incoming == if_outgoing) &&
+           batadv_is_wifi_netdev(if_outgoing->net_dev))
+               tq_iface_penalty = batadv_hop_penalty(BATADV_TQ_MAX_VALUE,
+                                                     bat_priv);
+
+       combined_tq = batadv_ogm_packet->tq *
+                     tq_own *
+                     tq_asym_penalty *
+                     tq_iface_penalty;
+       combined_tq /= BATADV_TQ_MAX_VALUE *
+                      BATADV_TQ_MAX_VALUE *
+                      BATADV_TQ_MAX_VALUE;
        batadv_ogm_packet->tq = combined_tq;
 
        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                  "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, total tq: %3i\n",
+                  "bidirectional: orig = %-15pM neigh = %-15pM => own_bcast = %2i, real recv = %2i, local tq: %3i, asym_penalty: %3i, iface_penalty: %3i, total tq: %3i, if_incoming = %s, if_outgoing = %s\n",
                   orig_node->orig, orig_neigh_node->orig, total_count,
-                  neigh_rq_count, tq_own,
-                  tq_asym_penalty, batadv_ogm_packet->tq);
+                  neigh_rq_count, tq_own, tq_asym_penalty, tq_iface_penalty,
+                  batadv_ogm_packet->tq, if_incoming->net_dev->name,
+                  if_outgoing ? if_outgoing->net_dev->name : "DEFAULT");
 
        /* if link has the minimum required transmission quality
         * consider it bidirectional
@@ -1136,17 +1253,21 @@ out:
  * @ethhdr: ethernet header of the packet
  * @batadv_ogm_packet: OGM packet to be considered
  * @if_incoming: interface on which the OGM packet was received
+ * @if_outgoing: interface for which the retransmission should be considered
  *
  * Returns duplicate status as enum batadv_dup_status
  */
 static enum batadv_dup_status
 batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
                            const struct batadv_ogm_packet *batadv_ogm_packet,
-                           const struct batadv_hard_iface *if_incoming)
+                           const struct batadv_hard_iface *if_incoming,
+                           struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        struct batadv_orig_node *orig_node;
-       struct batadv_neigh_node *tmp_neigh_node;
+       struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+       struct batadv_neigh_node *neigh_node;
+       struct batadv_neigh_ifinfo *neigh_ifinfo;
        int is_dup;
        int32_t seq_diff;
        int need_update = 0;
@@ -1161,27 +1282,37 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
        if (!orig_node)
                return BATADV_NO_DUP;
 
+       orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+       if (WARN_ON(!orig_ifinfo)) {
+               batadv_orig_node_free_ref(orig_node);
+               return 0;
+       }
+
        spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
-       seq_diff = seqno - orig_node->last_real_seqno;
+       seq_diff = seqno - orig_ifinfo->last_real_seqno;
 
        /* signalize caller that the packet is to be dropped. */
        if (!hlist_empty(&orig_node->neigh_list) &&
            batadv_window_protected(bat_priv, seq_diff,
-                                   &orig_node->batman_seqno_reset)) {
+                                   &orig_ifinfo->batman_seqno_reset)) {
                ret = BATADV_PROTECTED;
                goto out;
        }
 
        rcu_read_lock();
-       hlist_for_each_entry_rcu(tmp_neigh_node,
-                                &orig_node->neigh_list, list) {
-               neigh_addr = tmp_neigh_node->addr;
-               is_dup = batadv_test_bit(tmp_neigh_node->bat_iv.real_bits,
-                                        orig_node->last_real_seqno,
+       hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
+               neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node,
+                                                      if_outgoing);
+               if (!neigh_ifinfo)
+                       continue;
+
+               neigh_addr = neigh_node->addr;
+               is_dup = batadv_test_bit(neigh_ifinfo->bat_iv.real_bits,
+                                        orig_ifinfo->last_real_seqno,
                                         seqno);
 
                if (batadv_compare_eth(neigh_addr, ethhdr->h_source) &&
-                   tmp_neigh_node->if_incoming == if_incoming) {
+                   neigh_node->if_incoming == if_incoming) {
                        set_mark = 1;
                        if (is_dup)
                                ret = BATADV_NEIGH_DUP;
@@ -1192,173 +1323,78 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
                }
 
                /* if the window moved, set the update flag. */
-               bitmap = tmp_neigh_node->bat_iv.real_bits;
+               bitmap = neigh_ifinfo->bat_iv.real_bits;
                need_update |= batadv_bit_get_packet(bat_priv, bitmap,
                                                     seq_diff, set_mark);
 
-               packet_count = bitmap_weight(tmp_neigh_node->bat_iv.real_bits,
+               packet_count = bitmap_weight(bitmap,
                                             BATADV_TQ_LOCAL_WINDOW_SIZE);
-               tmp_neigh_node->bat_iv.real_packet_count = packet_count;
+               neigh_ifinfo->bat_iv.real_packet_count = packet_count;
+               batadv_neigh_ifinfo_free_ref(neigh_ifinfo);
        }
        rcu_read_unlock();
 
        if (need_update) {
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                          "updating last_seqno: old %u, new %u\n",
-                          orig_node->last_real_seqno, seqno);
-               orig_node->last_real_seqno = seqno;
+                          "%s updating last_seqno: old %u, new %u\n",
+                          if_outgoing ? if_outgoing->net_dev->name : "DEFAULT",
+                          orig_ifinfo->last_real_seqno, seqno);
+               orig_ifinfo->last_real_seqno = seqno;
        }
 
 out:
        spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
        batadv_orig_node_free_ref(orig_node);
+       if (orig_ifinfo)
+               batadv_orig_ifinfo_free_ref(orig_ifinfo);
        return ret;
 }
 
-static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
-                                 struct batadv_ogm_packet *batadv_ogm_packet,
-                                 const unsigned char *tt_buff,
-                                 struct batadv_hard_iface *if_incoming)
+
+/**
+ * batadv_iv_ogm_process_per_outif - process a batman iv OGM for an outgoing if
+ * @skb: the skb containing the OGM
+ * @orig_node: the (cached) orig node for the originator of this OGM
+ * @if_incoming: the interface where this packet was received
+ * @if_outgoing: the interface for which the packet should be considered
+ */
+static void
+batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
+                               struct batadv_orig_node *orig_node,
+                               struct batadv_hard_iface *if_incoming,
+                               struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
-       struct batadv_hard_iface *hard_iface;
-       struct batadv_orig_node *orig_neigh_node, *orig_node, *orig_node_tmp;
        struct batadv_neigh_node *router = NULL, *router_router = NULL;
+       struct batadv_orig_node *orig_neigh_node;
+       struct batadv_orig_ifinfo *orig_ifinfo;
        struct batadv_neigh_node *orig_neigh_router = NULL;
-       int has_directlink_flag;
-       int is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
-       int is_bidirect;
-       bool is_single_hop_neigh = false;
-       bool is_from_best_next_hop = false;
-       int sameseq, similar_ttl;
+       struct batadv_neigh_ifinfo *router_ifinfo = NULL;
+       struct batadv_ogm_packet *ogm_packet;
        enum batadv_dup_status dup_status;
-       uint32_t if_incoming_seqno;
+       bool is_from_best_next_hop = false;
+       bool is_single_hop_neigh = false;
+       bool sameseq, similar_ttl;
+       struct sk_buff *skb_priv;
+       struct ethhdr *ethhdr;
        uint8_t *prev_sender;
+       int is_bidirect;
 
-       /* Silently drop when the batman packet is actually not a
-        * correct packet.
-        *
-        * This might happen if a packet is padded (e.g. Ethernet has a
-        * minimum frame length of 64 byte) and the aggregation interprets
-        * it as an additional length.
-        *
-        * TODO: A more sane solution would be to have a bit in the
-        * batadv_ogm_packet to detect whether the packet is the last
-        * packet in an aggregation.  Here we expect that the padding
-        * is always zero (or not 0x01)
+       /* create a private copy of the skb, as some functions change tq value
+        * and/or flags.
         */
-       if (batadv_ogm_packet->packet_type != BATADV_IV_OGM)
+       skb_priv = skb_copy(skb, GFP_ATOMIC);
+       if (!skb_priv)
                return;
 
-       /* could be changed by schedule_own_packet() */
-       if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
-
-       if (batadv_ogm_packet->flags & BATADV_DIRECTLINK)
-               has_directlink_flag = 1;
-       else
-               has_directlink_flag = 0;
+       ethhdr = eth_hdr(skb_priv);
+       ogm_packet = (struct batadv_ogm_packet *)(skb_priv->data + ogm_offset);
 
-       if (batadv_compare_eth(ethhdr->h_source, batadv_ogm_packet->orig))
+       dup_status = batadv_iv_ogm_update_seqnos(ethhdr, ogm_packet,
+                                                if_incoming, if_outgoing);
+       if (batadv_compare_eth(ethhdr->h_source, ogm_packet->orig))
                is_single_hop_neigh = true;
 
-       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                  "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n",
-                  ethhdr->h_source, if_incoming->net_dev->name,
-                  if_incoming->net_dev->dev_addr, batadv_ogm_packet->orig,
-                  batadv_ogm_packet->prev_sender,
-                  ntohl(batadv_ogm_packet->seqno), batadv_ogm_packet->tq,
-                  batadv_ogm_packet->ttl,
-                  batadv_ogm_packet->version, has_directlink_flag);
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
-               if (hard_iface->if_status != BATADV_IF_ACTIVE)
-                       continue;
-
-               if (hard_iface->soft_iface != if_incoming->soft_iface)
-                       continue;
-
-               if (batadv_compare_eth(ethhdr->h_source,
-                                      hard_iface->net_dev->dev_addr))
-                       is_my_addr = 1;
-
-               if (batadv_compare_eth(batadv_ogm_packet->orig,
-                                      hard_iface->net_dev->dev_addr))
-                       is_my_orig = 1;
-
-               if (batadv_compare_eth(batadv_ogm_packet->prev_sender,
-                                      hard_iface->net_dev->dev_addr))
-                       is_my_oldorig = 1;
-       }
-       rcu_read_unlock();
-
-       if (is_my_addr) {
-               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                          "Drop packet: received my own broadcast (sender: %pM)\n",
-                          ethhdr->h_source);
-               return;
-       }
-
-       if (is_my_orig) {
-               unsigned long *word;
-               int offset;
-               int32_t bit_pos;
-               int16_t if_num;
-               uint8_t *weight;
-
-               orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
-                                                        ethhdr->h_source);
-               if (!orig_neigh_node)
-                       return;
-
-               /* neighbor has to indicate direct link and it has to
-                * come via the corresponding interface
-                * save packet seqno for bidirectional check
-                */
-               if (has_directlink_flag &&
-                   batadv_compare_eth(if_incoming->net_dev->dev_addr,
-                                      batadv_ogm_packet->orig)) {
-                       if_num = if_incoming->if_num;
-                       offset = if_num * BATADV_NUM_WORDS;
-
-                       spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
-                       word = &(orig_neigh_node->bat_iv.bcast_own[offset]);
-                       bit_pos = if_incoming_seqno - 2;
-                       bit_pos -= ntohl(batadv_ogm_packet->seqno);
-                       batadv_set_bit(word, bit_pos);
-                       weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num];
-                       *weight = bitmap_weight(word,
-                                               BATADV_TQ_LOCAL_WINDOW_SIZE);
-                       spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
-               }
-
-               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                          "Drop packet: originator packet from myself (via neighbor)\n");
-               batadv_orig_node_free_ref(orig_neigh_node);
-               return;
-       }
-
-       if (is_my_oldorig) {
-               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                          "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
-                          ethhdr->h_source);
-               return;
-       }
-
-       if (batadv_ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
-               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                          "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
-                          ethhdr->h_source);
-               return;
-       }
-
-       orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig);
-       if (!orig_node)
-               return;
-
-       dup_status = batadv_iv_ogm_update_seqnos(ethhdr, batadv_ogm_packet,
-                                                if_incoming);
-
        if (dup_status == BATADV_PROTECTED) {
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "Drop packet: packet within seqno protection time (sender: %pM)\n",
@@ -1366,27 +1402,28 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
                goto out;
        }
 
-       if (batadv_ogm_packet->tq == 0) {
+       if (ogm_packet->tq == 0) {
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "Drop packet: originator packet with tq equal 0\n");
                goto out;
        }
 
-       router = batadv_orig_node_get_router(orig_node);
+       router = batadv_orig_router_get(orig_node, if_outgoing);
        if (router) {
-               orig_node_tmp = router->orig_node;
-               router_router = batadv_orig_node_get_router(orig_node_tmp);
+               router_router = batadv_orig_router_get(router->orig_node,
+                                                      if_outgoing);
+               router_ifinfo = batadv_neigh_ifinfo_get(router, if_outgoing);
        }
 
-       if ((router && router->bat_iv.tq_avg != 0) &&
+       if ((router_ifinfo && router_ifinfo->bat_iv.tq_avg != 0) &&
            (batadv_compare_eth(router->addr, ethhdr->h_source)))
                is_from_best_next_hop = true;
 
-       prev_sender = batadv_ogm_packet->prev_sender;
+       prev_sender = ogm_packet->prev_sender;
        /* avoid temporary routing loops */
        if (router && router_router &&
            (batadv_compare_eth(router->addr, prev_sender)) &&
-           !(batadv_compare_eth(batadv_ogm_packet->orig, prev_sender)) &&
+           !(batadv_compare_eth(ogm_packet->orig, prev_sender)) &&
            (batadv_compare_eth(router->addr, router_router->addr))) {
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "Drop packet: ignoring all rebroadcast packets that may make me loop (sender: %pM)\n",
@@ -1394,7 +1431,8 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
                goto out;
        }
 
-       batadv_tvlv_ogm_receive(bat_priv, batadv_ogm_packet, orig_node);
+       if (if_outgoing == BATADV_IF_DEFAULT)
+               batadv_tvlv_ogm_receive(bat_priv, ogm_packet, orig_node);
 
        /* if sender is a direct neighbor the sender mac equals
         * originator mac
@@ -1410,9 +1448,10 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
 
        /* Update nc_nodes of the originator */
        batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
-                                batadv_ogm_packet, is_single_hop_neigh);
+                                ogm_packet, is_single_hop_neigh);
 
-       orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
+       orig_neigh_router = batadv_orig_router_get(orig_neigh_node,
+                                                  if_outgoing);
 
        /* drop packet if sender is not a direct neighbor and if we
         * don't route towards it
@@ -1424,28 +1463,48 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
        }
 
        is_bidirect = batadv_iv_ogm_calc_tq(orig_node, orig_neigh_node,
-                                           batadv_ogm_packet, if_incoming);
-
-       batadv_bonding_save_primary(orig_node, orig_neigh_node,
-                                   batadv_ogm_packet);
+                                           ogm_packet, if_incoming,
+                                           if_outgoing);
 
        /* update ranking if it is not a duplicate or has the same
         * seqno and similar ttl as the non-duplicate
         */
-       sameseq = orig_node->last_real_seqno == ntohl(batadv_ogm_packet->seqno);
-       similar_ttl = orig_node->last_ttl - 3 <= batadv_ogm_packet->ttl;
+       orig_ifinfo = batadv_orig_ifinfo_new(orig_node, if_outgoing);
+       if (!orig_ifinfo)
+               goto out_neigh;
+
+       sameseq = orig_ifinfo->last_real_seqno == ntohl(ogm_packet->seqno);
+       similar_ttl = (orig_ifinfo->last_ttl - 3) <= ogm_packet->ttl;
+
        if (is_bidirect && ((dup_status == BATADV_NO_DUP) ||
-                           (sameseq && similar_ttl)))
-               batadv_iv_ogm_orig_update(bat_priv, orig_node, ethhdr,
-                                         batadv_ogm_packet, if_incoming,
-                                         tt_buff, dup_status);
+                           (sameseq && similar_ttl))) {
+               batadv_iv_ogm_orig_update(bat_priv, orig_node,
+                                         orig_ifinfo, ethhdr,
+                                         ogm_packet, if_incoming,
+                                         if_outgoing, dup_status);
+       }
+       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+
+       /* only forward for specific interface, not for the default one. */
+       if (if_outgoing == BATADV_IF_DEFAULT)
+               goto out_neigh;
 
        /* is single hop (direct) neighbor */
        if (is_single_hop_neigh) {
+               /* OGMs from secondary interfaces should only scheduled once
+                * per interface where it has been received, not multiple times
+                */
+               if ((ogm_packet->ttl <= 2) &&
+                   (if_incoming != if_outgoing)) {
+                       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                                  "Drop packet: OGM from secondary interface and wrong outgoing interface\n");
+                       goto out_neigh;
+               }
                /* mark direct link on incoming interface */
-               batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
+               batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
                                      is_single_hop_neigh,
-                                     is_from_best_next_hop, if_incoming);
+                                     is_from_best_next_hop, if_incoming,
+                                     if_outgoing);
 
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                           "Forwarding packet: rebroadcast neighbor packet with direct link flag\n");
@@ -1467,9 +1526,9 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
 
        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                   "Forwarding packet: rebroadcast originator packet\n");
-       batadv_iv_ogm_forward(orig_node, ethhdr, batadv_ogm_packet,
+       batadv_iv_ogm_forward(orig_node, ethhdr, ogm_packet,
                              is_single_hop_neigh, is_from_best_next_hop,
-                             if_incoming);
+                             if_incoming, if_outgoing);
 
 out_neigh:
        if ((orig_neigh_node) && (!is_single_hop_neigh))
@@ -1482,6 +1541,165 @@ out:
        if (orig_neigh_router)
                batadv_neigh_node_free_ref(orig_neigh_router);
 
+       kfree_skb(skb_priv);
+}
+
+/**
+ * batadv_iv_ogm_process - process an incoming batman iv OGM
+ * @skb: the skb containing the OGM
+ * @ogm_offset: offset to the OGM which should be processed (for aggregates)
+ * @if_incoming: the interface where this packet was receved
+ */
+static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
+                                 struct batadv_hard_iface *if_incoming)
+{
+       struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
+       struct batadv_orig_node *orig_neigh_node, *orig_node;
+       struct batadv_hard_iface *hard_iface;
+       struct batadv_ogm_packet *ogm_packet;
+       uint32_t if_incoming_seqno;
+       bool has_directlink_flag;
+       struct ethhdr *ethhdr;
+       bool is_my_oldorig = false;
+       bool is_my_addr = false;
+       bool is_my_orig = false;
+
+       ogm_packet = (struct batadv_ogm_packet *)(skb->data + ogm_offset);
+       ethhdr = eth_hdr(skb);
+
+       /* Silently drop when the batman packet is actually not a
+        * correct packet.
+        *
+        * This might happen if a packet is padded (e.g. Ethernet has a
+        * minimum frame length of 64 byte) and the aggregation interprets
+        * it as an additional length.
+        *
+        * TODO: A more sane solution would be to have a bit in the
+        * batadv_ogm_packet to detect whether the packet is the last
+        * packet in an aggregation.  Here we expect that the padding
+        * is always zero (or not 0x01)
+        */
+       if (ogm_packet->packet_type != BATADV_IV_OGM)
+               return;
+
+       /* could be changed by schedule_own_packet() */
+       if_incoming_seqno = atomic_read(&if_incoming->bat_iv.ogm_seqno);
+
+       if (ogm_packet->flags & BATADV_DIRECTLINK)
+               has_directlink_flag = true;
+       else
+               has_directlink_flag = false;
+
+       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                  "Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, tq %d, TTL %d, V %d, IDF %d)\n",
+                  ethhdr->h_source, if_incoming->net_dev->name,
+                  if_incoming->net_dev->dev_addr, ogm_packet->orig,
+                  ogm_packet->prev_sender, ntohl(ogm_packet->seqno),
+                  ogm_packet->tq, ogm_packet->ttl,
+                  ogm_packet->version, has_directlink_flag);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->if_status != BATADV_IF_ACTIVE)
+                       continue;
+
+               if (hard_iface->soft_iface != if_incoming->soft_iface)
+                       continue;
+
+               if (batadv_compare_eth(ethhdr->h_source,
+                                      hard_iface->net_dev->dev_addr))
+                       is_my_addr = true;
+
+               if (batadv_compare_eth(ogm_packet->orig,
+                                      hard_iface->net_dev->dev_addr))
+                       is_my_orig = true;
+
+               if (batadv_compare_eth(ogm_packet->prev_sender,
+                                      hard_iface->net_dev->dev_addr))
+                       is_my_oldorig = true;
+       }
+       rcu_read_unlock();
+
+       if (is_my_addr) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: received my own broadcast (sender: %pM)\n",
+                          ethhdr->h_source);
+               return;
+       }
+
+       if (is_my_orig) {
+               unsigned long *word;
+               int offset;
+               int32_t bit_pos;
+               int16_t if_num;
+               uint8_t *weight;
+
+               orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
+                                                        ethhdr->h_source);
+               if (!orig_neigh_node)
+                       return;
+
+               /* neighbor has to indicate direct link and it has to
+                * come via the corresponding interface
+                * save packet seqno for bidirectional check
+                */
+               if (has_directlink_flag &&
+                   batadv_compare_eth(if_incoming->net_dev->dev_addr,
+                                      ogm_packet->orig)) {
+                       if_num = if_incoming->if_num;
+                       offset = if_num * BATADV_NUM_WORDS;
+
+                       spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
+                       word = &(orig_neigh_node->bat_iv.bcast_own[offset]);
+                       bit_pos = if_incoming_seqno - 2;
+                       bit_pos -= ntohl(ogm_packet->seqno);
+                       batadv_set_bit(word, bit_pos);
+                       weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num];
+                       *weight = bitmap_weight(word,
+                                               BATADV_TQ_LOCAL_WINDOW_SIZE);
+                       spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
+               }
+
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: originator packet from myself (via neighbor)\n");
+               batadv_orig_node_free_ref(orig_neigh_node);
+               return;
+       }
+
+       if (is_my_oldorig) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: ignoring all rebroadcast echos (sender: %pM)\n",
+                          ethhdr->h_source);
+               return;
+       }
+
+       if (ogm_packet->flags & BATADV_NOT_BEST_NEXT_HOP) {
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Drop packet: ignoring all packets not forwarded from the best next hop (sender: %pM)\n",
+                          ethhdr->h_source);
+               return;
+       }
+
+       orig_node = batadv_iv_ogm_orig_get(bat_priv, ogm_packet->orig);
+       if (!orig_node)
+               return;
+
+       batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
+                                       if_incoming, BATADV_IF_DEFAULT);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->if_status != BATADV_IF_ACTIVE)
+                       continue;
+
+               if (hard_iface->soft_iface != bat_priv->soft_iface)
+                       continue;
+
+               batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
+                                               if_incoming, hard_iface);
+       }
+       rcu_read_unlock();
+
        batadv_orig_node_free_ref(orig_node);
 }
 
@@ -1489,11 +1707,9 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
                                 struct batadv_hard_iface *if_incoming)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
-       struct batadv_ogm_packet *batadv_ogm_packet;
-       struct ethhdr *ethhdr;
-       int buff_pos = 0, packet_len;
-       unsigned char *tvlv_buff, *packet_buff;
+       struct batadv_ogm_packet *ogm_packet;
        uint8_t *packet_pos;
+       int ogm_offset;
        bool ret;
 
        ret = batadv_check_management_packet(skb, if_incoming, BATADV_OGM_HLEN);
@@ -1510,42 +1726,68 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
        batadv_add_counter(bat_priv, BATADV_CNT_MGMT_RX_BYTES,
                           skb->len + ETH_HLEN);
 
-       packet_len = skb_headlen(skb);
-       ethhdr = eth_hdr(skb);
-       packet_buff = skb->data;
-       batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff;
+       ogm_offset = 0;
+       ogm_packet = (struct batadv_ogm_packet *)skb->data;
 
        /* unpack the aggregated packets and process them one by one */
-       while (batadv_iv_ogm_aggr_packet(buff_pos, packet_len,
-                                        batadv_ogm_packet->tvlv_len)) {
-               tvlv_buff = packet_buff + buff_pos + BATADV_OGM_HLEN;
+       while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
+                                        ogm_packet->tvlv_len)) {
+               batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
 
-               batadv_iv_ogm_process(ethhdr, batadv_ogm_packet,
-                                     tvlv_buff, if_incoming);
+               ogm_offset += BATADV_OGM_HLEN;
+               ogm_offset += ntohs(ogm_packet->tvlv_len);
 
-               buff_pos += BATADV_OGM_HLEN;
-               buff_pos += ntohs(batadv_ogm_packet->tvlv_len);
-
-               packet_pos = packet_buff + buff_pos;
-               batadv_ogm_packet = (struct batadv_ogm_packet *)packet_pos;
+               packet_pos = skb->data + ogm_offset;
+               ogm_packet = (struct batadv_ogm_packet *)packet_pos;
        }
 
        kfree_skb(skb);
        return NET_RX_SUCCESS;
 }
 
+/* batadv_iv_ogm_orig_print_neigh - print neighbors for the originator table
+ * @orig_node: the orig_node for which the neighbors are printed
+ * @if_outgoing: outgoing interface for these entries
+ * @seq: debugfs table seq_file struct
+ *
+ * Must be called while holding an rcu lock.
+ */
+static void
+batadv_iv_ogm_orig_print_neigh(struct batadv_orig_node *orig_node,
+                              struct batadv_hard_iface *if_outgoing,
+                              struct seq_file *seq)
+{
+       struct batadv_neigh_node *neigh_node;
+       struct batadv_neigh_ifinfo *n_ifinfo;
+
+       hlist_for_each_entry_rcu(neigh_node, &orig_node->neigh_list, list) {
+               n_ifinfo = batadv_neigh_ifinfo_get(neigh_node, if_outgoing);
+               if (!n_ifinfo)
+                       continue;
+
+               seq_printf(seq, " %pM (%3i)",
+                          neigh_node->addr,
+                          n_ifinfo->bat_iv.tq_avg);
+
+               batadv_neigh_ifinfo_free_ref(n_ifinfo);
+       }
+}
+
 /**
  * batadv_iv_ogm_orig_print - print the originator table
  * @bat_priv: the bat priv with all the soft interface information
  * @seq: debugfs table seq_file struct
+ * @if_outgoing: the outgoing interface for which this should be printed
  */
 static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
-                                    struct seq_file *seq)
+                                    struct seq_file *seq,
+                                    struct batadv_hard_iface *if_outgoing)
 {
-       struct batadv_neigh_node *neigh_node, *neigh_node_tmp;
+       struct batadv_neigh_node *neigh_node;
        struct batadv_hashtable *hash = bat_priv->orig_hash;
        int last_seen_msecs, last_seen_secs;
        struct batadv_orig_node *orig_node;
+       struct batadv_neigh_ifinfo *n_ifinfo;
        unsigned long last_seen_jiffies;
        struct hlist_head *head;
        int batman_count = 0;
@@ -1560,11 +1802,17 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
 
                rcu_read_lock();
                hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
-                       neigh_node = batadv_orig_node_get_router(orig_node);
+                       neigh_node = batadv_orig_router_get(orig_node,
+                                                           if_outgoing);
                        if (!neigh_node)
                                continue;
 
-                       if (neigh_node->bat_iv.tq_avg == 0)
+                       n_ifinfo = batadv_neigh_ifinfo_get(neigh_node,
+                                                          if_outgoing);
+                       if (!n_ifinfo)
+                               goto next;
+
+                       if (n_ifinfo->bat_iv.tq_avg == 0)
                                goto next;
 
                        last_seen_jiffies = jiffies - orig_node->last_seen;
@@ -1574,22 +1822,19 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
 
                        seq_printf(seq, "%pM %4i.%03is   (%3i) %pM [%10s]:",
                                   orig_node->orig, last_seen_secs,
-                                  last_seen_msecs, neigh_node->bat_iv.tq_avg,
+                                  last_seen_msecs, n_ifinfo->bat_iv.tq_avg,
                                   neigh_node->addr,
                                   neigh_node->if_incoming->net_dev->name);
 
-                       hlist_for_each_entry_rcu(neigh_node_tmp,
-                                                &orig_node->neigh_list, list) {
-                               seq_printf(seq, " %pM (%3i)",
-                                          neigh_node_tmp->addr,
-                                          neigh_node_tmp->bat_iv.tq_avg);
-                       }
-
+                       batadv_iv_ogm_orig_print_neigh(orig_node, if_outgoing,
+                                                      seq);
                        seq_puts(seq, "\n");
                        batman_count++;
 
 next:
                        batadv_neigh_node_free_ref(neigh_node);
+                       if (n_ifinfo)
+                               batadv_neigh_ifinfo_free_ref(n_ifinfo);
                }
                rcu_read_unlock();
        }
@@ -1601,37 +1846,84 @@ next:
 /**
  * batadv_iv_ogm_neigh_cmp - compare the metrics of two neighbors
  * @neigh1: the first neighbor object of the comparison
+ * @if_outgoing1: outgoing interface for the first neighbor
  * @neigh2: the second neighbor object of the comparison
+ * @if_outgoing2: outgoing interface for the second neighbor
  *
  * Returns a value less, equal to or greater than 0 if the metric via neigh1 is
  * lower, the same as or higher than the metric via neigh2
  */
 static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
-                                  struct batadv_neigh_node *neigh2)
+                                  struct batadv_hard_iface *if_outgoing1,
+                                  struct batadv_neigh_node *neigh2,
+                                  struct batadv_hard_iface *if_outgoing2)
 {
+       struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
        uint8_t tq1, tq2;
+       int diff;
+
+       neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+       neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+       if (!neigh1_ifinfo || !neigh2_ifinfo) {
+               diff = 0;
+               goto out;
+       }
+
+       tq1 = neigh1_ifinfo->bat_iv.tq_avg;
+       tq2 = neigh2_ifinfo->bat_iv.tq_avg;
+       diff = tq1 - tq2;
 
-       tq1 = neigh1->bat_iv.tq_avg;
-       tq2 = neigh2->bat_iv.tq_avg;
+out:
+       if (neigh1_ifinfo)
+               batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
+       if (neigh2_ifinfo)
+               batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
 
-       return tq1 - tq2;
+       return diff;
 }
 
 /**
  * batadv_iv_ogm_neigh_is_eob - check if neigh1 is equally good or better than
  *  neigh2 from the metric prospective
  * @neigh1: the first neighbor object of the comparison
+ * @if_outgoing: outgoing interface for the first neighbor
  * @neigh2: the second neighbor object of the comparison
- *
- * Returns true if the metric via neigh1 is equally good or better than the
- * metric via neigh2, false otherwise.
+ * @if_outgoing2: outgoing interface for the second neighbor
+
+ * Returns true if the metric via neigh1 is equally good or better than
+ * the metric via neigh2, false otherwise.
  */
-static bool batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
-                                      struct batadv_neigh_node *neigh2)
+static bool
+batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1,
+                          struct batadv_hard_iface *if_outgoing1,
+                          struct batadv_neigh_node *neigh2,
+                          struct batadv_hard_iface *if_outgoing2)
 {
-       int diff = batadv_iv_ogm_neigh_cmp(neigh1, neigh2);
+       struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo;
+       uint8_t tq1, tq2;
+       bool ret;
 
-       return diff > -BATADV_TQ_SIMILARITY_THRESHOLD;
+       neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
+       neigh2_ifinfo = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
+
+       /* we can't say that the metric is better */
+       if (!neigh1_ifinfo || !neigh2_ifinfo) {
+               ret = false;
+               goto out;
+       }
+
+       tq1 = neigh1_ifinfo->bat_iv.tq_avg;
+       tq2 = neigh2_ifinfo->bat_iv.tq_avg;
+       ret = (tq1 - tq2) > -BATADV_TQ_SIMILARITY_THRESHOLD;
+
+out:
+       if (neigh1_ifinfo)
+               batadv_neigh_ifinfo_free_ref(neigh1_ifinfo);
+       if (neigh2_ifinfo)
+               batadv_neigh_ifinfo_free_ref(neigh2_ifinfo);
+
+       return ret;
 }
 
 static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
index 9739824..9586750 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
index a81b932..cc24073 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_BITARRAY_H_
index 28eb5e6..5c0eda4 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
index da173e7..43c985d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_BLA_H_
index 049a7a2..b758881 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -250,6 +248,19 @@ static int batadv_originators_open(struct inode *inode, struct file *file)
        return single_open(file, batadv_orig_seq_print_text, net_dev);
 }
 
+/**
+ * batadv_originators_hardif_open - handles debugfs output for the
+ *  originator table of an hard interface
+ * @inode: inode pointer to debugfs file
+ * @file: pointer to the seq_file
+ */
+static int batadv_originators_hardif_open(struct inode *inode,
+                                         struct file *file)
+{
+       struct net_device *net_dev = (struct net_device *)inode->i_private;
+       return single_open(file, batadv_orig_hardif_seq_print_text, net_dev);
+}
+
 static int batadv_gateways_open(struct inode *inode, struct file *file)
 {
        struct net_device *net_dev = (struct net_device *)inode->i_private;
@@ -371,6 +382,28 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
        NULL,
 };
 
+#define BATADV_HARDIF_DEBUGINFO(_name, _mode, _open)           \
+struct batadv_debuginfo batadv_hardif_debuginfo_##_name = {    \
+       .attr = {                                               \
+               .name = __stringify(_name),                     \
+               .mode = _mode,                                  \
+       },                                                      \
+       .fops = {                                               \
+               .owner = THIS_MODULE,                           \
+               .open = _open,                                  \
+               .read   = seq_read,                             \
+               .llseek = seq_lseek,                            \
+               .release = single_release,                      \
+       },                                                      \
+};
+static BATADV_HARDIF_DEBUGINFO(originators, S_IRUGO,
+                              batadv_originators_hardif_open);
+
+static struct batadv_debuginfo *batadv_hardif_debuginfos[] = {
+       &batadv_hardif_debuginfo_originators,
+       NULL,
+};
+
 void batadv_debugfs_init(void)
 {
        struct batadv_debuginfo **bat_debug;
@@ -398,6 +431,7 @@ void batadv_debugfs_init(void)
        return;
 err:
        debugfs_remove_recursive(batadv_debugfs);
+       batadv_debugfs = NULL;
 }
 
 void batadv_debugfs_destroy(void)
@@ -406,6 +440,59 @@ void batadv_debugfs_destroy(void)
        batadv_debugfs = NULL;
 }
 
+/**
+ * batadv_debugfs_add_hardif - creates the base directory for a hard interface
+ *  in debugfs.
+ * @hard_iface: hard interface which should be added.
+ */
+int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
+{
+       struct batadv_debuginfo **bat_debug;
+       struct dentry *file;
+
+       if (!batadv_debugfs)
+               goto out;
+
+       hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
+                                                  batadv_debugfs);
+       if (!hard_iface->debug_dir)
+               goto out;
+
+       for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug) {
+               file = debugfs_create_file(((*bat_debug)->attr).name,
+                                          S_IFREG | ((*bat_debug)->attr).mode,
+                                          hard_iface->debug_dir,
+                                          hard_iface->net_dev,
+                                          &(*bat_debug)->fops);
+               if (!file)
+                       goto rem_attr;
+       }
+
+       return 0;
+rem_attr:
+       debugfs_remove_recursive(hard_iface->debug_dir);
+       hard_iface->debug_dir = NULL;
+out:
+#ifdef CONFIG_DEBUG_FS
+       return -ENOMEM;
+#else
+       return 0;
+#endif /* CONFIG_DEBUG_FS */
+}
+
+/**
+ * batadv_debugfs_del_hardif - delete the base directory for a hard interface
+ *  in debugfs.
+ * @hard_iface: hard interface which is deleted.
+ */
+void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface)
+{
+       if (batadv_debugfs) {
+               debugfs_remove_recursive(hard_iface->debug_dir);
+               hard_iface->debug_dir = NULL;
+       }
+}
+
 int batadv_debugfs_add_meshif(struct net_device *dev)
 {
        struct batadv_priv *bat_priv = netdev_priv(dev);
index f8c3849..37c4d6d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_DEBUGFS_H_
@@ -26,5 +24,7 @@ void batadv_debugfs_init(void);
 void batadv_debugfs_destroy(void);
 int batadv_debugfs_add_meshif(struct net_device *dev);
 void batadv_debugfs_del_meshif(struct net_device *dev);
+int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface);
+void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface);
 
 #endif /* _NET_BATMAN_ADV_DEBUGFS_H_ */
index b316a4c..edee504 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
  *
  * Antonio Quartulli
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/if_ether.h>
@@ -141,7 +139,7 @@ static int batadv_compare_dat(const struct hlist_node *node, const void *data2)
        const void *data1 = container_of(node, struct batadv_dat_entry,
                                         hash_entry);
 
-       return (memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0);
+       return memcmp(data1, data2, sizeof(__be32)) == 0 ? 1 : 0;
 }
 
 /**
@@ -591,7 +589,8 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
                if (cand[i].type == BATADV_DAT_CANDIDATE_NOT_FOUND)
                        continue;
 
-               neigh_node = batadv_orig_node_get_router(cand[i].orig_node);
+               neigh_node = batadv_orig_router_get(cand[i].orig_node,
+                                                   BATADV_IF_DEFAULT);
                if (!neigh_node)
                        goto free_orig;
 
@@ -1039,9 +1038,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
        if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
                err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
                                                   BATADV_P_DAT_CACHE_REPLY,
-                                                  vid);
+                                                  NULL, vid);
        else
-               err = batadv_send_skb_via_tt(bat_priv, skb_new, vid);
+               err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid);
 
        if (err != NET_XMIT_DROP) {
                batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
index 60d853b..ac9be9b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2011-2014 B.A.T.M.A.N. contributors:
  *
  * Antonio Quartulli
  *
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _NET_BATMAN_ADV_ARP_H_
-#define _NET_BATMAN_ADV_ARP_H_
+#ifndef _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_
+#define _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_
 
 #ifdef CONFIG_BATMAN_ADV_DAT
 
@@ -169,4 +167,4 @@ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,
 
 #endif /* CONFIG_BATMAN_ADV_DAT */
 
-#endif /* _NET_BATMAN_ADV_ARP_H_ */
+#endif /* _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ */
index 6ddb614..88df9b1 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors:
  *
  * Martin Hundebøll <martin@hundeboll.net>
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
index ca029e2..5d7a0e6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2013-2014 B.A.T.M.A.N. contributors:
  *
  * Martin Hundebøll <martin@hundeboll.net>
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_
index 2449afa..55cf226 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
-/* This is the offset of the options field in a dhcp packet starting at
- * the beginning of the dhcp header
+/* These are the offsets of the "hw type" and "hw address length" in the dhcp
+ * packet starting at the beginning of the dhcp header
  */
-#define BATADV_DHCP_OPTIONS_OFFSET 240
-#define BATADV_DHCP_REQUEST 3
+#define BATADV_DHCP_HTYPE_OFFSET       1
+#define BATADV_DHCP_HLEN_OFFSET                2
+/* Value of htype representing Ethernet */
+#define BATADV_DHCP_HTYPE_ETHERNET     0x01
+/* This is the offset of the "chaddr" field in the dhcp packet starting at the
+ * beginning of the dhcp header
+ */
+#define BATADV_DHCP_CHADDR_OFFSET      28
 
 static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node)
 {
@@ -105,7 +109,18 @@ static void batadv_gw_select(struct batadv_priv *bat_priv,
        spin_unlock_bh(&bat_priv->gw.list_lock);
 }
 
-void batadv_gw_deselect(struct batadv_priv *bat_priv)
+/**
+ * batadv_gw_reselect - force a gateway reselection
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Set a flag to remind the GW component to perform a new gateway reselection.
+ * However this function does not ensure that the current gateway is going to be
+ * deselected. The reselection mechanism may elect the same gateway once again.
+ *
+ * This means that invoking batadv_gw_reselect() does not guarantee a gateway
+ * change and therefore a uevent is not necessarily expected.
+ */
+void batadv_gw_reselect(struct batadv_priv *bat_priv)
 {
        atomic_set(&bat_priv->gw.reselect, 1);
 }
@@ -114,6 +129,7 @@ static struct batadv_gw_node *
 batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
 {
        struct batadv_neigh_node *router;
+       struct batadv_neigh_ifinfo *router_ifinfo;
        struct batadv_gw_node *gw_node, *curr_gw = NULL;
        uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
        uint32_t gw_divisor;
@@ -130,14 +146,19 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
                        continue;
 
                orig_node = gw_node->orig_node;
-               router = batadv_orig_node_get_router(orig_node);
+               router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
                if (!router)
                        continue;
 
+               router_ifinfo = batadv_neigh_ifinfo_get(router,
+                                                       BATADV_IF_DEFAULT);
+               if (!router_ifinfo)
+                       goto next;
+
                if (!atomic_inc_not_zero(&gw_node->refcount))
                        goto next;
 
-               tq_avg = router->bat_iv.tq_avg;
+               tq_avg = router_ifinfo->bat_iv.tq_avg;
 
                switch (atomic_read(&bat_priv->gw_sel_class)) {
                case 1: /* fast connection */
@@ -182,6 +203,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
 
 next:
                batadv_neigh_node_free_ref(router);
+               if (router_ifinfo)
+                       batadv_neigh_ifinfo_free_ref(router_ifinfo);
        }
        rcu_read_unlock();
 
@@ -207,6 +230,11 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
        if (!curr_gw)
                return;
 
+       /* deselect the current gateway so that next time that client mode is
+        * enabled a proper GW_ADD event can be sent
+        */
+       batadv_gw_select(bat_priv, NULL);
+
        /* if batman-adv is switching the gw client mode off and a gateway was
         * already selected, send a DEL uevent
         */
@@ -219,6 +247,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
 {
        struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL;
        struct batadv_neigh_node *router = NULL;
+       struct batadv_neigh_ifinfo *router_ifinfo = NULL;
        char gw_addr[18] = { '\0' };
 
        if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
@@ -237,9 +266,17 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
        if (next_gw) {
                sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
 
-               router = batadv_orig_node_get_router(next_gw->orig_node);
+               router = batadv_orig_router_get(next_gw->orig_node,
+                                               BATADV_IF_DEFAULT);
                if (!router) {
-                       batadv_gw_deselect(bat_priv);
+                       batadv_gw_reselect(bat_priv);
+                       goto out;
+               }
+
+               router_ifinfo = batadv_neigh_ifinfo_get(router,
+                                                       BATADV_IF_DEFAULT);
+               if (!router_ifinfo) {
+                       batadv_gw_reselect(bat_priv);
                        goto out;
                }
        }
@@ -256,7 +293,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
                           next_gw->bandwidth_down / 10,
                           next_gw->bandwidth_down % 10,
                           next_gw->bandwidth_up / 10,
-                          next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
+                          next_gw->bandwidth_up % 10,
+                          router_ifinfo->bat_iv.tq_avg);
                batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
                                    gw_addr);
        } else {
@@ -266,7 +304,8 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
                           next_gw->bandwidth_down / 10,
                           next_gw->bandwidth_down % 10,
                           next_gw->bandwidth_up / 10,
-                          next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
+                          next_gw->bandwidth_up % 10,
+                          router_ifinfo->bat_iv.tq_avg);
                batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
                                    gw_addr);
        }
@@ -280,33 +319,47 @@ out:
                batadv_gw_node_free_ref(next_gw);
        if (router)
                batadv_neigh_node_free_ref(router);
+       if (router_ifinfo)
+               batadv_neigh_ifinfo_free_ref(router_ifinfo);
 }
 
 void batadv_gw_check_election(struct batadv_priv *bat_priv,
                              struct batadv_orig_node *orig_node)
 {
+       struct batadv_neigh_ifinfo *router_orig_tq = NULL;
+       struct batadv_neigh_ifinfo *router_gw_tq = NULL;
        struct batadv_orig_node *curr_gw_orig;
        struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL;
        uint8_t gw_tq_avg, orig_tq_avg;
 
        curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
        if (!curr_gw_orig)
-               goto deselect;
+               goto reselect;
 
-       router_gw = batadv_orig_node_get_router(curr_gw_orig);
+       router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT);
        if (!router_gw)
-               goto deselect;
+               goto reselect;
+
+       router_gw_tq = batadv_neigh_ifinfo_get(router_gw,
+                                              BATADV_IF_DEFAULT);
+       if (!router_gw_tq)
+               goto reselect;
 
        /* this node already is the gateway */
        if (curr_gw_orig == orig_node)
                goto out;
 
-       router_orig = batadv_orig_node_get_router(orig_node);
+       router_orig = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT);
        if (!router_orig)
                goto out;
 
-       gw_tq_avg = router_gw->bat_iv.tq_avg;
-       orig_tq_avg = router_orig->bat_iv.tq_avg;
+       router_orig_tq = batadv_neigh_ifinfo_get(router_orig,
+                                                BATADV_IF_DEFAULT);
+       if (!router_orig_tq)
+               goto out;
+
+       gw_tq_avg = router_gw_tq->bat_iv.tq_avg;
+       orig_tq_avg = router_orig_tq->bat_iv.tq_avg;
 
        /* the TQ value has to be better */
        if (orig_tq_avg < gw_tq_avg)
@@ -323,8 +376,8 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv,
                   "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
                   gw_tq_avg, orig_tq_avg);
 
-deselect:
-       batadv_gw_deselect(bat_priv);
+reselect:
+       batadv_gw_reselect(bat_priv);
 out:
        if (curr_gw_orig)
                batadv_orig_node_free_ref(curr_gw_orig);
@@ -332,6 +385,10 @@ out:
                batadv_neigh_node_free_ref(router_gw);
        if (router_orig)
                batadv_neigh_node_free_ref(router_orig);
+       if (router_gw_tq)
+               batadv_neigh_ifinfo_free_ref(router_gw_tq);
+       if (router_orig_tq)
+               batadv_neigh_ifinfo_free_ref(router_orig_tq);
 
        return;
 }
@@ -454,7 +511,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
                 */
                curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
                if (gw_node == curr_gw)
-                       batadv_gw_deselect(bat_priv);
+                       batadv_gw_reselect(bat_priv);
        }
 
 out:
@@ -480,7 +537,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
        struct batadv_gw_node *gw_node, *curr_gw;
        struct hlist_node *node_tmp;
        unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT);
-       int do_deselect = 0;
+       int do_reselect = 0;
 
        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
@@ -494,7 +551,7 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
                        continue;
 
                if (curr_gw == gw_node)
-                       do_deselect = 1;
+                       do_reselect = 1;
 
                hlist_del_rcu(&gw_node->list);
                batadv_gw_node_free_ref(gw_node);
@@ -502,9 +559,9 @@ void batadv_gw_node_purge(struct batadv_priv *bat_priv)
 
        spin_unlock_bh(&bat_priv->gw.list_lock);
 
-       /* gw_deselect() needs to acquire the gw_list_lock */
-       if (do_deselect)
-               batadv_gw_deselect(bat_priv);
+       /* gw_reselect() needs to acquire the gw_list_lock */
+       if (do_reselect)
+               batadv_gw_reselect(bat_priv);
 
        if (curr_gw)
                batadv_gw_node_free_ref(curr_gw);
@@ -517,28 +574,36 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
 {
        struct batadv_gw_node *curr_gw;
        struct batadv_neigh_node *router;
+       struct batadv_neigh_ifinfo *router_ifinfo = NULL;
        int ret = -1;
 
-       router = batadv_orig_node_get_router(gw_node->orig_node);
+       router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
        if (!router)
                goto out;
 
+       router_ifinfo = batadv_neigh_ifinfo_get(router, BATADV_IF_DEFAULT);
+       if (!router_ifinfo)
+               goto out;
+
        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
        ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
                         (curr_gw == gw_node ? "=>" : "  "),
                         gw_node->orig_node->orig,
-                        router->bat_iv.tq_avg, router->addr,
+                        router_ifinfo->bat_iv.tq_avg, router->addr,
                         router->if_incoming->net_dev->name,
                         gw_node->bandwidth_down / 10,
                         gw_node->bandwidth_down % 10,
                         gw_node->bandwidth_up / 10,
                         gw_node->bandwidth_up % 10);
 
-       batadv_neigh_node_free_ref(router);
        if (curr_gw)
                batadv_gw_node_free_ref(curr_gw);
 out:
+       if (router_ifinfo)
+               batadv_neigh_ifinfo_free_ref(router_ifinfo);
+       if (router)
+               batadv_neigh_node_free_ref(router);
        return ret;
 }
 
@@ -582,80 +647,39 @@ out:
        return 0;
 }
 
-/* this call might reallocate skb data */
-static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
-{
-       int ret = false;
-       unsigned char *p;
-       int pkt_len;
-
-       if (skb_linearize(skb) < 0)
-               goto out;
-
-       pkt_len = skb_headlen(skb);
-
-       if (pkt_len < header_len + BATADV_DHCP_OPTIONS_OFFSET + 1)
-               goto out;
-
-       p = skb->data + header_len + BATADV_DHCP_OPTIONS_OFFSET;
-       pkt_len -= header_len + BATADV_DHCP_OPTIONS_OFFSET + 1;
-
-       /* Access the dhcp option lists. Each entry is made up by:
-        * - octet 1: option type
-        * - octet 2: option data len (only if type != 255 and 0)
-        * - octet 3: option data
-        */
-       while (*p != 255 && !ret) {
-               /* p now points to the first octet: option type */
-               if (*p == 53) {
-                       /* type 53 is the message type option.
-                        * Jump the len octet and go to the data octet
-                        */
-                       if (pkt_len < 2)
-                               goto out;
-                       p += 2;
-
-                       /* check if the message type is what we need */
-                       if (*p == BATADV_DHCP_REQUEST)
-                               ret = true;
-                       break;
-               } else if (*p == 0) {
-                       /* option type 0 (padding), just go forward */
-                       if (pkt_len < 1)
-                               goto out;
-                       pkt_len--;
-                       p++;
-               } else {
-                       /* This is any other option. So we get the length... */
-                       if (pkt_len < 1)
-                               goto out;
-                       pkt_len--;
-                       p++;
-
-                       /* ...and then we jump over the data */
-                       if (pkt_len < 1 + (*p))
-                               goto out;
-                       pkt_len -= 1 + (*p);
-                       p += 1 + (*p);
-               }
-       }
-out:
-       return ret;
-}
-
-/* this call might reallocate skb data */
-bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
+/**
+ * batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message
+ * @skb: the packet to check
+ * @header_len: a pointer to the batman-adv header size
+ * @chaddr: buffer where the client address will be stored. Valid
+ *  only if the function returns BATADV_DHCP_TO_CLIENT
+ *
+ * Returns:
+ * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error
+ *   while parsing it
+ * - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server
+ * - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client
+ *
+ * This function may re-allocate the data buffer of the skb passed as argument.
+ */
+enum batadv_dhcp_recipient
+batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
+                            uint8_t *chaddr)
 {
+       enum batadv_dhcp_recipient ret = BATADV_DHCP_NO;
        struct ethhdr *ethhdr;
        struct iphdr *iphdr;
        struct ipv6hdr *ipv6hdr;
        struct udphdr *udphdr;
        struct vlan_ethhdr *vhdr;
+       int chaddr_offset;
        __be16 proto;
+       uint8_t *p;
 
        /* check for ethernet header */
        if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
-               return false;
+               return BATADV_DHCP_NO;
+
        ethhdr = (struct ethhdr *)skb->data;
        proto = ethhdr->h_proto;
        *header_len += ETH_HLEN;
@@ -663,7 +687,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
        /* check for initial vlan header */
        if (proto == htons(ETH_P_8021Q)) {
                if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
-                       return false;
+                       return BATADV_DHCP_NO;
 
                vhdr = (struct vlan_ethhdr *)skb->data;
                proto = vhdr->h_vlan_encapsulated_proto;
@@ -674,32 +698,34 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
        switch (proto) {
        case htons(ETH_P_IP):
                if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
-                       return false;
+                       return BATADV_DHCP_NO;
+
                iphdr = (struct iphdr *)(skb->data + *header_len);
                *header_len += iphdr->ihl * 4;
 
                /* check for udp header */
                if (iphdr->protocol != IPPROTO_UDP)
-                       return false;
+                       return BATADV_DHCP_NO;
 
                break;
        case htons(ETH_P_IPV6):
                if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
-                       return false;
+                       return BATADV_DHCP_NO;
+
                ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
                *header_len += sizeof(*ipv6hdr);
 
                /* check for udp header */
                if (ipv6hdr->nexthdr != IPPROTO_UDP)
-                       return false;
+                       return BATADV_DHCP_NO;
 
                break;
        default:
-               return false;
+               return BATADV_DHCP_NO;
        }
 
        if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
-               return false;
+               return BATADV_DHCP_NO;
 
        /* skb->data might have been reallocated by pskb_may_pull() */
        ethhdr = (struct ethhdr *)skb->data;
@@ -710,17 +736,40 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
        *header_len += sizeof(*udphdr);
 
        /* check for bootp port */
-       if ((proto == htons(ETH_P_IP)) &&
-           (udphdr->dest != htons(67)))
-               return false;
+       switch (proto) {
+       case htons(ETH_P_IP):
+               if (udphdr->dest == htons(67))
+                       ret = BATADV_DHCP_TO_SERVER;
+               else if (udphdr->source == htons(67))
+                       ret = BATADV_DHCP_TO_CLIENT;
+               break;
+       case htons(ETH_P_IPV6):
+               if (udphdr->dest == htons(547))
+                       ret = BATADV_DHCP_TO_SERVER;
+               else if (udphdr->source == htons(547))
+                       ret = BATADV_DHCP_TO_CLIENT;
+               break;
+       }
 
-       if ((proto == htons(ETH_P_IPV6)) &&
-           (udphdr->dest != htons(547)))
-               return false;
+       chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
+       /* store the client address if the message is going to a client */
+       if (ret == BATADV_DHCP_TO_CLIENT &&
+           pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
+               /* check if the DHCP packet carries an Ethernet DHCP */
+               p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
+               if (*p != BATADV_DHCP_HTYPE_ETHERNET)
+                       return BATADV_DHCP_NO;
+
+               /* check if the DHCP packet carries a valid Ethernet address */
+               p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET;
+               if (*p != ETH_ALEN)
+                       return BATADV_DHCP_NO;
+
+               memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN);
+       }
 
-       return true;
+       return ret;
 }
-
 /**
  * batadv_gw_out_of_range - check if the dhcp request destination is the best gw
  * @bat_priv: the bat priv with all the soft interface information
@@ -734,6 +783,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
  * false otherwise.
  *
  * This call might reallocate skb data.
+ * Must be invoked only when the DHCP packet is going TO a DHCP SERVER.
  */
 bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
                            struct sk_buff *skb)
@@ -741,19 +791,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
        struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
        struct batadv_orig_node *orig_dst_node = NULL;
        struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
-       struct ethhdr *ethhdr;
-       bool ret, out_of_range = false;
-       unsigned int header_len = 0;
+       struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
+       struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+       bool out_of_range = false;
        uint8_t curr_tq_avg;
        unsigned short vid;
 
        vid = batadv_get_vid(skb, 0);
 
-       ret = batadv_gw_is_dhcp_target(skb, &header_len);
-       if (!ret)
-               goto out;
-
-       ethhdr = (struct ethhdr *)skb->data;
        orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
                                                 ethhdr->h_dest, vid);
        if (!orig_dst_node)
@@ -763,10 +808,6 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
        if (!gw_node->bandwidth_down == 0)
                goto out;
 
-       ret = batadv_is_type_dhcprequest(skb, header_len);
-       if (!ret)
-               goto out;
-
        switch (atomic_read(&bat_priv->gw_mode)) {
        case BATADV_GW_MODE_SERVER:
                /* If we are a GW then we are our best GW. We can artificially
@@ -792,7 +833,14 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
                if (!neigh_curr)
                        goto out;
 
-               curr_tq_avg = neigh_curr->bat_iv.tq_avg;
+               curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
+                                                     BATADV_IF_DEFAULT);
+               if (!curr_ifinfo)
+                       goto out;
+
+               curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
+               batadv_neigh_ifinfo_free_ref(curr_ifinfo);
+
                break;
        case BATADV_GW_MODE_OFF:
        default:
@@ -803,8 +851,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
        if (!neigh_old)
                goto out;
 
-       if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD)
+       old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
+       if (!old_ifinfo)
+               goto out;
+
+       if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD)
                out_of_range = true;
+       batadv_neigh_ifinfo_free_ref(old_ifinfo);
 
 out:
        if (orig_dst_node)
index d95c2d2..7ee53bb 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
 #define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_
 
 void batadv_gw_check_client_stop(struct batadv_priv *bat_priv);
-void batadv_gw_deselect(struct batadv_priv *bat_priv);
+void batadv_gw_reselect(struct batadv_priv *bat_priv);
 void batadv_gw_election(struct batadv_priv *bat_priv);
 struct batadv_orig_node *
 batadv_gw_get_selected_orig(struct batadv_priv *bat_priv);
@@ -34,7 +32,9 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
                           struct batadv_orig_node *orig_node);
 void batadv_gw_node_purge(struct batadv_priv *bat_priv);
 int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
-bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
 bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
+enum batadv_dhcp_recipient
+batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
+                            uint8_t *chaddr);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
index b211b0f..6f5e621 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -164,7 +162,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
        if ((down_curr == down_new) && (up_curr == up_new))
                return count;
 
-       batadv_gw_deselect(bat_priv);
+       batadv_gw_reselect(bat_priv);
        batadv_info(net_dev,
                    "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n",
                    down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10,
index 56384a4..aa51165 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_
index 57c2a19..3d417d3 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -25,6 +23,7 @@
 #include "translation-table.h"
 #include "routing.h"
 #include "sysfs.h"
+#include "debugfs.h"
 #include "originator.h"
 #include "hash.h"
 #include "bridge_loop_avoidance.h"
@@ -88,15 +87,13 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
                return false;
 
        /* recurse over the parent device */
-       parent_dev = dev_get_by_index(&init_net, net_dev->iflink);
+       parent_dev = __dev_get_by_index(&init_net, net_dev->iflink);
        /* if we got a NULL parent_dev there is something broken.. */
        if (WARN(!parent_dev, "Cannot find parent device"))
                return false;
 
        ret = batadv_is_on_batman_iface(parent_dev);
 
-       if (parent_dev)
-               dev_put(parent_dev);
        return ret;
 }
 
@@ -541,6 +538,7 @@ static void batadv_hardif_remove_interface_finish(struct work_struct *work)
        hard_iface = container_of(work, struct batadv_hard_iface,
                                  cleanup_work);
 
+       batadv_debugfs_del_hardif(hard_iface);
        batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
        batadv_hardif_free_ref(hard_iface);
 }
@@ -571,6 +569,11 @@ batadv_hardif_add_interface(struct net_device *net_dev)
        hard_iface->net_dev = net_dev;
        hard_iface->soft_iface = NULL;
        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
+
+       ret = batadv_debugfs_add_hardif(hard_iface);
+       if (ret)
+               goto free_sysfs;
+
        INIT_LIST_HEAD(&hard_iface->list);
        INIT_WORK(&hard_iface->cleanup_work,
                  batadv_hardif_remove_interface_finish);
@@ -587,6 +590,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
 
        return hard_iface;
 
+free_sysfs:
+       batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
 free_if:
        kfree(hard_iface);
 release_dev:
index df4c8bd..1918cd5 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_
@@ -42,6 +40,7 @@ enum batadv_hard_if_cleanup {
 extern struct notifier_block batadv_hard_if_notifier;
 
 bool batadv_is_wifi_netdev(struct net_device *net_device);
+bool batadv_is_wifi_iface(int ifindex);
 struct batadv_hard_iface*
 batadv_hardif_get_by_netdev(const struct net_device *net_dev);
 int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
@@ -53,6 +52,11 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface);
 void batadv_update_min_mtu(struct net_device *soft_iface);
 void batadv_hardif_free_rcu(struct rcu_head *rcu);
 
+/**
+ * batadv_hardif_free_ref - decrement the hard interface refcounter and
+ *  possibly free it
+ * @hard_iface: the hard interface to free
+ */
 static inline void
 batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
 {
@@ -60,6 +64,18 @@ batadv_hardif_free_ref(struct batadv_hard_iface *hard_iface)
                call_rcu(&hard_iface->rcu, batadv_hardif_free_rcu);
 }
 
+/**
+ * batadv_hardif_free_ref_now - decrement the hard interface refcounter and
+ *  possibly free it (without rcu callback)
+ * @hard_iface: the hard interface to free
+ */
+static inline void
+batadv_hardif_free_ref_now(struct batadv_hard_iface *hard_iface)
+{
+       if (atomic_dec_and_test(&hard_iface->refcount))
+               batadv_hardif_free_rcu(&hard_iface->rcu);
+}
+
 static inline struct batadv_hard_iface *
 batadv_primary_if_get_selected(struct batadv_priv *bat_priv)
 {
index 7198daf..63bdf7e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
index 1b4da72..539fc12 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2006-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2006-2014 B.A.T.M.A.N. contributors:
  *
  * Simon Wunderlich, Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_HASH_H_
index 130cc32..abb9d6e 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -217,7 +215,8 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
                if (!orig_node)
                        goto dst_unreach;
 
-               neigh_node = batadv_orig_node_get_router(orig_node);
+               neigh_node = batadv_orig_router_get(orig_node,
+                                                   BATADV_IF_DEFAULT);
                if (!neigh_node)
                        goto dst_unreach;
 
index 6665080..0c33950 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_ICMP_SOCKET_H_
index 1511f64..e56b4d6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/crc32c.h>
@@ -421,13 +419,23 @@ static void batadv_recv_handler_init(void)
        for (i = BATADV_UNICAST_MIN; i <= BATADV_UNICAST_MAX; i++)
                batadv_rx_handler[i] = batadv_recv_unhandled_unicast_packet;
 
-       /* compile time checks for struct member offsets */
-       BUILD_BUG_ON(offsetof(struct batadv_unicast_4addr_packet, src) != 10);
-       BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, dest) != 4);
-       BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, dst) != 4);
-       BUILD_BUG_ON(offsetof(struct batadv_frag_packet, dest) != 4);
-       BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, dst) != 4);
-       BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, dst) != 4);
+       /* compile time checks for sizes */
+       BUILD_BUG_ON(sizeof(struct batadv_bla_claim_dst) != 6);
+       BUILD_BUG_ON(sizeof(struct batadv_ogm_packet) != 24);
+       BUILD_BUG_ON(sizeof(struct batadv_icmp_header) != 20);
+       BUILD_BUG_ON(sizeof(struct batadv_icmp_packet) != 20);
+       BUILD_BUG_ON(sizeof(struct batadv_icmp_packet_rr) != 116);
+       BUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);
+       BUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);
+       BUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);
+       BUILD_BUG_ON(sizeof(struct batadv_bcast_packet) != 14);
+       BUILD_BUG_ON(sizeof(struct batadv_coded_packet) != 46);
+       BUILD_BUG_ON(sizeof(struct batadv_unicast_tvlv_packet) != 20);
+       BUILD_BUG_ON(sizeof(struct batadv_tvlv_hdr) != 4);
+       BUILD_BUG_ON(sizeof(struct batadv_tvlv_gateway_data) != 8);
+       BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8);
+       BUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);
+       BUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);
 
        /* broadcast packet */
        batadv_rx_handler[BATADV_BCAST] = batadv_recv_bcast_packet;
@@ -1173,6 +1181,32 @@ unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
        return vid;
 }
 
+/**
+ * batadv_vlan_ap_isola_get - return the AP isolation status for the given vlan
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the VLAN identifier for which the AP isolation attributed as to be
+ *  looked up
+ *
+ * Returns true if AP isolation is on for the VLAN idenfied by vid, false
+ * otherwise
+ */
+bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)
+{
+       bool ap_isolation_enabled = false;
+       struct batadv_softif_vlan *vlan;
+
+       /* if the AP isolation is requested on a VLAN, then check for its
+        * setting in the proper VLAN private data structure
+        */
+       vlan = batadv_softif_vlan_get(bat_priv, vid);
+       if (vlan) {
+               ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
+               batadv_softif_vlan_free_ref(vlan);
+       }
+
+       return ap_isolation_enabled;
+}
+
 static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
 {
        struct batadv_algo_ops *bat_algo_ops;
index 322dd73..9374f1a 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_MAIN_H_
@@ -26,7 +24,7 @@
 #define BATADV_DRIVER_DEVICE "batman-adv"
 
 #ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2013.5.0"
+#define BATADV_SOURCE_VERSION "2014.1.0"
 #endif
 
 /* B.A.T.M.A.N. parameters */
 
 #define BATADV_NULL_IFINDEX 0 /* dummy ifindex used to avoid iface checks */
 
+#define BATADV_NO_MARK 0
+
+/* default interface for multi interface operation. The default interface is
+ * used for communication which originated locally (i.e. is not forwarded)
+ * or where special forwarding is not desired/necessary.
+ */
+#define BATADV_IF_DEFAULT      ((struct batadv_hard_iface *)NULL)
+
 #define BATADV_NUM_WORDS BITS_TO_LONGS(BATADV_TQ_LOCAL_WINDOW_SIZE)
 
 #define BATADV_LOG_BUF_LEN 8192          /* has to be a power of 2 */
@@ -369,5 +375,6 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src,
                              uint8_t *dst, uint8_t type, uint8_t version,
                              void *tvlv_value, uint16_t tvlv_value_len);
 unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len);
+bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid);
 
 #endif /* _NET_BATMAN_ADV_MAIN_H_ */
index 511d7e1..f1b604d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors:
  *
  * Martin Hundebøll, Jeppe Ledet-Pedersen
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/debugfs.h>
@@ -720,9 +718,21 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
                                    struct batadv_orig_node *orig_node,
                                    struct batadv_ogm_packet *ogm_packet)
 {
-       if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno))
+       struct batadv_orig_ifinfo *orig_ifinfo;
+       uint32_t last_real_seqno;
+       uint8_t last_ttl;
+
+       orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT);
+       if (!orig_ifinfo)
                return false;
-       if (orig_node->last_ttl != ogm_packet->ttl + 1)
+
+       last_ttl = orig_ifinfo->last_ttl;
+       last_real_seqno = orig_ifinfo->last_real_seqno;
+       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+
+       if (last_real_seqno != ntohl(ogm_packet->seqno))
+               return false;
+       if (last_ttl != ogm_packet->ttl + 1)
                return false;
        if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
                return false;
@@ -1010,6 +1020,8 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
        struct batadv_coded_packet *coded_packet;
        struct batadv_neigh_node *neigh_tmp, *router_neigh;
        struct batadv_neigh_node *router_coding = NULL;
+       struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
+       struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
        uint8_t *first_source, *first_dest, *second_source, *second_dest;
        __be32 packet_id1, packet_id2;
        size_t count;
@@ -1019,19 +1031,34 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
        int coded_size = sizeof(*coded_packet);
        int header_add = coded_size - unicast_size;
 
-       router_neigh = batadv_orig_node_get_router(neigh_node->orig_node);
+       /* TODO: do we need to consider the outgoing interface for
+        * coded packets?
+        */
+       router_neigh = batadv_orig_router_get(neigh_node->orig_node,
+                                             BATADV_IF_DEFAULT);
        if (!router_neigh)
                goto out;
 
+       router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh,
+                                                     BATADV_IF_DEFAULT);
+       if (!router_neigh_ifinfo)
+               goto out;
+
        neigh_tmp = nc_packet->neigh_node;
-       router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node);
+       router_coding = batadv_orig_router_get(neigh_tmp->orig_node,
+                                              BATADV_IF_DEFAULT);
        if (!router_coding)
                goto out;
 
-       tq_tmp = batadv_nc_random_weight_tq(router_neigh->bat_iv.tq_avg);
-       tq_weighted_neigh = tq_tmp;
-       tq_tmp = batadv_nc_random_weight_tq(router_coding->bat_iv.tq_avg);
-       tq_weighted_coding = tq_tmp;
+       router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding,
+                                                      BATADV_IF_DEFAULT);
+       if (!router_coding_ifinfo)
+               goto out;
+
+       tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg;
+       tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp);
+       tq_tmp = router_coding_ifinfo->bat_iv.tq_avg;
+       tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp);
 
        /* Select one destination for the MAC-header dst-field based on
         * weighted TQ-values.
@@ -1155,6 +1182,10 @@ out:
                batadv_neigh_node_free_ref(router_neigh);
        if (router_coding)
                batadv_neigh_node_free_ref(router_coding);
+       if (router_neigh_ifinfo)
+               batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo);
+       if (router_coding_ifinfo)
+               batadv_neigh_ifinfo_free_ref(router_coding_ifinfo);
        return res;
 }
 
index d4fd315..358c0d6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors:
  *
  * Martin Hundebøll, Jeppe Ledet-Pedersen
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_NETWORK_CODING_H_
@@ -64,7 +62,6 @@ static inline int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
 
 static inline void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
 {
-       return;
 }
 
 static inline void
@@ -74,7 +71,6 @@ batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
                         struct batadv_ogm_packet *ogm_packet,
                         int is_single_hop_neigh)
 {
-       return;
 }
 
 static inline void
@@ -83,17 +79,14 @@ batadv_nc_purge_orig(struct batadv_priv *bat_priv,
                     bool (*to_purge)(struct batadv_priv *,
                                      struct batadv_nc_node *))
 {
-       return;
 }
 
 static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
 {
-       return;
 }
 
 static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
 {
-       return;
 }
 
 static inline bool batadv_nc_skb_forward(struct sk_buff *skb,
@@ -106,14 +99,12 @@ static inline void
 batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
                                 struct sk_buff *skb)
 {
-       return;
 }
 
 static inline void
 batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
                                    struct sk_buff *skb)
 {
-       return;
 }
 
 static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,
index 803ab4b..6df12a2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -150,20 +148,114 @@ err:
        return -ENOMEM;
 }
 
+/**
+ * batadv_neigh_ifinfo_free_rcu - free the neigh_ifinfo object
+ * @rcu: rcu pointer of the neigh_ifinfo object
+ */
+static void batadv_neigh_ifinfo_free_rcu(struct rcu_head *rcu)
+{
+       struct batadv_neigh_ifinfo *neigh_ifinfo;
+
+       neigh_ifinfo = container_of(rcu, struct batadv_neigh_ifinfo, rcu);
+
+       if (neigh_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
+               batadv_hardif_free_ref_now(neigh_ifinfo->if_outgoing);
+
+       kfree(neigh_ifinfo);
+}
+
+/**
+ * batadv_neigh_ifinfo_free_now - decrement the refcounter and possibly free
+ *  the neigh_ifinfo (without rcu callback)
+ * @neigh_ifinfo: the neigh_ifinfo object to release
+ */
+static void
+batadv_neigh_ifinfo_free_ref_now(struct batadv_neigh_ifinfo *neigh_ifinfo)
+{
+       if (atomic_dec_and_test(&neigh_ifinfo->refcount))
+               batadv_neigh_ifinfo_free_rcu(&neigh_ifinfo->rcu);
+}
+
+/**
+ * batadv_neigh_ifinfo_free_ref - decrement the refcounter and possibly free
+ *  the neigh_ifinfo
+ * @neigh_ifinfo: the neigh_ifinfo object to release
+ */
+void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
+{
+       if (atomic_dec_and_test(&neigh_ifinfo->refcount))
+               call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
+}
+
+/**
+ * batadv_neigh_node_free_rcu - free the neigh_node
+ * @rcu: rcu pointer of the neigh_node
+ */
+static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
+{
+       struct hlist_node *node_tmp;
+       struct batadv_neigh_node *neigh_node;
+       struct batadv_neigh_ifinfo *neigh_ifinfo;
+
+       neigh_node = container_of(rcu, struct batadv_neigh_node, rcu);
+
+       hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
+                                 &neigh_node->ifinfo_list, list) {
+               batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
+       }
+       batadv_hardif_free_ref_now(neigh_node->if_incoming);
+
+       kfree(neigh_node);
+}
+
+/**
+ * batadv_neigh_node_free_ref_now - decrement the neighbors refcounter
+ *  and possibly free it (without rcu callback)
+ * @neigh_node: neigh neighbor to free
+ */
+static void
+batadv_neigh_node_free_ref_now(struct batadv_neigh_node *neigh_node)
+{
+       if (atomic_dec_and_test(&neigh_node->refcount))
+               batadv_neigh_node_free_rcu(&neigh_node->rcu);
+}
+
+/**
+ * batadv_neigh_node_free_ref - decrement the neighbors refcounter
+ *  and possibly free it
+ * @neigh_node: neigh neighbor to free
+ */
 void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node)
 {
        if (atomic_dec_and_test(&neigh_node->refcount))
-               kfree_rcu(neigh_node, rcu);
+               call_rcu(&neigh_node->rcu, batadv_neigh_node_free_rcu);
 }
 
-/* increases the refcounter of a found router */
+/**
+ * batadv_orig_node_get_router - router to the originator depending on iface
+ * @orig_node: the orig node for the router
+ * @if_outgoing: the interface where the payload packet has been received or
+ *  the OGM should be sent to
+ *
+ * Returns the neighbor which should be router for this orig_node/iface.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
 struct batadv_neigh_node *
-batadv_orig_node_get_router(struct batadv_orig_node *orig_node)
+batadv_orig_router_get(struct batadv_orig_node *orig_node,
+                      const struct batadv_hard_iface *if_outgoing)
 {
-       struct batadv_neigh_node *router;
+       struct batadv_orig_ifinfo *orig_ifinfo;
+       struct batadv_neigh_node *router = NULL;
 
        rcu_read_lock();
-       router = rcu_dereference(orig_node->router);
+       hlist_for_each_entry_rcu(orig_ifinfo, &orig_node->ifinfo_list, list) {
+               if (orig_ifinfo->if_outgoing != if_outgoing)
+                       continue;
+
+               router = rcu_dereference(orig_ifinfo->router);
+               break;
+       }
 
        if (router && !atomic_inc_not_zero(&router->refcount))
                router = NULL;
@@ -173,6 +265,164 @@ batadv_orig_node_get_router(struct batadv_orig_node *orig_node)
 }
 
 /**
+ * batadv_orig_ifinfo_get - find the ifinfo from an orig_node
+ * @orig_node: the orig node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * Returns the requested orig_ifinfo or NULL if not found.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
+struct batadv_orig_ifinfo *
+batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
+                      struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_orig_ifinfo *tmp, *orig_ifinfo = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp, &orig_node->ifinfo_list,
+                                list) {
+               if (tmp->if_outgoing != if_outgoing)
+                       continue;
+
+               if (!atomic_inc_not_zero(&tmp->refcount))
+                       continue;
+
+               orig_ifinfo = tmp;
+               break;
+       }
+       rcu_read_unlock();
+
+       return orig_ifinfo;
+}
+
+/**
+ * batadv_orig_ifinfo_new - search and possibly create an orig_ifinfo object
+ * @orig_node: the orig node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * Returns NULL in case of failure or the orig_ifinfo object for the if_outgoing
+ * interface otherwise. The object is created and added to the list
+ * if it does not exist.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
+struct batadv_orig_ifinfo *
+batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
+                      struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_orig_ifinfo *orig_ifinfo = NULL;
+       unsigned long reset_time;
+
+       spin_lock_bh(&orig_node->neigh_list_lock);
+
+       orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
+       if (orig_ifinfo)
+               goto out;
+
+       orig_ifinfo = kzalloc(sizeof(*orig_ifinfo), GFP_ATOMIC);
+       if (!orig_ifinfo)
+               goto out;
+
+       if (if_outgoing != BATADV_IF_DEFAULT &&
+           !atomic_inc_not_zero(&if_outgoing->refcount)) {
+               kfree(orig_ifinfo);
+               orig_ifinfo = NULL;
+               goto out;
+       }
+
+       reset_time = jiffies - 1;
+       reset_time -= msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
+       orig_ifinfo->batman_seqno_reset = reset_time;
+       orig_ifinfo->if_outgoing = if_outgoing;
+       INIT_HLIST_NODE(&orig_ifinfo->list);
+       atomic_set(&orig_ifinfo->refcount, 2);
+       hlist_add_head_rcu(&orig_ifinfo->list,
+                          &orig_node->ifinfo_list);
+out:
+       spin_unlock_bh(&orig_node->neigh_list_lock);
+       return orig_ifinfo;
+}
+
+/**
+ * batadv_neigh_ifinfo_get - find the ifinfo from an neigh_node
+ * @neigh_node: the neigh node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * The object is returned with refcounter increased by 1.
+ *
+ * Returns the requested neigh_ifinfo or NULL if not found
+ */
+struct batadv_neigh_ifinfo *
+batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
+                       struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_neigh_ifinfo *neigh_ifinfo = NULL,
+                                  *tmp_neigh_ifinfo;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_neigh_ifinfo, &neigh->ifinfo_list,
+                                list) {
+               if (tmp_neigh_ifinfo->if_outgoing != if_outgoing)
+                       continue;
+
+               if (!atomic_inc_not_zero(&tmp_neigh_ifinfo->refcount))
+                       continue;
+
+               neigh_ifinfo = tmp_neigh_ifinfo;
+               break;
+       }
+       rcu_read_unlock();
+
+       return neigh_ifinfo;
+}
+
+/**
+ * batadv_neigh_ifinfo_new - search and possibly create an neigh_ifinfo object
+ * @neigh_node: the neigh node to be queried
+ * @if_outgoing: the interface for which the ifinfo should be acquired
+ *
+ * Returns NULL in case of failure or the neigh_ifinfo object for the
+ * if_outgoing interface otherwise. The object is created and added to the list
+ * if it does not exist.
+ *
+ * The object is returned with refcounter increased by 1.
+ */
+struct batadv_neigh_ifinfo *
+batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
+                       struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_neigh_ifinfo *neigh_ifinfo;
+
+       spin_lock_bh(&neigh->ifinfo_lock);
+
+       neigh_ifinfo = batadv_neigh_ifinfo_get(neigh, if_outgoing);
+       if (neigh_ifinfo)
+               goto out;
+
+       neigh_ifinfo = kzalloc(sizeof(*neigh_ifinfo), GFP_ATOMIC);
+       if (!neigh_ifinfo)
+               goto out;
+
+       if (if_outgoing && !atomic_inc_not_zero(&if_outgoing->refcount)) {
+               kfree(neigh_ifinfo);
+               neigh_ifinfo = NULL;
+               goto out;
+       }
+
+       INIT_HLIST_NODE(&neigh_ifinfo->list);
+       atomic_set(&neigh_ifinfo->refcount, 2);
+       neigh_ifinfo->if_outgoing = if_outgoing;
+
+       hlist_add_head_rcu(&neigh_ifinfo->list, &neigh->ifinfo_list);
+
+out:
+       spin_unlock_bh(&neigh->ifinfo_lock);
+
+       return neigh_ifinfo;
+}
+
+/**
  * batadv_neigh_node_new - create and init a new neigh_node object
  * @hard_iface: the interface where the neighbour is connected to
  * @neigh_addr: the mac address of the neighbour interface
@@ -193,13 +443,13 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
                goto out;
 
        INIT_HLIST_NODE(&neigh_node->list);
+       INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
+       spin_lock_init(&neigh_node->ifinfo_lock);
 
        memcpy(neigh_node->addr, neigh_addr, ETH_ALEN);
        neigh_node->if_incoming = hard_iface;
        neigh_node->orig_node = orig_node;
 
-       INIT_LIST_HEAD(&neigh_node->bonding_list);
-
        /* extra reference for return */
        atomic_set(&neigh_node->refcount, 2);
 
@@ -207,30 +457,68 @@ out:
        return neigh_node;
 }
 
+/**
+ * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
+ * @rcu: rcu pointer of the orig_ifinfo object
+ */
+static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu)
+{
+       struct batadv_orig_ifinfo *orig_ifinfo;
+
+       orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
+
+       if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT)
+               batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
+
+       kfree(orig_ifinfo);
+}
+
+/**
+ * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
+ *  the orig_ifinfo (without rcu callback)
+ * @orig_ifinfo: the orig_ifinfo object to release
+ */
+static void
+batadv_orig_ifinfo_free_ref_now(struct batadv_orig_ifinfo *orig_ifinfo)
+{
+       if (atomic_dec_and_test(&orig_ifinfo->refcount))
+               batadv_orig_ifinfo_free_rcu(&orig_ifinfo->rcu);
+}
+
+/**
+ * batadv_orig_ifinfo_free_ref - decrement the refcounter and possibly free
+ *  the orig_ifinfo
+ * @orig_ifinfo: the orig_ifinfo object to release
+ */
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo)
+{
+       if (atomic_dec_and_test(&orig_ifinfo->refcount))
+               call_rcu(&orig_ifinfo->rcu, batadv_orig_ifinfo_free_rcu);
+}
+
 static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
 {
        struct hlist_node *node_tmp;
-       struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
+       struct batadv_neigh_node *neigh_node;
        struct batadv_orig_node *orig_node;
+       struct batadv_orig_ifinfo *orig_ifinfo;
 
        orig_node = container_of(rcu, struct batadv_orig_node, rcu);
 
        spin_lock_bh(&orig_node->neigh_list_lock);
 
-       /* for all bonding members ... */
-       list_for_each_entry_safe(neigh_node, tmp_neigh_node,
-                                &orig_node->bond_list, bonding_list) {
-               list_del_rcu(&neigh_node->bonding_list);
-               batadv_neigh_node_free_ref(neigh_node);
-       }
-
        /* for all neighbors towards this originator ... */
        hlist_for_each_entry_safe(neigh_node, node_tmp,
                                  &orig_node->neigh_list, list) {
                hlist_del_rcu(&neigh_node->list);
-               batadv_neigh_node_free_ref(neigh_node);
+               batadv_neigh_node_free_ref_now(neigh_node);
        }
 
+       hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
+                                 &orig_node->ifinfo_list, list) {
+               hlist_del_rcu(&orig_ifinfo->list);
+               batadv_orig_ifinfo_free_ref_now(orig_ifinfo);
+       }
        spin_unlock_bh(&orig_node->neigh_list_lock);
 
        /* Free nc_nodes */
@@ -327,8 +615,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
                return NULL;
 
        INIT_HLIST_HEAD(&orig_node->neigh_list);
-       INIT_LIST_HEAD(&orig_node->bond_list);
        INIT_LIST_HEAD(&orig_node->vlan_list);
+       INIT_HLIST_HEAD(&orig_node->ifinfo_list);
        spin_lock_init(&orig_node->bcast_seqno_lock);
        spin_lock_init(&orig_node->neigh_list_lock);
        spin_lock_init(&orig_node->tt_buff_lock);
@@ -344,15 +632,11 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
        orig_node->bat_priv = bat_priv;
        memcpy(orig_node->orig, addr, ETH_ALEN);
        batadv_dat_init_orig_node_addr(orig_node);
-       orig_node->router = NULL;
        atomic_set(&orig_node->last_ttvn, 0);
        orig_node->tt_buff = NULL;
        orig_node->tt_buff_len = 0;
        reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
        orig_node->bcast_seqno_reset = reset_time;
-       orig_node->batman_seqno_reset = reset_time;
-
-       atomic_set(&orig_node->bond_candidates, 0);
 
        /* create a vlan object for the "untagged" LAN */
        vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
@@ -376,20 +660,76 @@ free_orig_node:
        return NULL;
 }
 
+/**
+ * batadv_purge_orig_ifinfo - purge obsolete ifinfo entries from originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ *
+ * Returns true if any ifinfo entry was purged, false otherwise.
+ */
+static bool
+batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
+                        struct batadv_orig_node *orig_node)
+{
+       struct batadv_orig_ifinfo *orig_ifinfo;
+       struct batadv_hard_iface *if_outgoing;
+       struct hlist_node *node_tmp;
+       bool ifinfo_purged = false;
+
+       spin_lock_bh(&orig_node->neigh_list_lock);
+
+       /* for all ifinfo objects for this originator */
+       hlist_for_each_entry_safe(orig_ifinfo, node_tmp,
+                                 &orig_node->ifinfo_list, list) {
+               if_outgoing = orig_ifinfo->if_outgoing;
+
+               /* always keep the default interface */
+               if (if_outgoing == BATADV_IF_DEFAULT)
+                       continue;
+
+               /* don't purge if the interface is not (going) down */
+               if ((if_outgoing->if_status != BATADV_IF_INACTIVE) &&
+                   (if_outgoing->if_status != BATADV_IF_NOT_IN_USE) &&
+                   (if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED))
+                       continue;
+
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "router/ifinfo purge: originator %pM, iface: %s\n",
+                          orig_node->orig, if_outgoing->net_dev->name);
+
+               ifinfo_purged = true;
+
+               hlist_del_rcu(&orig_ifinfo->list);
+               batadv_orig_ifinfo_free_ref(orig_ifinfo);
+               if (orig_node->last_bonding_candidate == orig_ifinfo) {
+                       orig_node->last_bonding_candidate = NULL;
+                       batadv_orig_ifinfo_free_ref(orig_ifinfo);
+               }
+       }
+
+       spin_unlock_bh(&orig_node->neigh_list_lock);
+
+       return ifinfo_purged;
+}
+
+
+/**
+ * batadv_purge_orig_neighbors - purges neighbors from originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ *
+ * Returns true if any neighbor was purged, false otherwise
+ */
 static bool
 batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
-                           struct batadv_orig_node *orig_node,
-                           struct batadv_neigh_node **best_neigh)
+                           struct batadv_orig_node *orig_node)
 {
-       struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
        struct hlist_node *node_tmp;
        struct batadv_neigh_node *neigh_node;
        bool neigh_purged = false;
        unsigned long last_seen;
        struct batadv_hard_iface *if_incoming;
 
-       *best_neigh = NULL;
-
        spin_lock_bh(&orig_node->neigh_list_lock);
 
        /* for all neighbors towards this originator ... */
@@ -418,15 +758,7 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
                        neigh_purged = true;
 
                        hlist_del_rcu(&neigh_node->list);
-                       batadv_bonding_candidate_del(orig_node, neigh_node);
                        batadv_neigh_node_free_ref(neigh_node);
-               } else {
-                       /* store the best_neighbour if this is the first
-                        * iteration or if a better neighbor has been found
-                        */
-                       if (!*best_neigh ||
-                           bao->bat_neigh_cmp(neigh_node, *best_neigh) > 0)
-                               *best_neigh = neigh_node;
                }
        }
 
@@ -434,10 +766,57 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
        return neigh_purged;
 }
 
+/**
+ * batadv_find_best_neighbor - finds the best neighbor after purging
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ * @if_outgoing: the interface for which the metric should be compared
+ *
+ * Returns the current best neighbor, with refcount increased.
+ */
+static struct batadv_neigh_node *
+batadv_find_best_neighbor(struct batadv_priv *bat_priv,
+                         struct batadv_orig_node *orig_node,
+                         struct batadv_hard_iface *if_outgoing)
+{
+       struct batadv_neigh_node *best = NULL, *neigh;
+       struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(neigh, &orig_node->neigh_list, list) {
+               if (best && (bao->bat_neigh_cmp(neigh, if_outgoing,
+                                               best, if_outgoing) <= 0))
+                       continue;
+
+               if (!atomic_inc_not_zero(&neigh->refcount))
+                       continue;
+
+               if (best)
+                       batadv_neigh_node_free_ref(best);
+
+               best = neigh;
+       }
+       rcu_read_unlock();
+
+       return best;
+}
+
+/**
+ * batadv_purge_orig_node - purges obsolete information from an orig_node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be checked
+ *
+ * This function checks if the orig_node or substructures of it have become
+ * obsolete, and purges this information if that's the case.
+ *
+ * Returns true if the orig_node is to be removed, false otherwise.
+ */
 static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                                   struct batadv_orig_node *orig_node)
 {
        struct batadv_neigh_node *best_neigh_node;
+       struct batadv_hard_iface *hard_iface;
+       bool changed;
 
        if (batadv_has_timed_out(orig_node->last_seen,
                                 2 * BATADV_PURGE_TIMEOUT)) {
@@ -446,12 +825,39 @@ static bool batadv_purge_orig_node(struct batadv_priv *bat_priv,
                           orig_node->orig,
                           jiffies_to_msecs(orig_node->last_seen));
                return true;
-       } else {
-               if (batadv_purge_orig_neighbors(bat_priv, orig_node,
-                                               &best_neigh_node))
-                       batadv_update_route(bat_priv, orig_node,
-                                           best_neigh_node);
        }
+       changed = batadv_purge_orig_ifinfo(bat_priv, orig_node);
+       changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node);
+
+       if (!changed)
+               return false;
+
+       /* first for NULL ... */
+       best_neigh_node = batadv_find_best_neighbor(bat_priv, orig_node,
+                                                   BATADV_IF_DEFAULT);
+       batadv_update_route(bat_priv, orig_node, BATADV_IF_DEFAULT,
+                           best_neigh_node);
+       if (best_neigh_node)
+               batadv_neigh_node_free_ref(best_neigh_node);
+
+       /* ... then for all other interfaces. */
+       rcu_read_lock();
+       list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+               if (hard_iface->if_status != BATADV_IF_ACTIVE)
+                       continue;
+
+               if (hard_iface->soft_iface != bat_priv->soft_iface)
+                       continue;
+
+               best_neigh_node = batadv_find_best_neighbor(bat_priv,
+                                                           orig_node,
+                                                           hard_iface);
+               batadv_update_route(bat_priv, orig_node, hard_iface,
+                                   best_neigh_node);
+               if (best_neigh_node)
+                       batadv_neigh_node_free_ref(best_neigh_node);
+       }
+       rcu_read_unlock();
 
        return false;
 }
@@ -534,8 +940,54 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset)
                return 0;
        }
 
-       bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq);
+       bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq,
+                                              BATADV_IF_DEFAULT);
+
+       return 0;
+}
+
+/**
+ * batadv_orig_hardif_seq_print_text - writes originator infos for a specific
+ *  outgoing interface
+ * @seq: debugfs table seq_file struct
+ * @offset: not used
+ *
+ * Returns 0
+ */
+int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset)
+{
+       struct net_device *net_dev = (struct net_device *)seq->private;
+       struct batadv_hard_iface *hard_iface;
+       struct batadv_priv *bat_priv;
+
+       hard_iface = batadv_hardif_get_by_netdev(net_dev);
+
+       if (!hard_iface || !hard_iface->soft_iface) {
+               seq_puts(seq, "Interface not known to B.A.T.M.A.N.\n");
+               goto out;
+       }
+
+       bat_priv = netdev_priv(hard_iface->soft_iface);
+       if (!bat_priv->bat_algo_ops->bat_orig_print) {
+               seq_puts(seq,
+                        "No printing function for this routing protocol\n");
+               goto out;
+       }
+
+       if (hard_iface->if_status != BATADV_IF_ACTIVE) {
+               seq_puts(seq, "Interface not active\n");
+               goto out;
+       }
 
+       seq_printf(seq, "[B.A.T.M.A.N. adv %s, IF/MAC: %s/%pM (%s %s)]\n",
+                  BATADV_SOURCE_VERSION, hard_iface->net_dev->name,
+                  hard_iface->net_dev->dev_addr,
+                  hard_iface->soft_iface->name, bat_priv->bat_algo_ops->name);
+
+       bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, hard_iface);
+
+out:
+       batadv_hardif_free_ref(hard_iface);
        return 0;
 }
 
index 6f77d80..37be290 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_ORIGINATOR_H_
@@ -36,8 +34,26 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
                      struct batadv_orig_node *orig_node);
 void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node);
 struct batadv_neigh_node *
-batadv_orig_node_get_router(struct batadv_orig_node *orig_node);
+batadv_orig_router_get(struct batadv_orig_node *orig_node,
+                      const struct batadv_hard_iface *if_outgoing);
+struct batadv_neigh_ifinfo *
+batadv_neigh_ifinfo_new(struct batadv_neigh_node *neigh,
+                       struct batadv_hard_iface *if_outgoing);
+struct batadv_neigh_ifinfo *
+batadv_neigh_ifinfo_get(struct batadv_neigh_node *neigh,
+                       struct batadv_hard_iface *if_outgoing);
+void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo);
+
+struct batadv_orig_ifinfo *
+batadv_orig_ifinfo_get(struct batadv_orig_node *orig_node,
+                      struct batadv_hard_iface *if_outgoing);
+struct batadv_orig_ifinfo *
+batadv_orig_ifinfo_new(struct batadv_orig_node *orig_node,
+                      struct batadv_hard_iface *if_outgoing);
+void batadv_orig_ifinfo_free_ref(struct batadv_orig_ifinfo *orig_ifinfo);
+
 int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
+int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
                            int max_if_num);
 int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
index 2dd8f24..0a381d1 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_PACKET_H_
@@ -117,6 +115,7 @@ enum batadv_tt_client_flags {
        BATADV_TT_CLIENT_DEL     = BIT(0),
        BATADV_TT_CLIENT_ROAM    = BIT(1),
        BATADV_TT_CLIENT_WIFI    = BIT(4),
+       BATADV_TT_CLIENT_ISOLA   = BIT(5),
        BATADV_TT_CLIENT_NOPURGE = BIT(8),
        BATADV_TT_CLIENT_NEW     = BIT(9),
        BATADV_TT_CLIENT_PENDING = BIT(10),
index 46278bf..1ed9f7c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
 static int batadv_route_unicast_packet(struct sk_buff *skb,
                                       struct batadv_hard_iface *recv_if);
 
+/**
+ * _batadv_update_route - set the router for this originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be configured
+ * @recv_if: the receive interface for which this route is set
+ * @neigh_node: neighbor which should be the next router
+ *
+ * This function does not perform any error checks
+ */
 static void _batadv_update_route(struct batadv_priv *bat_priv,
                                 struct batadv_orig_node *orig_node,
+                                struct batadv_hard_iface *recv_if,
                                 struct batadv_neigh_node *neigh_node)
 {
+       struct batadv_orig_ifinfo *orig_ifinfo;
        struct batadv_neigh_node *curr_router;
 
-       curr_router = batadv_orig_node_get_router(orig_node);
+       orig_ifinfo = batadv_orig_ifinfo_get(orig_node, recv_if);
+       if (!orig_ifinfo)
+               return;
+
+       rcu_read_lock();
+       curr_router = rcu_dereference(orig_ifinfo->router);
+       if (curr_router && !atomic_inc_not_zero(&curr_router->refcount))
+               curr_router = NULL;
+       rcu_read_unlock();
 
        /* route deleted */
        if ((curr_router) && (!neigh_node)) {
@@ -71,16 +88,25 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
                neigh_node = NULL;
 
        spin_lock_bh(&orig_node->neigh_list_lock);
-       rcu_assign_pointer(orig_node->router, neigh_node);
+       rcu_assign_pointer(orig_ifinfo->router, neigh_node);
        spin_unlock_bh(&orig_node->neigh_list_lock);
+       batadv_orig_ifinfo_free_ref(orig_ifinfo);
 
        /* decrease refcount of previous best neighbor */
        if (curr_router)
                batadv_neigh_node_free_ref(curr_router);
 }
 
+/**
+ * batadv_update_route - set the router for this originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: orig node which is to be configured
+ * @recv_if: the receive interface for which this route is set
+ * @neigh_node: neighbor which should be the next router
+ */
 void batadv_update_route(struct batadv_priv *bat_priv,
                         struct batadv_orig_node *orig_node,
+                        struct batadv_hard_iface *recv_if,
                         struct batadv_neigh_node *neigh_node)
 {
        struct batadv_neigh_node *router = NULL;
@@ -88,125 +114,16 @@ void batadv_update_route(struct batadv_priv *bat_priv,
        if (!orig_node)
                goto out;
 
-       router = batadv_orig_node_get_router(orig_node);
+       router = batadv_orig_router_get(orig_node, recv_if);
 
        if (router != neigh_node)
-               _batadv_update_route(bat_priv, orig_node, neigh_node);
+               _batadv_update_route(bat_priv, orig_node, recv_if, neigh_node);
 
 out:
        if (router)
                batadv_neigh_node_free_ref(router);
 }
 
-/* caller must hold the neigh_list_lock */
-void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node,
-                                 struct batadv_neigh_node *neigh_node)
-{
-       /* this neighbor is not part of our candidate list */
-       if (list_empty(&neigh_node->bonding_list))
-               goto out;
-
-       list_del_rcu(&neigh_node->bonding_list);
-       INIT_LIST_HEAD(&neigh_node->bonding_list);
-       batadv_neigh_node_free_ref(neigh_node);
-       atomic_dec(&orig_node->bond_candidates);
-
-out:
-       return;
-}
-
-/**
- * batadv_bonding_candidate_add - consider a new link for bonding mode towards
- *  the given originator
- * @bat_priv: the bat priv with all the soft interface information
- * @orig_node: the target node
- * @neigh_node: the neighbor representing the new link to consider for bonding
- *  mode
- */
-void batadv_bonding_candidate_add(struct batadv_priv *bat_priv,
-                                 struct batadv_orig_node *orig_node,
-                                 struct batadv_neigh_node *neigh_node)
-{
-       struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
-       struct batadv_neigh_node *tmp_neigh_node, *router = NULL;
-       uint8_t interference_candidate = 0;
-
-       spin_lock_bh(&orig_node->neigh_list_lock);
-
-       /* only consider if it has the same primary address ...  */
-       if (!batadv_compare_eth(orig_node->orig,
-                               neigh_node->orig_node->primary_addr))
-               goto candidate_del;
-
-       router = batadv_orig_node_get_router(orig_node);
-       if (!router)
-               goto candidate_del;
-
-
-       /* ... and is good enough to be considered */
-       if (bao->bat_neigh_is_equiv_or_better(neigh_node, router))
-               goto candidate_del;
-
-       /* check if we have another candidate with the same mac address or
-        * interface. If we do, we won't select this candidate because of
-        * possible interference.
-        */
-       hlist_for_each_entry_rcu(tmp_neigh_node,
-                                &orig_node->neigh_list, list) {
-               if (tmp_neigh_node == neigh_node)
-                       continue;
-
-               /* we only care if the other candidate is even
-                * considered as candidate.
-                */
-               if (list_empty(&tmp_neigh_node->bonding_list))
-                       continue;
-
-               if ((neigh_node->if_incoming == tmp_neigh_node->if_incoming) ||
-                   (batadv_compare_eth(neigh_node->addr,
-                                       tmp_neigh_node->addr))) {
-                       interference_candidate = 1;
-                       break;
-               }
-       }
-
-       /* don't care further if it is an interference candidate */
-       if (interference_candidate)
-               goto candidate_del;
-
-       /* this neighbor already is part of our candidate list */
-       if (!list_empty(&neigh_node->bonding_list))
-               goto out;
-
-       if (!atomic_inc_not_zero(&neigh_node->refcount))
-               goto out;
-
-       list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list);
-       atomic_inc(&orig_node->bond_candidates);
-       goto out;
-
-candidate_del:
-       batadv_bonding_candidate_del(orig_node, neigh_node);
-
-out:
-       spin_unlock_bh(&orig_node->neigh_list_lock);
-
-       if (router)
-               batadv_neigh_node_free_ref(router);
-}
-
-/* copy primary address for bonding */
-void
-batadv_bonding_save_primary(const struct batadv_orig_node *orig_node,
-                           struct batadv_orig_node *orig_neigh_node,
-                           const struct batadv_ogm_packet *batman_ogm_packet)
-{
-       if (!(batman_ogm_packet->flags & BATADV_PRIMARIES_FIRST_HOP))
-               return;
-
-       memcpy(orig_neigh_node->primary_addr, orig_node->orig, ETH_ALEN);
-}
-
 /* checks whether the host restarted and is in the protection time.
  * returns:
  *  0 if the packet is to be accepted
@@ -461,114 +378,6 @@ out:
        return ret;
 }
 
-/* In the bonding case, send the packets in a round
- * robin fashion over the remaining interfaces.
- *
- * This method rotates the bonding list and increases the
- * returned router's refcount.
- */
-static struct batadv_neigh_node *
-batadv_find_bond_router(struct batadv_orig_node *primary_orig,
-                       const struct batadv_hard_iface *recv_if)
-{
-       struct batadv_neigh_node *tmp_neigh_node;
-       struct batadv_neigh_node *router = NULL, *first_candidate = NULL;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
-                               bonding_list) {
-               if (!first_candidate)
-                       first_candidate = tmp_neigh_node;
-
-               /* recv_if == NULL on the first node. */
-               if (tmp_neigh_node->if_incoming == recv_if)
-                       continue;
-
-               if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
-                       continue;
-
-               router = tmp_neigh_node;
-               break;
-       }
-
-       /* use the first candidate if nothing was found. */
-       if (!router && first_candidate &&
-           atomic_inc_not_zero(&first_candidate->refcount))
-               router = first_candidate;
-
-       if (!router)
-               goto out;
-
-       /* selected should point to the next element
-        * after the current router
-        */
-       spin_lock_bh(&primary_orig->neigh_list_lock);
-       /* this is a list_move(), which unfortunately
-        * does not exist as rcu version
-        */
-       list_del_rcu(&primary_orig->bond_list);
-       list_add_rcu(&primary_orig->bond_list,
-                    &router->bonding_list);
-       spin_unlock_bh(&primary_orig->neigh_list_lock);
-
-out:
-       rcu_read_unlock();
-       return router;
-}
-
-/**
- * batadv_find_ifalter_router - find the best of the remaining candidates which
- *  are not using this interface
- * @bat_priv: the bat priv with all the soft interface information
- * @primary_orig: the destination
- * @recv_if: the interface that the router returned by this function has to not
- *  use
- *
- * Returns the best candidate towards primary_orig that is not using recv_if.
- * Increases the returned neighbor's refcount
- */
-static struct batadv_neigh_node *
-batadv_find_ifalter_router(struct batadv_priv *bat_priv,
-                          struct batadv_orig_node *primary_orig,
-                          const struct batadv_hard_iface *recv_if)
-{
-       struct batadv_neigh_node *router = NULL, *first_candidate = NULL;
-       struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
-       struct batadv_neigh_node *tmp_neigh_node;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
-                               bonding_list) {
-               if (!first_candidate)
-                       first_candidate = tmp_neigh_node;
-
-               /* recv_if == NULL on the first node. */
-               if (tmp_neigh_node->if_incoming == recv_if)
-                       continue;
-
-               if (router && bao->bat_neigh_cmp(tmp_neigh_node, router))
-                       continue;
-
-               if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
-                       continue;
-
-               /* decrement refcount of previously selected router */
-               if (router)
-                       batadv_neigh_node_free_ref(router);
-
-               /* we found a better router (or at least one valid router) */
-               router = tmp_neigh_node;
-       }
-
-       /* use the first candidate if nothing was found. */
-       if (!router && first_candidate &&
-           atomic_inc_not_zero(&first_candidate->refcount))
-               router = first_candidate;
-
-       rcu_read_unlock();
-       return router;
-}
-
 /**
  * batadv_check_unicast_packet - Check for malformed unicast packets
  * @bat_priv: the bat priv with all the soft interface information
@@ -606,95 +415,141 @@ static int batadv_check_unicast_packet(struct batadv_priv *bat_priv,
        return 0;
 }
 
-/* find a suitable router for this originator, and use
- * bonding if possible. increases the found neighbors
- * refcount.
+/**
+ * batadv_find_router - find a suitable router for this originator
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the destination node
+ * @recv_if: pointer to interface this packet was received on
+ *
+ * Returns the router which should be used for this orig_node on
+ * this interface, or NULL if not available.
  */
 struct batadv_neigh_node *
 batadv_find_router(struct batadv_priv *bat_priv,
                   struct batadv_orig_node *orig_node,
-                  const struct batadv_hard_iface *recv_if)
+                  struct batadv_hard_iface *recv_if)
 {
-       struct batadv_orig_node *primary_orig_node;
-       struct batadv_orig_node *router_orig;
-       struct batadv_neigh_node *router;
-       static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
-       int bonding_enabled;
-       uint8_t *primary_addr;
+       struct batadv_algo_ops *bao = bat_priv->bat_algo_ops;
+       struct batadv_neigh_node *first_candidate_router = NULL;
+       struct batadv_neigh_node *next_candidate_router = NULL;
+       struct batadv_neigh_node *router, *cand_router = NULL;
+       struct batadv_neigh_node *last_cand_router = NULL;
+       struct batadv_orig_ifinfo *cand, *first_candidate = NULL;
+       struct batadv_orig_ifinfo *next_candidate = NULL;
+       struct batadv_orig_ifinfo *last_candidate;
+       bool last_candidate_found = false;
 
        if (!orig_node)
                return NULL;
 
-       router = batadv_orig_node_get_router(orig_node);
-       if (!router)
-               goto err;
+       router = batadv_orig_router_get(orig_node, recv_if);
 
-       /* without bonding, the first node should
-        * always choose the default router.
+       /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop)
+        * and if activated.
+        */
+       if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) ||
+           !router)
+               return router;
+
+       /* bonding: loop through the list of possible routers found
+        * for the various outgoing interfaces and find a candidate after
+        * the last chosen bonding candidate (next_candidate). If no such
+        * router is found, use the first candidate found (the previously
+        * chosen bonding candidate might have been the last one in the list).
+        * If this can't be found either, return the previously choosen
+        * router - obviously there are no other candidates.
         */
-       bonding_enabled = atomic_read(&bat_priv->bonding);
-
        rcu_read_lock();
-       /* select default router to output */
-       router_orig = router->orig_node;
-       if (!router_orig)
-               goto err_unlock;
+       last_candidate = orig_node->last_bonding_candidate;
+       if (last_candidate)
+               last_cand_router = rcu_dereference(last_candidate->router);
 
-       if ((!recv_if) && (!bonding_enabled))
-               goto return_router;
+       hlist_for_each_entry_rcu(cand, &orig_node->ifinfo_list, list) {
+               /* acquire some structures and references ... */
+               if (!atomic_inc_not_zero(&cand->refcount))
+                       continue;
 
-       primary_addr = router_orig->primary_addr;
+               cand_router = rcu_dereference(cand->router);
+               if (!cand_router)
+                       goto next;
 
-       /* if we have something in the primary_addr, we can search
-        * for a potential bonding candidate.
-        */
-       if (batadv_compare_eth(primary_addr, zero_mac))
-               goto return_router;
+               if (!atomic_inc_not_zero(&cand_router->refcount)) {
+                       cand_router = NULL;
+                       goto next;
+               }
 
-       /* find the orig_node which has the primary interface. might
-        * even be the same as our router_orig in many cases
-        */
-       if (batadv_compare_eth(primary_addr, router_orig->orig)) {
-               primary_orig_node = router_orig;
-       } else {
-               primary_orig_node = batadv_orig_hash_find(bat_priv,
-                                                         primary_addr);
-               if (!primary_orig_node)
-                       goto return_router;
+               /* alternative candidate should be good enough to be
+                * considered
+                */
+               if (!bao->bat_neigh_is_equiv_or_better(cand_router,
+                                                      cand->if_outgoing,
+                                                      router, recv_if))
+                       goto next;
+
+               /* don't use the same router twice */
+               if (last_cand_router == cand_router)
+                       goto next;
+
+               /* mark the first possible candidate */
+               if (!first_candidate) {
+                       atomic_inc(&cand_router->refcount);
+                       atomic_inc(&cand->refcount);
+                       first_candidate = cand;
+                       first_candidate_router = cand_router;
+               }
+
+               /* check if the loop has already passed the previously selected
+                * candidate ... this function should select the next candidate
+                * AFTER the previously used bonding candidate.
+                */
+               if (!last_candidate || last_candidate_found) {
+                       next_candidate = cand;
+                       next_candidate_router = cand_router;
+                       break;
+               }
 
-               batadv_orig_node_free_ref(primary_orig_node);
+               if (last_candidate == cand)
+                       last_candidate_found = true;
+next:
+               /* free references */
+               if (cand_router) {
+                       batadv_neigh_node_free_ref(cand_router);
+                       cand_router = NULL;
+               }
+               batadv_orig_ifinfo_free_ref(cand);
        }
+       rcu_read_unlock();
 
-       /* with less than 2 candidates, we can't do any
-        * bonding and prefer the original router.
-        */
-       if (atomic_read(&primary_orig_node->bond_candidates) < 2)
-               goto return_router;
+       /* last_bonding_candidate is reset below, remove the old reference. */
+       if (orig_node->last_bonding_candidate)
+               batadv_orig_ifinfo_free_ref(orig_node->last_bonding_candidate);
 
-       /* all nodes between should choose a candidate which
-        * is is not on the interface where the packet came
-        * in.
+       /* After finding candidates, handle the three cases:
+        * 1) there is a next candidate, use that
+        * 2) there is no next candidate, use the first of the list
+        * 3) there is no candidate at all, return the default router
         */
-       batadv_neigh_node_free_ref(router);
+       if (next_candidate) {
+               batadv_neigh_node_free_ref(router);
 
-       if (bonding_enabled)
-               router = batadv_find_bond_router(primary_orig_node, recv_if);
-       else
-               router = batadv_find_ifalter_router(bat_priv, primary_orig_node,
-                                                   recv_if);
+               /* remove references to first candidate, we don't need it. */
+               if (first_candidate) {
+                       batadv_neigh_node_free_ref(first_candidate_router);
+                       batadv_orig_ifinfo_free_ref(first_candidate);
+               }
+               router = next_candidate_router;
+               orig_node->last_bonding_candidate = next_candidate;
+       } else if (first_candidate) {
+               batadv_neigh_node_free_ref(router);
 
-return_router:
-       if (router && router->if_incoming->if_status != BATADV_IF_ACTIVE)
-               goto err_unlock;
+               /* refcounting has already been done in the loop above. */
+               router = first_candidate_router;
+               orig_node->last_bonding_candidate = first_candidate;
+       } else {
+               orig_node->last_bonding_candidate = NULL;
+       }
 
-       rcu_read_unlock();
        return router;
-err_unlock:
-       rcu_read_unlock();
-err:
-       if (router)
-               batadv_neigh_node_free_ref(router);
-       return NULL;
 }
 
 static int batadv_route_unicast_packet(struct sk_buff *skb,
@@ -1135,6 +990,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
        int hdr_size = sizeof(*bcast_packet);
        int ret = NET_RX_DROP;
        int32_t seq_diff;
+       uint32_t seqno;
 
        /* drop packet if it has not necessary minimum size */
        if (unlikely(!pskb_may_pull(skb, hdr_size)))
@@ -1170,12 +1026,13 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
 
        spin_lock_bh(&orig_node->bcast_seqno_lock);
 
+       seqno = ntohl(bcast_packet->seqno);
        /* check whether the packet is a duplicate */
        if (batadv_test_bit(orig_node->bcast_bits, orig_node->last_bcast_seqno,
-                           ntohl(bcast_packet->seqno)))
+                           seqno))
                goto spin_unlock;
 
-       seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
+       seq_diff = seqno - orig_node->last_bcast_seqno;
 
        /* check whether the packet is old and the host just restarted. */
        if (batadv_window_protected(bat_priv, seq_diff,
@@ -1186,7 +1043,7 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
         * if required.
         */
        if (batadv_bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
-               orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
+               orig_node->last_bcast_seqno = seqno;
 
        spin_unlock_bh(&orig_node->bcast_seqno_lock);
 
index 19544dd..557d3d1 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_ROUTING_H_
@@ -25,6 +23,7 @@ bool batadv_check_management_packet(struct sk_buff *skb,
                                    int header_len);
 void batadv_update_route(struct batadv_priv *bat_priv,
                         struct batadv_orig_node *orig_node,
+                        struct batadv_hard_iface *recv_if,
                         struct batadv_neigh_node *neigh_node);
 int batadv_recv_icmp_packet(struct sk_buff *skb,
                            struct batadv_hard_iface *recv_if);
@@ -45,16 +44,7 @@ int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
 struct batadv_neigh_node *
 batadv_find_router(struct batadv_priv *bat_priv,
                   struct batadv_orig_node *orig_node,
-                  const struct batadv_hard_iface *recv_if);
-void batadv_bonding_candidate_del(struct batadv_orig_node *orig_node,
-                                 struct batadv_neigh_node *neigh_node);
-void batadv_bonding_candidate_add(struct batadv_priv *bat_priv,
-                                 struct batadv_orig_node *orig_node,
-                                 struct batadv_neigh_node *neigh_node);
-void batadv_bonding_save_primary(const struct batadv_orig_node *orig_node,
-                                struct batadv_orig_node *orig_neigh_node,
-                                const struct batadv_ogm_packet
-                                *batman_ogm_packet);
+                  struct batadv_hard_iface *recv_if);
 int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff,
                            unsigned long *last_reset);
 
index fba4dcf..579f5f0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -321,13 +319,23 @@ out:
  */
 int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
                                   struct sk_buff *skb, int packet_type,
-                                  int packet_subtype, unsigned short vid)
+                                  int packet_subtype, uint8_t *dst_hint,
+                                  unsigned short vid)
 {
        struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
        struct batadv_orig_node *orig_node;
+       uint8_t *src, *dst;
+
+       src = ethhdr->h_source;
+       dst = ethhdr->h_dest;
+
+       /* if we got an hint! let's send the packet to this client (if any) */
+       if (dst_hint) {
+               src = NULL;
+               dst = dst_hint;
+       }
+       orig_node = batadv_transtable_search(bat_priv, src, dst, vid);
 
-       orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
-                                            ethhdr->h_dest, vid);
        return batadv_send_skb_unicast(bat_priv, skb, packet_type,
                                       packet_subtype, orig_node, vid);
 }
@@ -379,6 +387,8 @@ static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
                kfree_skb(forw_packet->skb);
        if (forw_packet->if_incoming)
                batadv_hardif_free_ref(forw_packet->if_incoming);
+       if (forw_packet->if_outgoing)
+               batadv_hardif_free_ref(forw_packet->if_outgoing);
        kfree(forw_packet);
 }
 
@@ -442,6 +452,7 @@ int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
 
        forw_packet->skb = newskb;
        forw_packet->if_incoming = primary_if;
+       forw_packet->if_outgoing = NULL;
 
        /* how often did we send the bcast packet ? */
        forw_packet->num_packets = 0;
@@ -537,11 +548,16 @@ void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
 
        bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
 
-       /* we have to have at least one packet in the queue
-        * to determine the queues wake up time unless we are
-        * shutting down
+       /* we have to have at least one packet in the queue to determine the
+        * queues wake up time unless we are shutting down.
+        *
+        * only re-schedule if this is the "original" copy, e.g. the OGM of the
+        * primary interface should only be rescheduled once per period, but
+        * this function will be called for the forw_packet instances of the
+        * other secondary interfaces as well.
         */
-       if (forw_packet->own)
+       if (forw_packet->own &&
+           forw_packet->if_incoming == forw_packet->if_outgoing)
                batadv_schedule_bat_ogm(forw_packet->if_incoming);
 
 out:
@@ -602,7 +618,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
                 * we delete only packets belonging to the given interface
                 */
                if ((hard_iface) &&
-                   (forw_packet->if_incoming != hard_iface))
+                   (forw_packet->if_incoming != hard_iface) &&
+                   (forw_packet->if_outgoing != hard_iface))
                        continue;
 
                spin_unlock_bh(&bat_priv->forw_bat_list_lock);
index aa2e253..aaddaa9 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_SEND_H_
@@ -40,7 +38,8 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
                                           int packet_subtype);
 int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
                                   struct sk_buff *skb, int packet_type,
-                                  int packet_subtype, unsigned short vid);
+                                  int packet_subtype, uint8_t *dst_hint,
+                                  unsigned short vid);
 int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
                           unsigned short vid);
 
@@ -57,11 +56,11 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
  * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
  */
 static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
-                                        struct sk_buff *skb,
+                                        struct sk_buff *skb, uint8_t *dst_hint,
                                         unsigned short vid)
 {
        return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0,
-                                             vid);
+                                             dst_hint, vid);
 }
 
 /**
@@ -81,11 +80,12 @@ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
 static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv,
                                               struct sk_buff *skb,
                                               int packet_subtype,
+                                              uint8_t *dst_hint,
                                               unsigned short vid)
 {
        return batadv_send_skb_via_tt_generic(bat_priv, skb,
                                              BATADV_UNICAST_4ADDR,
-                                             packet_subtype, vid);
+                                             packet_subtype, dst_hint, vid);
 }
 
 #endif /* _NET_BATMAN_ADV_SEND_H_ */
index a8f99d1..f82c267 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -121,7 +119,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
                batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS,
                                       "mac address changed", false);
                batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS,
-                                   BATADV_NULL_IFINDEX);
+                                   BATADV_NULL_IFINDEX, BATADV_NO_MARK);
        }
 
        return 0;
@@ -162,6 +160,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
                                                   0x00, 0x00};
        static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
                                                    0x00, 0x00};
+       enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
+       uint8_t *dst_hint = NULL, chaddr[ETH_ALEN];
        struct vlan_ethhdr *vhdr;
        unsigned int header_len = 0;
        int data_len = skb->len, ret;
@@ -169,6 +169,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
        bool do_bcast = false, client_added;
        unsigned short vid;
        uint32_t seqno;
+       int gw_mode;
 
        if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
                goto dropped;
@@ -198,7 +199,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
        /* Register the client MAC in the transtable */
        if (!is_multicast_ether_addr(ethhdr->h_source)) {
                client_added = batadv_tt_local_add(soft_iface, ethhdr->h_source,
-                                                  vid, skb->skb_iif);
+                                                  vid, skb->skb_iif,
+                                                  skb->mark);
                if (!client_added)
                        goto dropped;
        }
@@ -215,36 +217,39 @@ static int batadv_interface_tx(struct sk_buff *skb,
        if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
                goto dropped;
 
+       gw_mode = atomic_read(&bat_priv->gw_mode);
        if (is_multicast_ether_addr(ethhdr->h_dest)) {
-               do_bcast = true;
-
-               switch (atomic_read(&bat_priv->gw_mode)) {
-               case BATADV_GW_MODE_SERVER:
-                       /* gateway servers should not send dhcp
-                        * requests into the mesh
-                        */
-                       ret = batadv_gw_is_dhcp_target(skb, &header_len);
-                       if (ret)
-                               goto dropped;
-                       break;
-               case BATADV_GW_MODE_CLIENT:
-                       /* gateway clients should send dhcp requests
-                        * via unicast to their gateway
-                        */
-                       ret = batadv_gw_is_dhcp_target(skb, &header_len);
-                       if (ret)
-                               do_bcast = false;
-                       break;
-               case BATADV_GW_MODE_OFF:
-               default:
-                       break;
+               /* if gw mode is off, broadcast every packet */
+               if (gw_mode == BATADV_GW_MODE_OFF) {
+                       do_bcast = true;
+                       goto send;
                }
 
-               /* reminder: ethhdr might have become unusable from here on
-                * (batadv_gw_is_dhcp_target() might have reallocated skb data)
+               dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
+                                                       chaddr);
+               /* skb->data may have been modified by
+                * batadv_gw_dhcp_recipient_get()
                 */
+               ethhdr = (struct ethhdr *)skb->data;
+               /* if gw_mode is on, broadcast any non-DHCP message.
+                * All the DHCP packets are going to be sent as unicast
+                */
+               if (dhcp_rcp == BATADV_DHCP_NO) {
+                       do_bcast = true;
+                       goto send;
+               }
+
+               if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
+                       dst_hint = chaddr;
+               else if ((gw_mode == BATADV_GW_MODE_SERVER) &&
+                        (dhcp_rcp == BATADV_DHCP_TO_SERVER))
+                       /* gateways should not forward any DHCP message if
+                        * directed to a DHCP server
+                        */
+                       goto dropped;
        }
 
+send:
        batadv_skb_set_priority(skb, 0);
 
        /* ethernet packet should be broadcasted */
@@ -290,22 +295,22 @@ static int batadv_interface_tx(struct sk_buff *skb,
 
        /* unicast packet */
        } else {
-               if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
+               /* DHCP packets going to a server will use the GW feature */
+               if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
                        ret = batadv_gw_out_of_range(bat_priv, skb);
                        if (ret)
                                goto dropped;
-               }
-
-               if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
-                       goto dropped;
-
-               batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
-
-               if (is_multicast_ether_addr(ethhdr->h_dest))
                        ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
-               else
-                       ret = batadv_send_skb_via_tt(bat_priv, skb, vid);
+               } else {
+                       if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
+                                                                 skb))
+                               goto dropped;
 
+                       batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
+
+                       ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
+                                                    vid);
+               }
                if (ret == NET_XMIT_DROP)
                        goto dropped_freed;
        }
@@ -394,9 +399,23 @@ void batadv_interface_rx(struct net_device *soft_iface,
                batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
                                                     ethhdr->h_source, vid);
 
-       if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest,
-                                 vid))
+       if (is_multicast_ether_addr(ethhdr->h_dest)) {
+               /* set the mark on broadcast packets if AP isolation is ON and
+                * the packet is coming from an "isolated" client
+                */
+               if (batadv_vlan_ap_isola_get(bat_priv, vid) &&
+                   batadv_tt_global_is_isolated(bat_priv, ethhdr->h_source,
+                                                vid)) {
+                       /* save bits in skb->mark not covered by the mask and
+                        * apply the mark on the rest
+                        */
+                       skb->mark &= ~bat_priv->isolation_mark_mask;
+                       skb->mark |= bat_priv->isolation_mark;
+               }
+       } else if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source,
+                                        ethhdr->h_dest, vid)) {
                goto dropped;
+       }
 
        netif_rx(skb);
        goto out;
@@ -485,7 +504,7 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
         */
        batadv_tt_local_add(bat_priv->soft_iface,
                            bat_priv->soft_iface->dev_addr, vid,
-                           BATADV_NULL_IFINDEX);
+                           BATADV_NULL_IFINDEX, BATADV_NO_MARK);
 
        spin_lock_bh(&bat_priv->softif_vlan_list_lock);
        hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
@@ -678,7 +697,7 @@ static int batadv_softif_init_late(struct net_device *dev)
        atomic_set(&bat_priv->gw.bandwidth_down, 100);
        atomic_set(&bat_priv->gw.bandwidth_up, 20);
        atomic_set(&bat_priv->orig_interval, 1000);
-       atomic_set(&bat_priv->hop_penalty, 30);
+       atomic_set(&bat_priv->hop_penalty, 15);
 #ifdef CONFIG_BATMAN_ADV_DEBUG
        atomic_set(&bat_priv->log_level, 0);
 #endif
@@ -697,6 +716,8 @@ static int batadv_softif_init_late(struct net_device *dev)
 #endif
        bat_priv->tt.last_changeset = NULL;
        bat_priv->tt.last_changeset_len = 0;
+       bat_priv->isolation_mark = 0;
+       bat_priv->isolation_mark_mask = 0;
 
        /* randomize initial seqno to avoid collision */
        get_random_bytes(&random_seqno, sizeof(random_seqno));
index 06fc91f..dbab22f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_SOFT_INTERFACE_H_
index 6335433..e456bf6 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -329,10 +327,10 @@ static ssize_t batadv_show_bat_algo(struct kobject *kobj,
        return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);
 }
 
-static void batadv_post_gw_deselect(struct net_device *net_dev)
+static void batadv_post_gw_reselect(struct net_device *net_dev)
 {
        struct batadv_priv *bat_priv = netdev_priv(net_dev);
-       batadv_gw_deselect(bat_priv);
+       batadv_gw_reselect(bat_priv);
 }
 
 static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr,
@@ -408,7 +406,16 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
        batadv_info(net_dev, "Changing gw mode from: %s to: %s\n",
                    curr_gw_mode_str, buff);
 
-       batadv_gw_deselect(bat_priv);
+       /* Invoking batadv_gw_reselect() is not enough to really de-select the
+        * current GW. It will only instruct the gateway client code to perform
+        * a re-election the next time that this is needed.
+        *
+        * When gw client mode is being switched off the current GW must be
+        * de-selected explicitly otherwise no GW_ADD uevent is thrown on
+        * client mode re-activation. This is operation is performed in
+        * batadv_gw_check_client_stop().
+        */
+       batadv_gw_reselect(bat_priv);
        /* always call batadv_gw_check_client_stop() before changing the gateway
         * state
         */
@@ -443,6 +450,74 @@ static ssize_t batadv_store_gw_bwidth(struct kobject *kobj,
        return batadv_gw_bandwidth_set(net_dev, buff, count);
 }
 
+/**
+ * batadv_show_isolation_mark - print the current isolation mark/mask
+ * @kobj: kobject representing the private mesh sysfs directory
+ * @attr: the batman-adv attribute the user is interacting with
+ * @buff: the buffer that will contain the data to send back to the user
+ *
+ * Returns the number of bytes written into 'buff' on success or a negative
+ * error code in case of failure
+ */
+static ssize_t batadv_show_isolation_mark(struct kobject *kobj,
+                                         struct attribute *attr, char *buff)
+{
+       struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
+
+       return sprintf(buff, "%#.8x/%#.8x\n", bat_priv->isolation_mark,
+                      bat_priv->isolation_mark_mask);
+}
+
+/**
+ * batadv_store_isolation_mark - parse and store the isolation mark/mask entered
+ *  by the user
+ * @kobj: kobject representing the private mesh sysfs directory
+ * @attr: the batman-adv attribute the user is interacting with
+ * @buff: the buffer containing the user data
+ * @count: number of bytes in the buffer
+ *
+ * Returns 'count' on success or a negative error code in case of failure
+ */
+static ssize_t batadv_store_isolation_mark(struct kobject *kobj,
+                                          struct attribute *attr, char *buff,
+                                          size_t count)
+{
+       struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
+       struct batadv_priv *bat_priv = netdev_priv(net_dev);
+       uint32_t mark, mask;
+       char *mask_ptr;
+
+       /* parse the mask if it has been specified, otherwise assume the mask is
+        * the biggest possible
+        */
+       mask = 0xFFFFFFFF;
+       mask_ptr = strchr(buff, '/');
+       if (mask_ptr) {
+               *mask_ptr = '\0';
+               mask_ptr++;
+
+               /* the mask must be entered in hex base as it is going to be a
+                * bitmask and not a prefix length
+                */
+               if (kstrtou32(mask_ptr, 16, &mask) < 0)
+                       return -EINVAL;
+       }
+
+       /* the mark can be entered in any base */
+       if (kstrtou32(buff, 0, &mark) < 0)
+               return -EINVAL;
+
+       bat_priv->isolation_mark_mask = mask;
+       /* erase bits not covered by the mask */
+       bat_priv->isolation_mark = mark & bat_priv->isolation_mark_mask;
+
+       batadv_info(net_dev,
+                   "New skb mark for extended isolation: %#.8x/%#.8x\n",
+                   bat_priv->isolation_mark, bat_priv->isolation_mark_mask);
+
+       return count;
+}
+
 BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
 BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
 #ifdef CONFIG_BATMAN_ADV_BLA
@@ -461,7 +536,7 @@ BATADV_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * BATADV_JITTER,
 BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE,
                     NULL);
 BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE,
-                    batadv_post_gw_deselect);
+                    batadv_post_gw_reselect);
 static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
                   batadv_store_gw_bwidth);
 #ifdef CONFIG_BATMAN_ADV_DEBUG
@@ -471,6 +546,8 @@ BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);
 BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR,
                     batadv_nc_status_update);
 #endif
+static BATADV_ATTR(isolation_mark, S_IRUGO | S_IWUSR,
+                  batadv_show_isolation_mark, batadv_store_isolation_mark);
 
 static struct batadv_attribute *batadv_mesh_attrs[] = {
        &batadv_attr_aggregated_ogms,
@@ -494,6 +571,7 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
 #ifdef CONFIG_BATMAN_ADV_NC
        &batadv_attr_network_coding,
 #endif
+       &batadv_attr_isolation_mark,
        NULL,
 };
 
index c7d725d..b715b60 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_SYSFS_H_
index 19bc42f..a6fb1ff 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "main.h"
@@ -476,11 +474,13 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
  * @vid: VLAN identifier
  * @ifindex: index of the interface where the client is connected to (useful to
  *  identify wireless clients)
+ * @mark: the value contained in the skb->mark field of the received packet (if
+ *  any)
  *
  * Returns true if the client was successfully added, false otherwise.
  */
 bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
-                        unsigned short vid, int ifindex)
+                        unsigned short vid, int ifindex, uint32_t mark)
 {
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        struct batadv_tt_local_entry *tt_local;
@@ -491,6 +491,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
        int hash_added, table_size, packet_size_max;
        bool ret = false, roamed_back = false;
        uint8_t remote_flags;
+       uint32_t match_mark;
 
        if (ifindex != BATADV_NULL_IFINDEX)
                in_dev = dev_get_by_index(&init_net, ifindex);
@@ -615,6 +616,17 @@ check_roaming:
        else
                tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
 
+       /* check the mark in the skb: if it's equal to the configured
+        * isolation_mark, it means the packet is coming from an isolated
+        * non-mesh client
+        */
+       match_mark = (mark & bat_priv->isolation_mark_mask);
+       if (bat_priv->isolation_mark_mask &&
+           match_mark == bat_priv->isolation_mark)
+               tt_local->common.flags |= BATADV_TT_CLIENT_ISOLA;
+       else
+               tt_local->common.flags &= ~BATADV_TT_CLIENT_ISOLA;
+
        /* if any "dynamic" flag has been modified, resend an ADD event for this
         * entry so that all the nodes can get the new flags
         */
@@ -875,7 +887,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
        seq_printf(seq,
                   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
                   net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn));
-       seq_printf(seq, "       %-13s  %s %-7s %-9s (%-10s)\n", "Client", "VID",
+       seq_printf(seq, "       %-13s  %s %-8s %-9s (%-10s)\n", "Client", "VID",
                   "Flags", "Last seen", "CRC");
 
        for (i = 0; i < hash->size; i++) {
@@ -903,7 +915,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
                        }
 
                        seq_printf(seq,
-                                  " * %pM %4i [%c%c%c%c%c] %3u.%03u   (%#.8x)\n",
+                                  " * %pM %4i [%c%c%c%c%c%c] %3u.%03u   (%#.8x)\n",
                                   tt_common_entry->addr,
                                   BATADV_PRINT_VID(tt_common_entry->vid),
                                   (tt_common_entry->flags &
@@ -915,6 +927,8 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
                                    BATADV_TT_CLIENT_PENDING ? 'X' : '.'),
                                   (tt_common_entry->flags &
                                    BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+                                  (tt_common_entry->flags &
+                                   BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
                                   no_purge ? 0 : last_seen_secs,
                                   no_purge ? 0 : last_seen_msecs,
                                   vlan->tt.crc);
@@ -1386,12 +1400,14 @@ batadv_transtable_best_orig(struct batadv_priv *bat_priv,
 
        head = &tt_global_entry->orig_list;
        hlist_for_each_entry_rcu(orig_entry, head, list) {
-               router = batadv_orig_node_get_router(orig_entry->orig_node);
+               router = batadv_orig_router_get(orig_entry->orig_node,
+                                               BATADV_IF_DEFAULT);
                if (!router)
                        continue;
 
                if (best_router &&
-                   bao->bat_neigh_cmp(router, best_router) <= 0) {
+                   bao->bat_neigh_cmp(router, BATADV_IF_DEFAULT,
+                                      best_router, BATADV_IF_DEFAULT) <= 0) {
                        batadv_neigh_node_free_ref(router);
                        continue;
                }
@@ -1447,13 +1463,14 @@ batadv_tt_global_print_entry(struct batadv_priv *bat_priv,
 
                last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
                seq_printf(seq,
-                          " %c %pM %4i   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c]\n",
+                          " %c %pM %4i   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c%c]\n",
                           '*', tt_global_entry->common.addr,
                           BATADV_PRINT_VID(tt_global_entry->common.vid),
                           best_entry->ttvn, best_entry->orig_node->orig,
                           last_ttvn, vlan->tt.crc,
                           (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
                           (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+                          (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
                           (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
 
                batadv_orig_node_vlan_free_ref(vlan);
@@ -1478,13 +1495,14 @@ print_list:
 
                last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
                seq_printf(seq,
-                          " %c %pM %4d   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c]\n",
+                          " %c %pM %4d   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c%c]\n",
                           '+', tt_global_entry->common.addr,
                           BATADV_PRINT_VID(tt_global_entry->common.vid),
                           orig_entry->ttvn, orig_entry->orig_node->orig,
                           last_ttvn, vlan->tt.crc,
                           (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
                           (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
+                          (flags & BATADV_TT_CLIENT_ISOLA ? 'I' : '.'),
                           (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
 
                batadv_orig_node_vlan_free_ref(vlan);
@@ -1853,6 +1871,11 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
            tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
                ret = true;
 
+       /* check if the two clients are marked as isolated */
+       if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
+           tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
+               ret = true;
+
        return ret;
 }
 
@@ -1879,19 +1902,8 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
        struct batadv_tt_global_entry *tt_global_entry = NULL;
        struct batadv_orig_node *orig_node = NULL;
        struct batadv_tt_orig_list_entry *best_entry;
-       bool ap_isolation_enabled = false;
-       struct batadv_softif_vlan *vlan;
 
-       /* if the AP isolation is requested on a VLAN, then check for its
-        * setting in the proper VLAN private data structure
-        */
-       vlan = batadv_softif_vlan_get(bat_priv, vid);
-       if (vlan) {
-               ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
-               batadv_softif_vlan_free_ref(vlan);
-       }
-
-       if (src && ap_isolation_enabled) {
+       if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
                tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
                if (!tt_local_entry ||
                    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
@@ -3567,3 +3579,29 @@ int batadv_tt_init(struct batadv_priv *bat_priv)
 
        return 1;
 }
+
+/**
+ * batadv_tt_global_is_isolated - check if a client is marked as isolated
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac address of the client
+ * @vid: the identifier of the VLAN where this client is connected
+ *
+ * Returns true if the client is marked with the TT_CLIENT_ISOLA flag, false
+ * otherwise
+ */
+bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
+                                 const uint8_t *addr, unsigned short vid)
+{
+       struct batadv_tt_global_entry *tt;
+       bool ret;
+
+       tt = batadv_tt_global_hash_find(bat_priv, addr, vid);
+       if (!tt)
+               return false;
+
+       ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
+
+       batadv_tt_global_entry_free_ref(tt);
+
+       return ret;
+}
index 026b1ff..20a1d78 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_
@@ -22,7 +20,7 @@
 
 int batadv_tt_init(struct batadv_priv *bat_priv);
 bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
-                        unsigned short vid, int ifindex);
+                        unsigned short vid, int ifindex, uint32_t mark);
 uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
                                const uint8_t *addr, unsigned short vid,
                                const char *message, bool roaming);
@@ -50,5 +48,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
                                          struct batadv_orig_node *orig_node,
                                          const unsigned char *addr,
                                          unsigned short vid);
+bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
+                                 const uint8_t *addr, unsigned short vid);
 
 #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
index 91dd369..b53f90d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich
  *
@@ -12,9 +12,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifndef _NET_BATMAN_ADV_TYPES_H_
 #endif /* CONFIG_BATMAN_ADV_DAT */
 
 /**
+ * enum batadv_dhcp_recipient - dhcp destination
+ * @BATADV_DHCP_NO: packet is not a dhcp message
+ * @BATADV_DHCP_TO_SERVER: dhcp message is directed to a server
+ * @BATADV_DHCP_TO_CLIENT: dhcp message is directed to a client
+ */
+enum batadv_dhcp_recipient {
+       BATADV_DHCP_NO = 0,
+       BATADV_DHCP_TO_SERVER,
+       BATADV_DHCP_TO_CLIENT,
+};
+
+/**
  * BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the
  *  wire only
  */
@@ -74,6 +84,7 @@ struct batadv_hard_iface_bat_iv {
  * @rcu: struct used for freeing in an RCU-safe manner
  * @bat_iv: BATMAN IV specific per hard interface data
  * @cleanup_work: work queue callback item for hard interface deinit
+ * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
  */
 struct batadv_hard_iface {
        struct list_head list;
@@ -88,6 +99,29 @@ struct batadv_hard_iface {
        struct rcu_head rcu;
        struct batadv_hard_iface_bat_iv bat_iv;
        struct work_struct cleanup_work;
+       struct dentry *debug_dir;
+};
+
+/**
+ * struct batadv_orig_ifinfo - originator info per outgoing interface
+ * @list: list node for orig_node::ifinfo_list
+ * @if_outgoing: pointer to outgoing hard interface
+ * @router: router that should be used to reach this originator
+ * @last_real_seqno: last and best known sequence number
+ * @last_ttl: ttl of last received packet
+ * @batman_seqno_reset: time when the batman seqno window was reset
+ * @refcount: number of contexts the object is used
+ * @rcu: struct used for freeing in an RCU-safe manner
+ */
+struct batadv_orig_ifinfo {
+       struct hlist_node list;
+       struct batadv_hard_iface *if_outgoing;
+       struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
+       uint32_t last_real_seqno;
+       uint8_t last_ttl;
+       unsigned long batman_seqno_reset;
+       atomic_t refcount;
+       struct rcu_head rcu;
 };
 
 /**
@@ -165,11 +199,11 @@ struct batadv_orig_bat_iv {
  * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
  * @orig: originator ethernet address
  * @primary_addr: hosts primary interface address
- * @router: router that should be used to reach this originator
+ * @ifinfo_list: list for routers per outgoing interface
+ * @last_bonding_candidate: pointer to last ifinfo of last used router
  * @batadv_dat_addr_t:  address of the orig node in the distributed hash
  * @last_seen: time when last packet from this node was received
  * @bcast_seqno_reset: time when the broadcast seqno window was reset
- * @batman_seqno_reset: time when the batman seqno window was reset
  * @capabilities: announced capabilities of this originator
  * @last_ttvn: last seen translation table version number
  * @tt_buff: last tt changeset this node received from the orig node
@@ -182,19 +216,15 @@ struct batadv_orig_bat_iv {
  *  made up by two operations (data structure update and metdata -CRC/TTVN-
  *  recalculation) and they have to be executed atomically in order to avoid
  *  another thread to read the table/metadata between those.
- * @last_real_seqno: last and best known sequence number
- * @last_ttl: ttl of last received packet
  * @bcast_bits: bitfield containing the info which payload broadcast originated
  *  from this orig node this host already has seen (relative to
  *  last_bcast_seqno)
  * @last_bcast_seqno: last broadcast sequence number received by this host
  * @neigh_list: list of potential next hop neighbor towards this orig node
- * @neigh_list_lock: lock protecting neigh_list, router and bonding_list
+ * @neigh_list_lock: lock protecting neigh_list and router
  * @hash_entry: hlist node for batadv_priv::orig_hash
  * @bat_priv: pointer to soft_iface this orig node belongs to
  * @bcast_seqno_lock: lock protecting bcast_bits & last_bcast_seqno
- * @bond_candidates: how many candidates are available
- * @bond_list: list of bonding candidates
  * @refcount: number of contexts the object is used
  * @rcu: struct used for freeing in an RCU-safe manner
  * @in_coding_list: list of nodes this orig can hear
@@ -210,13 +240,13 @@ struct batadv_orig_bat_iv {
 struct batadv_orig_node {
        uint8_t orig[ETH_ALEN];
        uint8_t primary_addr[ETH_ALEN];
-       struct batadv_neigh_node __rcu *router; /* rcu protected pointer */
+       struct hlist_head ifinfo_list;
+       struct batadv_orig_ifinfo *last_bonding_candidate;
 #ifdef CONFIG_BATMAN_ADV_DAT
        batadv_dat_addr_t dat_addr;
 #endif
        unsigned long last_seen;
        unsigned long bcast_seqno_reset;
-       unsigned long batman_seqno_reset;
        uint8_t capabilities;
        atomic_t last_ttvn;
        unsigned char *tt_buff;
@@ -225,19 +255,15 @@ struct batadv_orig_node {
        bool tt_initialised;
        /* prevents from changing the table while reading it */
        spinlock_t tt_lock;
-       uint32_t last_real_seqno;
-       uint8_t last_ttl;
        DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
        uint32_t last_bcast_seqno;
        struct hlist_head neigh_list;
-       /* neigh_list_lock protects: neigh_list, router & bonding_list */
+       /* neigh_list_lock protects: neigh_list and router */
        spinlock_t neigh_list_lock;
        struct hlist_node hash_entry;
        struct batadv_priv *bat_priv;
        /* bcast_seqno_lock protects: bcast_bits & last_bcast_seqno */
        spinlock_t bcast_seqno_lock;
-       atomic_t bond_candidates;
-       struct list_head bond_list;
        atomic_t refcount;
        struct rcu_head rcu;
 #ifdef CONFIG_BATMAN_ADV_NC
@@ -283,49 +309,62 @@ struct batadv_gw_node {
 };
 
 /**
- * struct batadv_neigh_bat_iv - B.A.T.M.A.N. IV specific structure for single
- *  hop neighbors
+ * struct batadv_neigh_node - structure for single hops neighbors
+ * @list: list node for batadv_orig_node::neigh_list
+ * @orig_node: pointer to corresponding orig_node
+ * @addr: the MAC address of the neighboring interface
+ * @ifinfo_list: list for routing metrics per outgoing interface
+ * @ifinfo_lock: lock protecting private ifinfo members and list
+ * @if_incoming: pointer to incoming hard interface
+ * @last_seen: when last packet via this neighbor was received
+ * @last_ttl: last received ttl from this neigh node
+ * @rcu: struct used for freeing in an RCU-safe manner
+ * @bat_iv: B.A.T.M.A.N. IV private structure
+ */
+struct batadv_neigh_node {
+       struct hlist_node list;
+       struct batadv_orig_node *orig_node;
+       uint8_t addr[ETH_ALEN];
+       struct hlist_head ifinfo_list;
+       spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */
+       struct batadv_hard_iface *if_incoming;
+       unsigned long last_seen;
+       atomic_t refcount;
+       struct rcu_head rcu;
+};
+
+/* struct batadv_neigh_node_bat_iv - neighbor information per outgoing
+ *  interface for BATMAN IV
  * @tq_recv: ring buffer of received TQ values from this neigh node
  * @tq_index: ring buffer index
  * @tq_avg: averaged tq of all tq values in the ring buffer (tq_recv)
  * @real_bits: bitfield containing the number of OGMs received from this neigh
  *  node (relative to orig_node->last_real_seqno)
  * @real_packet_count: counted result of real_bits
- * @lq_update_lock: lock protecting tq_recv & tq_index
  */
-struct batadv_neigh_bat_iv {
+struct batadv_neigh_ifinfo_bat_iv {
        uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE];
        uint8_t tq_index;
        uint8_t tq_avg;
        DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
        uint8_t real_packet_count;
-       spinlock_t lq_update_lock; /* protects tq_recv & tq_index */
 };
 
-/**
- * struct batadv_neigh_node - structure for single hops neighbors
- * @list: list node for batadv_orig_node::neigh_list
- * @orig_node: pointer to corresponding orig_node
- * @addr: the MAC address of the neighboring interface
- * @if_incoming: pointer to incoming hard interface
- * @last_seen: when last packet via this neighbor was received
+/* struct batadv_neigh_ifinfo - neighbor information per outgoing interface
+ * @list: list node for batadv_neigh_node::ifinfo_list
+ * @if_outgoing: pointer to outgoing hard interface
+ * @bat_iv: B.A.T.M.A.N. IV private structure
  * @last_ttl: last received ttl from this neigh node
- * @bonding_list: list node for batadv_orig_node::bond_list
  * @refcount: number of contexts the object is used
- * @rcu: struct used for freeing in an RCU-safe manner
- * @bat_iv: B.A.T.M.A.N. IV private structure
+ * @rcu: struct used for freeing in a RCU-safe manner
  */
-struct batadv_neigh_node {
+struct batadv_neigh_ifinfo {
        struct hlist_node list;
-       struct batadv_orig_node *orig_node;
-       uint8_t addr[ETH_ALEN];
-       struct batadv_hard_iface *if_incoming;
-       unsigned long last_seen;
+       struct batadv_hard_iface *if_outgoing;
+       struct batadv_neigh_ifinfo_bat_iv bat_iv;
        uint8_t last_ttl;
-       struct list_head bonding_list;
        atomic_t refcount;
        struct rcu_head rcu;
-       struct batadv_neigh_bat_iv bat_iv;
 };
 
 /**
@@ -687,6 +726,8 @@ struct batadv_priv {
 #ifdef CONFIG_BATMAN_ADV_DEBUG
        atomic_t log_level;
 #endif
+       uint32_t isolation_mark;
+       uint32_t isolation_mark_mask;
        atomic_t bcast_seqno;
        atomic_t bcast_queue_left;
        atomic_t batman_queue_left;
@@ -981,8 +1022,10 @@ struct batadv_skb_cb {
  * @direct_link_flags: direct link flags for aggregated OGM packets
  * @num_packets: counter for bcast packet retransmission
  * @delayed_work: work queue callback item for packet sending
- * @if_incoming: pointer incoming hard-iface or primary iface if locally
- *  generated packet
+ * @if_incoming: pointer to incoming hard-iface or primary iface if
+ *  locally generated packet
+ * @if_outgoing: packet where the packet should be sent to, or NULL if
+ *  unspecified
  */
 struct batadv_forw_packet {
        struct hlist_node list;
@@ -994,6 +1037,7 @@ struct batadv_forw_packet {
        uint8_t num_packets;
        struct delayed_work delayed_work;
        struct batadv_hard_iface *if_incoming;
+       struct batadv_hard_iface *if_outgoing;
 };
 
 /**
@@ -1007,9 +1051,11 @@ struct batadv_forw_packet {
  * @bat_primary_iface_set: called when primary interface is selected / changed
  * @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
  * @bat_ogm_emit: send scheduled OGM
- * @bat_neigh_cmp: compare the metrics of two neighbors
- * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or
- *  better than neigh2 from the metric prospective
+ * @bat_neigh_cmp: compare the metrics of two neighbors for their respective
+ *  outgoing interfaces
+ * @bat_neigh_is_equiv_or_better: check if neigh1 is equally good or better
+ *  than neigh2 for their respective outgoing interface from the metric
+ *  prospective
  * @bat_orig_print: print the originator table (optional)
  * @bat_orig_free: free the resources allocated by the routing algorithm for an
  *  orig_node object
@@ -1028,11 +1074,17 @@ struct batadv_algo_ops {
        void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface);
        void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet);
        int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1,
-                            struct batadv_neigh_node *neigh2);
-       bool (*bat_neigh_is_equiv_or_better)(struct batadv_neigh_node *neigh1,
-                                            struct batadv_neigh_node *neigh2);
+                            struct batadv_hard_iface *if_outgoing1,
+                            struct batadv_neigh_node *neigh2,
+                            struct batadv_hard_iface *if_outgoing2);
+       bool (*bat_neigh_is_equiv_or_better)
+               (struct batadv_neigh_node *neigh1,
+                struct batadv_hard_iface *if_outgoing1,
+                struct batadv_neigh_node *neigh2,
+                struct batadv_hard_iface *if_outgoing2);
        /* orig_node handling API */
-       void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq);
+       void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq,
+                              struct batadv_hard_iface *hard_iface);
        void (*bat_orig_free)(struct batadv_orig_node *orig_node);
        int (*bat_orig_add_if)(struct batadv_orig_node *orig_node,
                               int max_if_num);
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
new file mode 100644 (file)
index 0000000..adb3ea0
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+   Copyright (c) 2013 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+#include <net/af_ieee802154.h> /* to get the address type */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+#include "6lowpan.h"
+
+#include "../ieee802154/6lowpan.h" /* for the compression support */
+
+#define IFACE_NAME_TEMPLATE "bt%d"
+#define EUI64_ADDR_LEN 8
+
+struct skb_cb {
+       struct in6_addr addr;
+       struct l2cap_conn *conn;
+};
+#define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb))
+
+/* The devices list contains those devices that we are acting
+ * as a proxy. The BT 6LoWPAN device is a virtual device that
+ * connects to the Bluetooth LE device. The real connection to
+ * BT device is done via l2cap layer. There exists one
+ * virtual device / one BT 6LoWPAN network (=hciX device).
+ * The list contains struct lowpan_dev elements.
+ */
+static LIST_HEAD(bt_6lowpan_devices);
+static DEFINE_RWLOCK(devices_lock);
+
+struct lowpan_peer {
+       struct list_head list;
+       struct l2cap_conn *conn;
+
+       /* peer addresses in various formats */
+       unsigned char eui64_addr[EUI64_ADDR_LEN];
+       struct in6_addr peer_addr;
+};
+
+struct lowpan_dev {
+       struct list_head list;
+
+       struct hci_dev *hdev;
+       struct net_device *netdev;
+       struct list_head peers;
+       atomic_t peer_count; /* number of items in peers list */
+
+       struct work_struct delete_netdev;
+       struct delayed_work notify_peers;
+};
+
+static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
+{
+       return netdev_priv(netdev);
+}
+
+static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
+{
+       list_add(&peer->list, &dev->peers);
+       atomic_inc(&dev->peer_count);
+}
+
+static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
+{
+       list_del(&peer->list);
+
+       if (atomic_dec_and_test(&dev->peer_count)) {
+               BT_DBG("last peer");
+               return true;
+       }
+
+       return false;
+}
+
+static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
+                                                bdaddr_t *ba, __u8 type)
+{
+       struct lowpan_peer *peer, *tmp;
+
+       BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
+              ba, type);
+
+       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+               BT_DBG("addr %pMR type %d",
+                      &peer->conn->hcon->dst, peer->conn->hcon->dst_type);
+
+               if (bacmp(&peer->conn->hcon->dst, ba))
+                       continue;
+
+               if (type == peer->conn->hcon->dst_type)
+                       return peer;
+       }
+
+       return NULL;
+}
+
+static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
+                                                  struct l2cap_conn *conn)
+{
+       struct lowpan_peer *peer, *tmp;
+
+       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+               if (peer->conn == conn)
+                       return peer;
+       }
+
+       return NULL;
+}
+
+static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
+{
+       struct lowpan_dev *entry, *tmp;
+       struct lowpan_peer *peer = NULL;
+       unsigned long flags;
+
+       read_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               peer = peer_lookup_conn(entry, conn);
+               if (peer)
+                       break;
+       }
+
+       read_unlock_irqrestore(&devices_lock, flags);
+
+       return peer;
+}
+
+static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
+{
+       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *dev = NULL;
+       unsigned long flags;
+
+       read_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               if (conn->hcon->hdev == entry->hdev) {
+                       dev = entry;
+                       break;
+               }
+       }
+
+       read_unlock_irqrestore(&devices_lock, flags);
+
+       return dev;
+}
+
+static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff *skb_cp;
+       int ret;
+
+       skb_cp = skb_copy(skb, GFP_ATOMIC);
+       if (!skb_cp)
+               return -ENOMEM;
+
+       ret = netif_rx(skb_cp);
+
+       BT_DBG("receive skb %d", ret);
+       if (ret < 0)
+               return NET_RX_DROP;
+
+       return ret;
+}
+
+static int process_data(struct sk_buff *skb, struct net_device *netdev,
+                       struct l2cap_conn *conn)
+{
+       const u8 *saddr, *daddr;
+       u8 iphc0, iphc1;
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       unsigned long flags;
+
+       dev = lowpan_dev(netdev);
+
+       read_lock_irqsave(&devices_lock, flags);
+       peer = peer_lookup_conn(dev, conn);
+       read_unlock_irqrestore(&devices_lock, flags);
+       if (!peer)
+               goto drop;
+
+       saddr = peer->eui64_addr;
+       daddr = dev->netdev->dev_addr;
+
+       /* at least two bytes will be used for the encoding */
+       if (skb->len < 2)
+               goto drop;
+
+       if (lowpan_fetch_skb_u8(skb, &iphc0))
+               goto drop;
+
+       if (lowpan_fetch_skb_u8(skb, &iphc1))
+               goto drop;
+
+       return lowpan_process_data(skb, netdev,
+                                  saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+                                  daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+                                  iphc0, iphc1, give_skb_to_upper);
+
+drop:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
+                   struct l2cap_conn *conn)
+{
+       struct sk_buff *local_skb;
+       int ret;
+
+       if (!netif_running(dev))
+               goto drop;
+
+       if (dev->type != ARPHRD_6LOWPAN)
+               goto drop;
+
+       /* check that it's our buffer */
+       if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+               /* Copy the packet so that the IPv6 header is
+                * properly aligned.
+                */
+               local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
+                                           skb_tailroom(skb), GFP_ATOMIC);
+               if (!local_skb)
+                       goto drop;
+
+               local_skb->protocol = htons(ETH_P_IPV6);
+               local_skb->pkt_type = PACKET_HOST;
+
+               skb_reset_network_header(local_skb);
+               skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
+
+               if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
+                       kfree_skb(local_skb);
+                       goto drop;
+               }
+
+               dev->stats.rx_bytes += skb->len;
+               dev->stats.rx_packets++;
+
+               kfree_skb(local_skb);
+               kfree_skb(skb);
+       } else {
+               switch (skb->data[0] & 0xe0) {
+               case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+                       local_skb = skb_clone(skb, GFP_ATOMIC);
+                       if (!local_skb)
+                               goto drop;
+
+                       ret = process_data(local_skb, dev, conn);
+                       if (ret != NET_RX_SUCCESS)
+                               goto drop;
+
+                       dev->stats.rx_bytes += skb->len;
+                       dev->stats.rx_packets++;
+
+                       kfree_skb(skb);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return NET_RX_SUCCESS;
+
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+/* Packet from BT LE device */
+int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       int err;
+
+       peer = lookup_peer(conn);
+       if (!peer)
+               return -ENOENT;
+
+       dev = lookup_dev(conn);
+       if (!dev || !dev->netdev)
+               return -ENOENT;
+
+       err = recv_pkt(skb, dev->netdev, conn);
+       BT_DBG("recv pkt %d", err);
+
+       return err;
+}
+
+static inline int skbuff_copy(void *msg, int len, int count, int mtu,
+                             struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff **frag;
+       int sent = 0;
+
+       memcpy(skb_put(skb, count), msg, count);
+
+       sent += count;
+       msg  += count;
+       len  -= count;
+
+       dev->stats.tx_bytes += count;
+       dev->stats.tx_packets++;
+
+       raw_dump_table(__func__, "Sending", skb->data, skb->len);
+
+       /* Continuation fragments (no L2CAP header) */
+       frag = &skb_shinfo(skb)->frag_list;
+       while (len > 0) {
+               struct sk_buff *tmp;
+
+               count = min_t(unsigned int, mtu, len);
+
+               tmp = bt_skb_alloc(count, GFP_ATOMIC);
+               if (!tmp)
+                       return -ENOMEM;
+
+               *frag = tmp;
+
+               memcpy(skb_put(*frag, count), msg, count);
+
+               raw_dump_table(__func__, "Sending fragment",
+                              (*frag)->data, count);
+
+               (*frag)->priority = skb->priority;
+
+               sent += count;
+               msg  += count;
+               len  -= count;
+
+               skb->len += (*frag)->len;
+               skb->data_len += (*frag)->len;
+
+               frag = &(*frag)->next;
+
+               dev->stats.tx_bytes += count;
+               dev->stats.tx_packets++;
+       }
+
+       return sent;
+}
+
+static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg,
+                                 size_t len, u32 priority,
+                                 struct net_device *dev)
+{
+       struct sk_buff *skb;
+       int err, count;
+       struct l2cap_hdr *lh;
+
+       /* FIXME: This mtu check should be not needed and atm is only used for
+        * testing purposes
+        */
+       if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE))
+               conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE;
+
+       count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
+
+       BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count);
+
+       skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC);
+       if (!skb)
+               return ERR_PTR(-ENOMEM);
+
+       skb->priority = priority;
+
+       lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE);
+       lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN);
+       lh->len = cpu_to_le16(len);
+
+       err = skbuff_copy(msg, len, count, conn->mtu, skb, dev);
+       if (unlikely(err < 0)) {
+               kfree_skb(skb);
+               BT_DBG("skbuff copy %d failed", err);
+               return ERR_PTR(err);
+       }
+
+       return skb;
+}
+
+static int conn_send(struct l2cap_conn *conn,
+                    void *msg, size_t len, u32 priority,
+                    struct net_device *dev)
+{
+       struct sk_buff *skb;
+
+       skb = create_pdu(conn, msg, len, priority, dev);
+       if (IS_ERR(skb))
+               return -EINVAL;
+
+       BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len,
+              skb->priority);
+
+       hci_send_acl(conn->hchan, skb, ACL_START);
+
+       return 0;
+}
+
+static void get_dest_bdaddr(struct in6_addr *ip6_daddr,
+                           bdaddr_t *addr, u8 *addr_type)
+{
+       u8 *eui64;
+
+       eui64 = ip6_daddr->s6_addr + 8;
+
+       addr->b[0] = eui64[7];
+       addr->b[1] = eui64[6];
+       addr->b[2] = eui64[5];
+       addr->b[3] = eui64[2];
+       addr->b[4] = eui64[1];
+       addr->b[5] = eui64[0];
+
+       addr->b[5] ^= 2;
+
+       /* Set universal/local bit to 0 */
+       if (addr->b[5] & 1) {
+               addr->b[5] &= ~1;
+               *addr_type = ADDR_LE_DEV_PUBLIC;
+       } else {
+               *addr_type = ADDR_LE_DEV_RANDOM;
+       }
+}
+
+static int header_create(struct sk_buff *skb, struct net_device *netdev,
+                        unsigned short type, const void *_daddr,
+                        const void *_saddr, unsigned int len)
+{
+       struct ipv6hdr *hdr;
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       bdaddr_t addr, *any = BDADDR_ANY;
+       u8 *saddr, *daddr = any->b;
+       u8 addr_type;
+
+       if (type != ETH_P_IPV6)
+               return -EINVAL;
+
+       hdr = ipv6_hdr(skb);
+
+       dev = lowpan_dev(netdev);
+
+       if (ipv6_addr_is_multicast(&hdr->daddr)) {
+               memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
+                      sizeof(struct in6_addr));
+               lowpan_cb(skb)->conn = NULL;
+       } else {
+               unsigned long flags;
+
+               /* Get destination BT device from skb.
+                * If there is no such peer then discard the packet.
+                */
+               get_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
+
+               BT_DBG("dest addr %pMR type %d", &addr, addr_type);
+
+               read_lock_irqsave(&devices_lock, flags);
+               peer = peer_lookup_ba(dev, &addr, addr_type);
+               read_unlock_irqrestore(&devices_lock, flags);
+
+               if (!peer) {
+                       BT_DBG("no such peer %pMR found", &addr);
+                       return -ENOENT;
+               }
+
+               daddr = peer->eui64_addr;
+
+               memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
+                      sizeof(struct in6_addr));
+               lowpan_cb(skb)->conn = peer->conn;
+       }
+
+       saddr = dev->netdev->dev_addr;
+
+       return lowpan_header_compress(skb, netdev, type, daddr, saddr, len);
+}
+
+/* Packet to BT LE device */
+static int send_pkt(struct l2cap_conn *conn, const void *saddr,
+                   const void *daddr, struct sk_buff *skb,
+                   struct net_device *netdev)
+{
+       raw_dump_table(__func__, "raw skb data dump before fragmentation",
+                      skb->data, skb->len);
+
+       return conn_send(conn, skb->data, skb->len, 0, netdev);
+}
+
+static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct sk_buff *local_skb;
+       struct lowpan_dev *entry, *tmp;
+       unsigned long flags;
+
+       read_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               struct lowpan_peer *pentry, *ptmp;
+               struct lowpan_dev *dev;
+
+               if (entry->netdev != netdev)
+                       continue;
+
+               dev = lowpan_dev(entry->netdev);
+
+               list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+                       local_skb = skb_clone(skb, GFP_ATOMIC);
+
+                       send_pkt(pentry->conn, netdev->dev_addr,
+                                pentry->eui64_addr, local_skb, netdev);
+
+                       kfree_skb(local_skb);
+               }
+       }
+
+       read_unlock_irqrestore(&devices_lock, flags);
+}
+
+static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       int err = 0;
+       unsigned char *eui64_addr;
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       bdaddr_t addr;
+       u8 addr_type;
+
+       if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
+               /* We need to send the packet to every device
+                * behind this interface.
+                */
+               send_mcast_pkt(skb, netdev);
+       } else {
+               unsigned long flags;
+
+               get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
+               eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8;
+               dev = lowpan_dev(netdev);
+
+               read_lock_irqsave(&devices_lock, flags);
+               peer = peer_lookup_ba(dev, &addr, addr_type);
+               read_unlock_irqrestore(&devices_lock, flags);
+
+               BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name,
+                      &addr, &lowpan_cb(skb)->addr, peer);
+
+               if (peer && peer->conn)
+                       err = send_pkt(peer->conn, netdev->dev_addr,
+                                      eui64_addr, skb, netdev);
+       }
+       dev_kfree_skb(skb);
+
+       if (err)
+               BT_DBG("ERROR: xmit failed (%d)", err);
+
+       return (err < 0) ? NET_XMIT_DROP : err;
+}
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_start_xmit         = bt_xmit,
+};
+
+static struct header_ops header_ops = {
+       .create = header_create,
+};
+
+static void netdev_setup(struct net_device *dev)
+{
+       dev->addr_len           = EUI64_ADDR_LEN;
+       dev->type               = ARPHRD_6LOWPAN;
+
+       dev->hard_header_len    = 0;
+       dev->needed_tailroom    = 0;
+       dev->mtu                = IPV6_MIN_MTU;
+       dev->tx_queue_len       = 0;
+       dev->flags              = IFF_RUNNING | IFF_POINTOPOINT;
+       dev->watchdog_timeo     = 0;
+
+       dev->netdev_ops         = &netdev_ops;
+       dev->header_ops         = &header_ops;
+       dev->destructor         = free_netdev;
+}
+
+static struct device_type bt_type = {
+       .name   = "bluetooth",
+};
+
+static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
+{
+       /* addr is the BT address in little-endian format */
+       eui[0] = addr[5];
+       eui[1] = addr[4];
+       eui[2] = addr[3];
+       eui[3] = 0xFF;
+       eui[4] = 0xFE;
+       eui[5] = addr[2];
+       eui[6] = addr[1];
+       eui[7] = addr[0];
+
+       eui[0] ^= 2;
+
+       /* Universal/local bit set, RFC 4291 */
+       if (addr_type == ADDR_LE_DEV_PUBLIC)
+               eui[0] |= 1;
+       else
+               eui[0] &= ~1;
+}
+
+static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr,
+                        u8 addr_type)
+{
+       netdev->addr_assign_type = NET_ADDR_PERM;
+       set_addr(netdev->dev_addr, addr->b, addr_type);
+       netdev->dev_addr[0] ^= 2;
+}
+
+static void ifup(struct net_device *netdev)
+{
+       int err;
+
+       rtnl_lock();
+       err = dev_open(netdev);
+       if (err < 0)
+               BT_INFO("iface %s cannot be opened (%d)", netdev->name, err);
+       rtnl_unlock();
+}
+
+static void do_notify_peers(struct work_struct *work)
+{
+       struct lowpan_dev *dev = container_of(work, struct lowpan_dev,
+                                             notify_peers.work);
+
+       netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */
+}
+
+static bool is_bt_6lowpan(struct hci_conn *hcon)
+{
+       if (hcon->type != LE_LINK)
+               return false;
+
+       return test_bit(HCI_CONN_6LOWPAN, &hcon->flags);
+}
+
+static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev)
+{
+       struct lowpan_peer *peer;
+       unsigned long flags;
+
+       peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
+       if (!peer)
+               return -ENOMEM;
+
+       peer->conn = conn;
+       memset(&peer->peer_addr, 0, sizeof(struct in6_addr));
+
+       /* RFC 2464 ch. 5 */
+       peer->peer_addr.s6_addr[0] = 0xFE;
+       peer->peer_addr.s6_addr[1] = 0x80;
+       set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b,
+                conn->hcon->dst_type);
+
+       memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
+              EUI64_ADDR_LEN);
+       peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local)
+                                  * is done according RFC2464
+                                  */
+
+       raw_dump_inline(__func__, "peer IPv6 address",
+                       (unsigned char *)&peer->peer_addr, 16);
+       raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8);
+
+       write_lock_irqsave(&devices_lock, flags);
+       INIT_LIST_HEAD(&peer->list);
+       peer_add(dev, peer);
+       write_unlock_irqrestore(&devices_lock, flags);
+
+       /* Notifying peers about us needs to be done without locks held */
+       INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
+       schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100));
+
+       return 0;
+}
+
+/* This gets called when BT LE 6LoWPAN device is connected. We then
+ * create network device that acts as a proxy between BT LE device
+ * and kernel network stack.
+ */
+int bt_6lowpan_add_conn(struct l2cap_conn *conn)
+{
+       struct lowpan_peer *peer = NULL;
+       struct lowpan_dev *dev;
+       struct net_device *netdev;
+       int err = 0;
+       unsigned long flags;
+
+       if (!is_bt_6lowpan(conn->hcon))
+               return 0;
+
+       peer = lookup_peer(conn);
+       if (peer)
+               return -EEXIST;
+
+       dev = lookup_dev(conn);
+       if (dev)
+               return add_peer_conn(conn, dev);
+
+       netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup);
+       if (!netdev)
+               return -ENOMEM;
+
+       set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type);
+
+       netdev->netdev_ops = &netdev_ops;
+       SET_NETDEV_DEV(netdev, &conn->hcon->dev);
+       SET_NETDEV_DEVTYPE(netdev, &bt_type);
+
+       err = register_netdev(netdev);
+       if (err < 0) {
+               BT_INFO("register_netdev failed %d", err);
+               free_netdev(netdev);
+               goto out;
+       }
+
+       BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR",
+              netdev->ifindex, &conn->hcon->dst, &conn->hcon->src);
+       set_bit(__LINK_STATE_PRESENT, &netdev->state);
+
+       dev = netdev_priv(netdev);
+       dev->netdev = netdev;
+       dev->hdev = conn->hcon->hdev;
+       INIT_LIST_HEAD(&dev->peers);
+
+       write_lock_irqsave(&devices_lock, flags);
+       INIT_LIST_HEAD(&dev->list);
+       list_add(&dev->list, &bt_6lowpan_devices);
+       write_unlock_irqrestore(&devices_lock, flags);
+
+       ifup(netdev);
+
+       return add_peer_conn(conn, dev);
+
+out:
+       return err;
+}
+
+static void delete_netdev(struct work_struct *work)
+{
+       struct lowpan_dev *entry = container_of(work, struct lowpan_dev,
+                                               delete_netdev);
+
+       unregister_netdev(entry->netdev);
+
+       /* The entry pointer is deleted in device_event() */
+}
+
+int bt_6lowpan_del_conn(struct l2cap_conn *conn)
+{
+       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *dev = NULL;
+       struct lowpan_peer *peer;
+       int err = -ENOENT;
+       unsigned long flags;
+       bool last = false;
+
+       if (!conn || !is_bt_6lowpan(conn->hcon))
+               return 0;
+
+       write_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               dev = lowpan_dev(entry->netdev);
+               peer = peer_lookup_conn(dev, conn);
+               if (peer) {
+                       last = peer_del(dev, peer);
+                       err = 0;
+                       break;
+               }
+       }
+
+       if (!err && last && dev && !atomic_read(&dev->peer_count)) {
+               write_unlock_irqrestore(&devices_lock, flags);
+
+               cancel_delayed_work_sync(&dev->notify_peers);
+
+               /* bt_6lowpan_del_conn() is called with hci dev lock held which
+                * means that we must delete the netdevice in worker thread.
+                */
+               INIT_WORK(&entry->delete_netdev, delete_netdev);
+               schedule_work(&entry->delete_netdev);
+       } else {
+               write_unlock_irqrestore(&devices_lock, flags);
+       }
+
+       return err;
+}
+
+static int device_event(struct notifier_block *unused,
+                       unsigned long event, void *ptr)
+{
+       struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+       struct lowpan_dev *entry, *tmp;
+       unsigned long flags;
+
+       if (netdev->type != ARPHRD_6LOWPAN)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_UNREGISTER:
+               write_lock_irqsave(&devices_lock, flags);
+               list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
+                                        list) {
+                       if (entry->netdev == netdev) {
+                               list_del(&entry->list);
+                               kfree(entry);
+                               break;
+                       }
+               }
+               write_unlock_irqrestore(&devices_lock, flags);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block bt_6lowpan_dev_notifier = {
+       .notifier_call = device_event,
+};
+
+int bt_6lowpan_init(void)
+{
+       return register_netdevice_notifier(&bt_6lowpan_dev_notifier);
+}
+
+void bt_6lowpan_cleanup(void)
+{
+       unregister_netdevice_notifier(&bt_6lowpan_dev_notifier);
+}
diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h
new file mode 100644 (file)
index 0000000..680eac8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+   Copyright (c) 2013 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#ifndef __6LOWPAN_H
+#define __6LOWPAN_H
+
+#include <linux/skbuff.h>
+#include <net/bluetooth/l2cap.h>
+
+int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb);
+int bt_6lowpan_add_conn(struct l2cap_conn *conn);
+int bt_6lowpan_del_conn(struct l2cap_conn *conn);
+int bt_6lowpan_init(void);
+void bt_6lowpan_cleanup(void);
+
+#endif /* __6LOWPAN_H */
index d3f3f7b..985b560 100644 (file)
@@ -12,6 +12,7 @@ menuconfig BT
        select CRYPTO_AES
        select CRYPTO_ECB
        select CRYPTO_SHA256
+       select 6LOWPAN_IPHC
        help
          Bluetooth is low-cost, low-power, short-range wireless technology.
          It was designed as a replacement for cables and other short-range
index 6a791e7..cc6827e 100644 (file)
@@ -10,6 +10,10 @@ obj-$(CONFIG_BT_HIDP)        += hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
        hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
-       a2mp.o amp.o
+       a2mp.o amp.o 6lowpan.o
+
+ifeq ($(CONFIG_IEEE802154_6LOWPAN),)
+  bluetooth-y +=  ../ieee802154/6lowpan_iphc.o
+endif
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
index 8b8b5f8..5e8663c 100644 (file)
@@ -636,6 +636,49 @@ static int conn_max_interval_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get,
                        conn_max_interval_set, "%llu\n");
 
+static ssize_t lowpan_read(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[3];
+
+       buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer,
+                           size_t count, loff_t *position)
+{
+       struct hci_dev *hdev = fp->private_data;
+       bool enable;
+       char buf[32];
+       size_t buf_size = min(count, (sizeof(buf)-1));
+
+       if (copy_from_user(buf, user_buffer, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+
+       if (strtobool(buf, &enable) < 0)
+               return -EINVAL;
+
+       if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
+               return -EALREADY;
+
+       change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags);
+
+       return count;
+}
+
+static const struct file_operations lowpan_debugfs_fops = {
+       .open           = simple_open,
+       .read           = lowpan_read,
+       .write          = lowpan_write,
+       .llseek         = default_llseek,
+};
+
 /* ---- HCI requests ---- */
 
 static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@@ -1261,8 +1304,13 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
         * as supported send it. If not supported assume that the controller
         * does not have actual support for stored link keys which makes this
         * command redundant anyway.
+        *
+        * Some controllers indicate that they support handling deleting
+        * stored link keys, but they don't. The quirk lets a driver
+        * just disable this command.
         */
-       if (hdev->commands[6] & 0x80) {
+       if (hdev->commands[6] & 0x80 &&
+           !test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
                struct hci_cp_delete_stored_link_key cp;
 
                bacpy(&cp.bdaddr, BDADDR_ANY);
@@ -1406,6 +1454,8 @@ static int __hci_init(struct hci_dev *hdev)
                                    hdev, &conn_min_interval_fops);
                debugfs_create_file("conn_max_interval", 0644, hdev->debugfs,
                                    hdev, &conn_max_interval_fops);
+               debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
+                                   &lowpan_debugfs_fops);
        }
 
        return 0;
index 5fb3df6..5f81245 100644 (file)
@@ -3533,6 +3533,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        conn->handle = __le16_to_cpu(ev->handle);
        conn->state = BT_CONNECTED;
 
+       if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
+               set_bit(HCI_CONN_6LOWPAN, &conn->flags);
+
        hci_conn_add_sysfs(conn);
 
        hci_proto_connect_cfm(conn, ev->status);
index b6bca64..b0ad2c7 100644 (file)
@@ -40,6 +40,7 @@
 #include "smp.h"
 #include "a2mp.h"
 #include "amp.h"
+#include "6lowpan.h"
 
 bool disable_ertm;
 
@@ -1468,6 +1469,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        BT_DBG("");
 
+       bt_6lowpan_add_conn(conn);
+
        /* Check if we have socket listening on cid */
        pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
                                          &hcon->src, &hcon->dst);
@@ -7119,6 +7122,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
                        l2cap_conn_del(conn->hcon, EACCES);
                break;
 
+       case L2CAP_FC_6LOWPAN:
+               bt_6lowpan_recv(conn, skb);
+               break;
+
        default:
                l2cap_data_channel(conn, cid, skb);
                break;
@@ -7186,6 +7193,8 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
+       bt_6lowpan_del_conn(hcon->l2cap_data);
+
        l2cap_conn_del(hcon, bt_to_errno(reason));
 }
 
@@ -7467,11 +7476,14 @@ int __init l2cap_init(void)
        debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs,
                           &le_default_mps);
 
+       bt_6lowpan_init();
+
        return 0;
 }
 
 void l2cap_exit(void)
 {
+       bt_6lowpan_cleanup();
        debugfs_remove(l2cap_debugfs);
        l2cap_cleanup_sockets();
 }
index e7806e6..20ef748 100644 (file)
@@ -147,6 +147,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
                    __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
                        chan->sec_level = BT_SECURITY_SDP;
                break;
+       case L2CAP_CHAN_RAW:
+               chan->sec_level = BT_SECURITY_SDP;
+               break;
        }
 
        bacpy(&chan->src, &la.l2_bdaddr);
index 84fcf9f..f9c0980 100644 (file)
@@ -58,6 +58,7 @@ struct rfcomm_dev {
        uint                    modem_status;
 
        struct rfcomm_dlc       *dlc;
+       wait_queue_head_t       conn_wait;
 
        struct device           *tty_dev;
 
@@ -103,20 +104,60 @@ static void rfcomm_dev_destruct(struct tty_port *port)
        module_put(THIS_MODULE);
 }
 
-/* device-specific initialization: open the dlc */
-static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
+static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
 {
-       struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
+       struct hci_dev *hdev;
+       struct hci_conn *conn;
 
-       return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
+       hdev = hci_get_route(&dev->dst, &dev->src);
+       if (!hdev)
+               return NULL;
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+
+       hci_dev_put(hdev);
+
+       return conn ? &conn->dev : NULL;
 }
 
-/* we block the open until the dlc->state becomes BT_CONNECTED */
-static int rfcomm_dev_carrier_raised(struct tty_port *port)
+/* device-specific initialization: open the dlc */
+static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
 {
        struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
+       DEFINE_WAIT(wait);
+       int err;
+
+       err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
+       if (err)
+               return err;
+
+       while (1) {
+               prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE);
+
+               if (dev->dlc->state == BT_CLOSED) {
+                       err = -dev->err;
+                       break;
+               }
+
+               if (dev->dlc->state == BT_CONNECTED)
+                       break;
+
+               if (signal_pending(current)) {
+                       err = -ERESTARTSYS;
+                       break;
+               }
+
+               tty_unlock(tty);
+               schedule();
+               tty_lock(tty);
+       }
+       finish_wait(&dev->conn_wait, &wait);
+
+       if (!err)
+               device_move(dev->tty_dev, rfcomm_get_device(dev),
+                           DPM_ORDER_DEV_AFTER_PARENT);
 
-       return (dev->dlc->state == BT_CONNECTED);
+       return err;
 }
 
 /* device-specific cleanup: close the dlc */
@@ -135,7 +176,6 @@ static const struct tty_port_operations rfcomm_port_ops = {
        .destruct = rfcomm_dev_destruct,
        .activate = rfcomm_dev_activate,
        .shutdown = rfcomm_dev_shutdown,
-       .carrier_raised = rfcomm_dev_carrier_raised,
 };
 
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
@@ -169,22 +209,6 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
        return dev;
 }
 
-static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
-{
-       struct hci_dev *hdev;
-       struct hci_conn *conn;
-
-       hdev = hci_get_route(&dev->dst, &dev->src);
-       if (!hdev)
-               return NULL;
-
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
-
-       hci_dev_put(hdev);
-
-       return conn ? &conn->dev : NULL;
-}
-
 static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
 {
        struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
@@ -258,6 +282,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 
        tty_port_init(&dev->port);
        dev->port.ops = &rfcomm_port_ops;
+       init_waitqueue_head(&dev->conn_wait);
 
        skb_queue_head_init(&dev->pending);
 
@@ -437,7 +462,8 @@ static int rfcomm_release_dev(void __user *arg)
                tty_kref_put(tty);
        }
 
-       if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+       if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
+           !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
                tty_port_put(&dev->port);
 
        tty_port_put(&dev->port);
@@ -575,12 +601,9 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
        BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
 
        dev->err = err;
-       if (dlc->state == BT_CONNECTED) {
-               device_move(dev->tty_dev, rfcomm_get_device(dev),
-                           DPM_ORDER_DEV_AFTER_PARENT);
+       wake_up_interruptible(&dev->conn_wait);
 
-               wake_up_interruptible(&dev->port.open_wait);
-       } else if (dlc->state == BT_CLOSED)
+       if (dlc->state == BT_CLOSED)
                tty_port_tty_hangup(&dev->port, false);
 }
 
@@ -670,10 +693,20 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 
        /* install the tty_port */
        err = tty_port_install(&dev->port, driver, tty);
-       if (err)
+       if (err) {
                rfcomm_tty_cleanup(tty);
+               return err;
+       }
 
-       return err;
+       /* take over the tty_port reference if the port was created with the
+        * flag RFCOMM_RELEASE_ONHUP. This will force the release of the port
+        * when the last process closes the tty. The behaviour is expected by
+        * userspace.
+        */
+       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+               tty_port_put(&dev->port);
+
+       return 0;
 }
 
 static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
@@ -1010,10 +1043,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
        BT_DBG("tty %p dev %p", tty, dev);
 
        tty_port_hangup(&dev->port);
-
-       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
-           !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
-               tty_port_put(&dev->port);
 }
 
 static int rfcomm_tty_tiocmget(struct tty_struct *tty)
@@ -1096,7 +1125,7 @@ int __init rfcomm_init_ttys(void)
        rfcomm_tty_driver->subtype      = SERIAL_TYPE_NORMAL;
        rfcomm_tty_driver->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        rfcomm_tty_driver->init_termios = tty_std_termios;
-       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
 
index ba780cc..19311aa 100644 (file)
 
 #include "br_private.h"
 
-static const struct stp_proto br_stp_proto = {
-       .rcv    = br_stp_rcv,
-};
+static void __net_exit br_net_exit(struct net *net)
+{
+       struct net_device *dev;
+       LIST_HEAD(list);
+
+       rtnl_lock();
+       for_each_netdev(net, dev)
+               if (dev->priv_flags & IFF_EBRIDGE)
+                       br_dev_delete(dev, &list);
+
+       unregister_netdevice_many(&list);
+       rtnl_unlock();
+
+}
 
 static struct pernet_operations br_net_ops = {
        .exit   = br_net_exit,
 };
 
+static const struct stp_proto br_stp_proto = {
+       .rcv    = br_stp_rcv,
+};
+
 static int __init br_init(void)
 {
        int err;
index 1f6bd1e..cffe1d6 100644 (file)
@@ -455,18 +455,3 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
 
        return 0;
 }
-
-void __net_exit br_net_exit(struct net *net)
-{
-       struct net_device *dev;
-       LIST_HEAD(list);
-
-       rtnl_lock();
-       for_each_netdev(net, dev)
-               if (dev->priv_flags & IFF_EBRIDGE)
-                       br_dev_delete(dev, &list);
-
-       unregister_netdevice_many(&list);
-       rtnl_unlock();
-
-}
index 3733f15..fcd1233 100644 (file)
@@ -407,7 +407,6 @@ void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
 void br_port_carrier_check(struct net_bridge_port *p);
 int br_add_bridge(struct net *net, const char *name);
 int br_del_bridge(struct net *net, const char *name);
-void br_net_exit(struct net *net);
 int br_add_if(struct net_bridge *br, struct net_device *dev);
 int br_del_if(struct net_bridge *br, struct net_device *dev);
 int br_min_mtu(const struct net_bridge *br);
index 7344a8f..4589ff6 100644 (file)
@@ -285,7 +285,7 @@ static int chnl_net_open(struct net_device *dev)
                                goto error;
                }
 
-               lldev = dev_get_by_index(dev_net(dev), llifindex);
+               lldev = __dev_get_by_index(dev_net(dev), llifindex);
 
                if (lldev == NULL) {
                        pr_debug("no interface?\n");
@@ -307,7 +307,6 @@ static int chnl_net_open(struct net_device *dev)
                mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
                mtu = min_t(int, GPRS_PDP_MTU, mtu);
                dev_set_mtu(dev, mtu);
-               dev_put(lldev);
 
                if (mtu < 100) {
                        pr_warn("CAIF Interface MTU too small (%d)\n", mtu);
index 88c8a39..ac31891 100644 (file)
@@ -839,21 +839,21 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
        if (!gwj->ccgw.src_idx || !gwj->ccgw.dst_idx)
                goto out;
 
-       gwj->src.dev = dev_get_by_index(&init_net, gwj->ccgw.src_idx);
+       gwj->src.dev = __dev_get_by_index(&init_net, gwj->ccgw.src_idx);
 
        if (!gwj->src.dev)
                goto out;
 
        if (gwj->src.dev->type != ARPHRD_CAN)
-               goto put_src_out;
+               goto out;
 
-       gwj->dst.dev = dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
+       gwj->dst.dev = __dev_get_by_index(&init_net, gwj->ccgw.dst_idx);
 
        if (!gwj->dst.dev)
-               goto put_src_out;
+               goto out;
 
        if (gwj->dst.dev->type != ARPHRD_CAN)
-               goto put_src_dst_out;
+               goto out;
 
        gwj->limit_hops = limhops;
 
@@ -862,11 +862,6 @@ static int cgw_create_job(struct sk_buff *skb,  struct nlmsghdr *nlh)
        err = cgw_register_filter(gwj);
        if (!err)
                hlist_add_head_rcu(&gwj->list, &cgw_list);
-
-put_src_dst_out:
-       dev_put(gwj->dst.dev);
-put_src_out:
-       dev_put(gwj->src.dev);
 out:
        if (err)
                kmem_cache_free(cgw_cache, gwj);
index ce01847..9957557 100644 (file)
@@ -147,6 +147,8 @@ struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
 struct list_head ptype_all __read_mostly;      /* Taps */
 static struct list_head offload_base __read_mostly;
 
+static int netif_rx_internal(struct sk_buff *skb);
+
 /*
  * The @dev_base_head list is protected by @dev_base_lock and the rtnl
  * semaphore.
@@ -1117,6 +1119,8 @@ rollback:
 
        write_seqcount_end(&devnet_rename_seq);
 
+       netdev_adjacent_rename_links(dev, oldname);
+
        write_lock_bh(&dev_base_lock);
        hlist_del_rcu(&dev->name_hlist);
        write_unlock_bh(&dev_base_lock);
@@ -1136,6 +1140,7 @@ rollback:
                        err = ret;
                        write_seqcount_begin(&devnet_rename_seq);
                        memcpy(dev->name, oldname, IFNAMSIZ);
+                       memcpy(oldname, newname, IFNAMSIZ);
                        goto rollback;
                } else {
                        pr_err("%s: name change rollback failed: %d\n",
@@ -1698,7 +1703,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
        skb_scrub_packet(skb, true);
        skb->protocol = eth_type_trans(skb, dev);
 
-       return netif_rx(skb);
+       return netif_rx_internal(skb);
 }
 EXPORT_SYMBOL_GPL(dev_forward_skb);
 
@@ -2530,7 +2535,7 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
 EXPORT_SYMBOL(netif_skb_features);
 
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
-                       struct netdev_queue *txq, void *accel_priv)
+                       struct netdev_queue *txq)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
        int rc = NETDEV_TX_OK;
@@ -2596,13 +2601,10 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        dev_queue_xmit_nit(skb, dev);
 
                skb_len = skb->len;
-               if (accel_priv)
-                       rc = ops->ndo_dfwd_start_xmit(skb, dev, accel_priv);
-               else
-                       rc = ops->ndo_start_xmit(skb, dev);
-
+               trace_net_dev_start_xmit(skb, dev);
+               rc = ops->ndo_start_xmit(skb, dev);
                trace_net_dev_xmit(skb, rc, dev, skb_len);
-               if (rc == NETDEV_TX_OK && txq)
+               if (rc == NETDEV_TX_OK)
                        txq_trans_update(txq);
                return rc;
        }
@@ -2618,10 +2620,8 @@ gso:
                        dev_queue_xmit_nit(nskb, dev);
 
                skb_len = nskb->len;
-               if (accel_priv)
-                       rc = ops->ndo_dfwd_start_xmit(nskb, dev, accel_priv);
-               else
-                       rc = ops->ndo_start_xmit(nskb, dev);
+               trace_net_dev_start_xmit(nskb, dev);
+               rc = ops->ndo_start_xmit(nskb, dev);
                trace_net_dev_xmit(nskb, rc, dev, skb_len);
                if (unlikely(rc != NETDEV_TX_OK)) {
                        if (rc & ~NETDEV_TX_MASK)
@@ -2802,7 +2802,7 @@ EXPORT_SYMBOL(dev_loopback_xmit);
  *      the BH enable code must have IRQs enabled so that it will not deadlock.
  *          --BLG
  */
-int dev_queue_xmit(struct sk_buff *skb)
+int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
 {
        struct net_device *dev = skb->dev;
        struct netdev_queue *txq;
@@ -2818,7 +2818,7 @@ int dev_queue_xmit(struct sk_buff *skb)
 
        skb_update_prio(skb);
 
-       txq = netdev_pick_tx(dev, skb);
+       txq = netdev_pick_tx(dev, skb, accel_priv);
        q = rcu_dereference_bh(txq->qdisc);
 
 #ifdef CONFIG_NET_CLS_ACT
@@ -2854,7 +2854,7 @@ int dev_queue_xmit(struct sk_buff *skb)
 
                        if (!netif_xmit_stopped(txq)) {
                                __this_cpu_inc(xmit_recursion);
-                               rc = dev_hard_start_xmit(skb, dev, txq, NULL);
+                               rc = dev_hard_start_xmit(skb, dev, txq);
                                __this_cpu_dec(xmit_recursion);
                                if (dev_xmit_complete(rc)) {
                                        HARD_TX_UNLOCK(dev, txq);
@@ -2883,8 +2883,19 @@ out:
        rcu_read_unlock_bh();
        return rc;
 }
+
+int dev_queue_xmit(struct sk_buff *skb)
+{
+       return __dev_queue_xmit(skb, NULL);
+}
 EXPORT_SYMBOL(dev_queue_xmit);
 
+int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv)
+{
+       return __dev_queue_xmit(skb, accel_priv);
+}
+EXPORT_SYMBOL(dev_queue_xmit_accel);
+
 
 /*=======================================================================
                        Receiver routines
@@ -3213,22 +3224,7 @@ enqueue:
        return NET_RX_DROP;
 }
 
-/**
- *     netif_rx        -       post buffer to the network code
- *     @skb: buffer to post
- *
- *     This function receives a packet from a device driver and queues it for
- *     the upper (protocol) levels to process.  It always succeeds. The buffer
- *     may be dropped during processing for congestion control or by the
- *     protocol layers.
- *
- *     return values:
- *     NET_RX_SUCCESS  (no congestion)
- *     NET_RX_DROP     (packet was dropped)
- *
- */
-
-int netif_rx(struct sk_buff *skb)
+static int netif_rx_internal(struct sk_buff *skb)
 {
        int ret;
 
@@ -3264,14 +3260,38 @@ int netif_rx(struct sk_buff *skb)
        }
        return ret;
 }
+
+/**
+ *     netif_rx        -       post buffer to the network code
+ *     @skb: buffer to post
+ *
+ *     This function receives a packet from a device driver and queues it for
+ *     the upper (protocol) levels to process.  It always succeeds. The buffer
+ *     may be dropped during processing for congestion control or by the
+ *     protocol layers.
+ *
+ *     return values:
+ *     NET_RX_SUCCESS  (no congestion)
+ *     NET_RX_DROP     (packet was dropped)
+ *
+ */
+
+int netif_rx(struct sk_buff *skb)
+{
+       trace_netif_rx_entry(skb);
+
+       return netif_rx_internal(skb);
+}
 EXPORT_SYMBOL(netif_rx);
 
 int netif_rx_ni(struct sk_buff *skb)
 {
        int err;
 
+       trace_netif_rx_ni_entry(skb);
+
        preempt_disable();
-       err = netif_rx(skb);
+       err = netif_rx_internal(skb);
        if (local_softirq_pending())
                do_softirq();
        preempt_enable();
@@ -3656,22 +3676,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
        return ret;
 }
 
-/**
- *     netif_receive_skb - process receive buffer from network
- *     @skb: buffer to process
- *
- *     netif_receive_skb() is the main receive data processing function.
- *     It always succeeds. The buffer may be dropped during processing
- *     for congestion control or by the protocol layers.
- *
- *     This function may only be called from softirq context and interrupts
- *     should be enabled.
- *
- *     Return values (usually ignored):
- *     NET_RX_SUCCESS: no congestion
- *     NET_RX_DROP: packet was dropped
- */
-int netif_receive_skb(struct sk_buff *skb)
+static int netif_receive_skb_internal(struct sk_buff *skb)
 {
        net_timestamp_check(netdev_tstamp_prequeue, skb);
 
@@ -3697,6 +3702,28 @@ int netif_receive_skb(struct sk_buff *skb)
 #endif
        return __netif_receive_skb(skb);
 }
+
+/**
+ *     netif_receive_skb - process receive buffer from network
+ *     @skb: buffer to process
+ *
+ *     netif_receive_skb() is the main receive data processing function.
+ *     It always succeeds. The buffer may be dropped during processing
+ *     for congestion control or by the protocol layers.
+ *
+ *     This function may only be called from softirq context and interrupts
+ *     should be enabled.
+ *
+ *     Return values (usually ignored):
+ *     NET_RX_SUCCESS: no congestion
+ *     NET_RX_DROP: packet was dropped
+ */
+int netif_receive_skb(struct sk_buff *skb)
+{
+       trace_netif_receive_skb_entry(skb);
+
+       return netif_receive_skb_internal(skb);
+}
 EXPORT_SYMBOL(netif_receive_skb);
 
 /* Network device is going away, flush any packets still pending
@@ -3758,7 +3785,7 @@ static int napi_gro_complete(struct sk_buff *skb)
        }
 
 out:
-       return netif_receive_skb(skb);
+       return netif_receive_skb_internal(skb);
 }
 
 /* napi->gro_list contains packets ordered by age.
@@ -3882,10 +3909,23 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
        if (same_flow)
                goto ok;
 
-       if (NAPI_GRO_CB(skb)->flush || napi->gro_count >= MAX_GRO_SKBS)
+       if (NAPI_GRO_CB(skb)->flush)
                goto normal;
 
-       napi->gro_count++;
+       if (unlikely(napi->gro_count >= MAX_GRO_SKBS)) {
+               struct sk_buff *nskb = napi->gro_list;
+
+               /* locate the end of the list to select the 'oldest' flow */
+               while (nskb->next) {
+                       pp = &nskb->next;
+                       nskb = *pp;
+               }
+               *pp = NULL;
+               nskb->next = NULL;
+               napi_gro_complete(nskb);
+       } else {
+               napi->gro_count++;
+       }
        NAPI_GRO_CB(skb)->count = 1;
        NAPI_GRO_CB(skb)->age = jiffies;
        skb_shinfo(skb)->gso_size = skb_gro_len(skb);
@@ -3953,7 +3993,7 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
 {
        switch (ret) {
        case GRO_NORMAL:
-               if (netif_receive_skb(skb))
+               if (netif_receive_skb_internal(skb))
                        ret = GRO_DROP;
                break;
 
@@ -3978,6 +4018,8 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb)
 
 gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
+       trace_napi_gro_receive_entry(skb);
+
        return napi_skb_finish(dev_gro_receive(napi, skb), skb);
 }
 EXPORT_SYMBOL(napi_gro_receive);
@@ -4011,7 +4053,7 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *
 {
        switch (ret) {
        case GRO_NORMAL:
-               if (netif_receive_skb(skb))
+               if (netif_receive_skb_internal(skb))
                        ret = GRO_DROP;
                break;
 
@@ -4050,6 +4092,8 @@ gro_result_t napi_gro_frags(struct napi_struct *napi)
        if (!skb)
                return GRO_DROP;
 
+       trace_napi_gro_frags_entry(skb);
+
        return napi_frags_finish(napi, skb, dev_gro_receive(napi, skb));
 }
 EXPORT_SYMBOL(napi_gro_frags);
@@ -4582,13 +4626,36 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev)
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu);
 
+int netdev_adjacent_sysfs_add(struct net_device *dev,
+                             struct net_device *adj_dev,
+                             struct list_head *dev_list)
+{
+       char linkname[IFNAMSIZ+7];
+       sprintf(linkname, dev_list == &dev->adj_list.upper ?
+               "upper_%s" : "lower_%s", adj_dev->name);
+       return sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj),
+                                linkname);
+}
+void netdev_adjacent_sysfs_del(struct net_device *dev,
+                              char *name,
+                              struct list_head *dev_list)
+{
+       char linkname[IFNAMSIZ+7];
+       sprintf(linkname, dev_list == &dev->adj_list.upper ?
+               "upper_%s" : "lower_%s", name);
+       sysfs_remove_link(&(dev->dev.kobj), linkname);
+}
+
+#define netdev_adjacent_is_neigh_list(dev, dev_list) \
+               (dev_list == &dev->adj_list.upper || \
+                dev_list == &dev->adj_list.lower)
+
 static int __netdev_adjacent_dev_insert(struct net_device *dev,
                                        struct net_device *adj_dev,
                                        struct list_head *dev_list,
                                        void *private, bool master)
 {
        struct netdev_adjacent *adj;
-       char linkname[IFNAMSIZ+7];
        int ret;
 
        adj = __netdev_find_adj(dev, adj_dev, dev_list);
@@ -4611,16 +4678,8 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
        pr_debug("dev_hold for %s, because of link added from %s to %s\n",
                 adj_dev->name, dev->name, adj_dev->name);
 
-       if (dev_list == &dev->adj_list.lower) {
-               sprintf(linkname, "lower_%s", adj_dev->name);
-               ret = sysfs_create_link(&(dev->dev.kobj),
-                                       &(adj_dev->dev.kobj), linkname);
-               if (ret)
-                       goto free_adj;
-       } else if (dev_list == &dev->adj_list.upper) {
-               sprintf(linkname, "upper_%s", adj_dev->name);
-               ret = sysfs_create_link(&(dev->dev.kobj),
-                                       &(adj_dev->dev.kobj), linkname);
+       if (netdev_adjacent_is_neigh_list(dev, dev_list)) {
+               ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list);
                if (ret)
                        goto free_adj;
        }
@@ -4640,14 +4699,8 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
        return 0;
 
 remove_symlinks:
-       if (dev_list == &dev->adj_list.lower) {
-               sprintf(linkname, "lower_%s", adj_dev->name);
-               sysfs_remove_link(&(dev->dev.kobj), linkname);
-       } else if (dev_list == &dev->adj_list.upper) {
-               sprintf(linkname, "upper_%s", adj_dev->name);
-               sysfs_remove_link(&(dev->dev.kobj), linkname);
-       }
-
+       if (netdev_adjacent_is_neigh_list(dev, dev_list))
+               netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
 free_adj:
        kfree(adj);
        dev_put(adj_dev);
@@ -4660,7 +4713,6 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
                                         struct list_head *dev_list)
 {
        struct netdev_adjacent *adj;
-       char linkname[IFNAMSIZ+7];
 
        adj = __netdev_find_adj(dev, adj_dev, dev_list);
 
@@ -4680,13 +4732,8 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
        if (adj->master)
                sysfs_remove_link(&(dev->dev.kobj), "master");
 
-       if (dev_list == &dev->adj_list.lower) {
-               sprintf(linkname, "lower_%s", adj_dev->name);
-               sysfs_remove_link(&(dev->dev.kobj), linkname);
-       } else if (dev_list == &dev->adj_list.upper) {
-               sprintf(linkname, "upper_%s", adj_dev->name);
-               sysfs_remove_link(&(dev->dev.kobj), linkname);
-       }
+       if (netdev_adjacent_is_neigh_list(dev, dev_list))
+               netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
 
        list_del_rcu(&adj->list);
        pr_debug("dev_put for %s, because link removed from %s to %s\n",
@@ -4955,6 +5002,25 @@ void netdev_upper_dev_unlink(struct net_device *dev,
 }
 EXPORT_SYMBOL(netdev_upper_dev_unlink);
 
+void netdev_adjacent_rename_links(struct net_device *dev, char *oldname)
+{
+       struct netdev_adjacent *iter;
+
+       list_for_each_entry(iter, &dev->adj_list.upper, list) {
+               netdev_adjacent_sysfs_del(iter->dev, oldname,
+                                         &iter->dev->adj_list.lower);
+               netdev_adjacent_sysfs_add(iter->dev, dev,
+                                         &iter->dev->adj_list.lower);
+       }
+
+       list_for_each_entry(iter, &dev->adj_list.lower, list) {
+               netdev_adjacent_sysfs_del(iter->dev, oldname,
+                                         &iter->dev->adj_list.upper);
+               netdev_adjacent_sysfs_add(iter->dev, dev,
+                                         &iter->dev->adj_list.upper);
+       }
+}
+
 void *netdev_lower_dev_get_private(struct net_device *dev,
                                   struct net_device *lower_dev)
 {
@@ -5287,6 +5353,17 @@ int dev_change_flags(struct net_device *dev, unsigned int flags)
 }
 EXPORT_SYMBOL(dev_change_flags);
 
+static int __dev_set_mtu(struct net_device *dev, int new_mtu)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       if (ops->ndo_change_mtu)
+               return ops->ndo_change_mtu(dev, new_mtu);
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 /**
  *     dev_set_mtu - Change maximum transfer unit
  *     @dev: device
@@ -5296,8 +5373,7 @@ EXPORT_SYMBOL(dev_change_flags);
  */
 int dev_set_mtu(struct net_device *dev, int new_mtu)
 {
-       const struct net_device_ops *ops = dev->netdev_ops;
-       int err;
+       int err, orig_mtu;
 
        if (new_mtu == dev->mtu)
                return 0;
@@ -5309,14 +5385,20 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
        if (!netif_device_present(dev))
                return -ENODEV;
 
-       err = 0;
-       if (ops->ndo_change_mtu)
-               err = ops->ndo_change_mtu(dev, new_mtu);
-       else
-               dev->mtu = new_mtu;
+       orig_mtu = dev->mtu;
+       err = __dev_set_mtu(dev, new_mtu);
 
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
+       if (!err) {
+               err = call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
+               err = notifier_to_errno(err);
+               if (err) {
+                       /* setting mtu back and notifying everyone again,
+                        * so that they have a chance to revert changes.
+                        */
+                       __dev_set_mtu(dev, orig_mtu);
+                       call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
+               }
+       }
        return err;
 }
 EXPORT_SYMBOL(dev_set_mtu);
@@ -6586,11 +6668,11 @@ static int dev_cpu_callback(struct notifier_block *nfb,
 
        /* Process offline CPU's input_pkt_queue */
        while ((skb = __skb_dequeue(&oldsd->process_queue))) {
-               netif_rx(skb);
+               netif_rx_internal(skb);
                input_queue_head_incr(oldsd);
        }
        while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) {
-               netif_rx(skb);
+               netif_rx_internal(skb);
                input_queue_head_incr(oldsd);
        }
 
index b324bfa..87577d4 100644 (file)
@@ -395,17 +395,21 @@ u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
 EXPORT_SYMBOL(__netdev_pick_tx);
 
 struct netdev_queue *netdev_pick_tx(struct net_device *dev,
-                                   struct sk_buff *skb)
+                                   struct sk_buff *skb,
+                                   void *accel_priv)
 {
        int queue_index = 0;
 
        if (dev->real_num_tx_queues != 1) {
                const struct net_device_ops *ops = dev->netdev_ops;
                if (ops->ndo_select_queue)
-                       queue_index = ops->ndo_select_queue(dev, skb);
+                       queue_index = ops->ndo_select_queue(dev, skb,
+                                                           accel_priv);
                else
                        queue_index = __netdev_pick_tx(dev, skb);
-               queue_index = dev_cap_txqueue(dev, queue_index);
+
+               if (!accel_priv)
+                       queue_index = dev_cap_txqueue(dev, queue_index);
        }
 
        skb_set_queue_mapping(skb, queue_index);
index ea97361..f8012fe 100644 (file)
@@ -117,7 +117,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh)
 
 unsigned long neigh_rand_reach_time(unsigned long base)
 {
-       return base ? (net_random() % base) + (base >> 1) : 0;
+       return base ? (prandom_u32() % base) + (base >> 1) : 0;
 }
 EXPORT_SYMBOL(neigh_rand_reach_time);
 
@@ -1415,7 +1415,8 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
                    struct sk_buff *skb)
 {
        unsigned long now = jiffies;
-       unsigned long sched_next = now + (net_random() %
+
+       unsigned long sched_next = now + (prandom_u32() %
                                          NEIGH_VAR(p, PROXY_DELAY));
 
        if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
@@ -2086,13 +2087,16 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
                                              nla_get_msecs(tbp[i]));
                                break;
                        case NDTPA_ANYCAST_DELAY:
-                               NEIGH_VAR_SET(p, ANYCAST_DELAY, nla_get_msecs(tbp[i]));
+                               NEIGH_VAR_SET(p, ANYCAST_DELAY,
+                                             nla_get_msecs(tbp[i]));
                                break;
                        case NDTPA_PROXY_DELAY:
-                               NEIGH_VAR_SET(p, PROXY_DELAY, nla_get_msecs(tbp[i]));
+                               NEIGH_VAR_SET(p, PROXY_DELAY,
+                                             nla_get_msecs(tbp[i]));
                                break;
                        case NDTPA_LOCKTIME:
-                               NEIGH_VAR_SET(p, LOCKTIME, nla_get_msecs(tbp[i]));
+                               NEIGH_VAR_SET(p, LOCKTIME,
+                                             nla_get_msecs(tbp[i]));
                                break;
                        }
                }
index 3030978..19fe9c7 100644 (file)
@@ -375,7 +375,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
        if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) {
                struct netdev_queue *txq;
 
-               txq = netdev_pick_tx(dev, skb);
+               txq = netdev_pick_tx(dev, skb, NULL);
 
                /* try until next clock tick */
                for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
index a797fff..fa3e128 100644 (file)
@@ -389,6 +389,9 @@ struct pktgen_dev {
 #ifdef CONFIG_XFRM
        __u8    ipsmode;                /* IPSEC mode (config) */
        __u8    ipsproto;               /* IPSEC type (config) */
+       __u32   spi;
+       struct dst_entry dst;
+       struct dst_ops dstops;
 #endif
        char result[512];
 };
@@ -654,8 +657,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        }
 
 #ifdef CONFIG_XFRM
-       if (pkt_dev->flags & F_IPSEC_ON)
+       if (pkt_dev->flags & F_IPSEC_ON) {
                seq_printf(seq,  "IPSEC  ");
+               if (pkt_dev->spi)
+                       seq_printf(seq, "spi:%u", pkt_dev->spi);
+       }
 #endif
 
        if (pkt_dev->flags & F_MACSRC_RND)
@@ -1476,7 +1482,18 @@ static ssize_t pktgen_if_write(struct file *file,
                sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
                return count;
        }
+#ifdef CONFIG_XFRM
+       if (!strcmp(name, "spi")) {
+               len = num_arg(&user_buffer[i], 10, &value);
+               if (len < 0)
+                       return len;
 
+               i += len;
+               pkt_dev->spi = value;
+               sprintf(pg_result, "OK: spi=%u", pkt_dev->spi);
+               return count;
+       }
+#endif
        if (!strcmp(name, "flowlen")) {
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
@@ -2233,13 +2250,21 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
        struct xfrm_state *x = pkt_dev->flows[flow].x;
        struct pktgen_net *pn = net_generic(dev_net(pkt_dev->odev), pg_net_id);
        if (!x) {
-               /*slow path: we dont already have xfrm_state*/
-               x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
-                                       (xfrm_address_t *)&pkt_dev->cur_daddr,
-                                       (xfrm_address_t *)&pkt_dev->cur_saddr,
-                                       AF_INET,
-                                       pkt_dev->ipsmode,
-                                       pkt_dev->ipsproto, 0);
+
+               if (pkt_dev->spi) {
+                       /* We need as quick as possible to find the right SA
+                        * Searching with minimum criteria to archieve this.
+                        */
+                       x = xfrm_state_lookup_byspi(pn->net, htonl(pkt_dev->spi), AF_INET);
+               } else {
+                       /* slow path: we dont already have xfrm_state */
+                       x = xfrm_stateonly_find(pn->net, DUMMY_MARK,
+                                               (xfrm_address_t *)&pkt_dev->cur_daddr,
+                                               (xfrm_address_t *)&pkt_dev->cur_saddr,
+                                               AF_INET,
+                                               pkt_dev->ipsmode,
+                                               pkt_dev->ipsproto, 0);
+               }
                if (x) {
                        pkt_dev->flows[flow].x = x;
                        set_pkt_overhead(pkt_dev);
@@ -2475,31 +2500,47 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
 
 #ifdef CONFIG_XFRM
+static u32 pktgen_dst_metrics[RTAX_MAX + 1] = {
+
+       [RTAX_HOPLIMIT] = 0x5, /* Set a static hoplimit */
+};
+
 static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
 {
        struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
        int err = 0;
+       struct net *net = dev_net(pkt_dev->odev);
 
        if (!x)
                return 0;
        /* XXX: we dont support tunnel mode for now until
         * we resolve the dst issue */
-       if (x->props.mode != XFRM_MODE_TRANSPORT)
+       if ((x->props.mode != XFRM_MODE_TRANSPORT) && (pkt_dev->spi == 0))
                return 0;
 
-       spin_lock(&x->lock);
+       /* But when user specify an valid SPI, transformation
+        * supports both transport/tunnel mode + ESP/AH type.
+        */
+       if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
+               skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF;
 
+       rcu_read_lock_bh();
        err = x->outer_mode->output(x, skb);
-       if (err)
+       rcu_read_unlock_bh();
+       if (err) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR);
                goto error;
+       }
        err = x->type->output(x, skb);
-       if (err)
+       if (err) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR);
                goto error;
-
+       }
+       spin_lock_bh(&x->lock);
        x->curlft.bytes += skb->len;
        x->curlft.packets++;
+       spin_unlock_bh(&x->lock);
 error:
-       spin_unlock(&x->lock);
        return err;
 }
 
@@ -3542,6 +3583,17 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 #ifdef CONFIG_XFRM
        pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
        pkt_dev->ipsproto = IPPROTO_ESP;
+
+       /* xfrm tunnel mode needs additional dst to extract outter
+        * ip header protocol/ttl/id field, here creat a phony one.
+        * instead of looking for a valid rt, which definitely hurting
+        * performance under such circumstance.
+        */
+       pkt_dev->dstops.family = AF_INET;
+       pkt_dev->dst.dev = pkt_dev->odev;
+       dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false);
+       pkt_dev->dst.child = &pkt_dev->dst;
+       pkt_dev->dst.ops = &pkt_dev->dstops;
 #endif
 
        return add_dev_to_thread(t, pkt_dev);
index 1d641e7..15057d2 100644 (file)
@@ -65,6 +65,7 @@
 #include <net/dst.h>
 #include <net/sock.h>
 #include <net/checksum.h>
+#include <net/ip6_checksum.h>
 #include <net/xfrm.h>
 
 #include <asm/uaccess.h>
@@ -3549,6 +3550,278 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
 }
 EXPORT_SYMBOL_GPL(skb_partial_csum_set);
 
+static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len,
+                              unsigned int max)
+{
+       if (skb_headlen(skb) >= len)
+               return 0;
+
+       /* If we need to pullup then pullup to the max, so we
+        * won't need to do it again.
+        */
+       if (max > skb->len)
+               max = skb->len;
+
+       if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
+               return -ENOMEM;
+
+       if (skb_headlen(skb) < len)
+               return -EPROTO;
+
+       return 0;
+}
+
+/* This value should be large enough to cover a tagged ethernet header plus
+ * maximally sized IP and TCP or UDP headers.
+ */
+#define MAX_IP_HDR_LEN 128
+
+static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate)
+{
+       unsigned int off;
+       bool fragment;
+       int err;
+
+       fragment = false;
+
+       err = skb_maybe_pull_tail(skb,
+                                 sizeof(struct iphdr),
+                                 MAX_IP_HDR_LEN);
+       if (err < 0)
+               goto out;
+
+       if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF))
+               fragment = true;
+
+       off = ip_hdrlen(skb);
+
+       err = -EPROTO;
+
+       if (fragment)
+               goto out;
+
+       switch (ip_hdr(skb)->protocol) {
+       case IPPROTO_TCP:
+               err = skb_maybe_pull_tail(skb,
+                                         off + sizeof(struct tcphdr),
+                                         MAX_IP_HDR_LEN);
+               if (err < 0)
+                       goto out;
+
+               if (!skb_partial_csum_set(skb, off,
+                                         offsetof(struct tcphdr, check))) {
+                       err = -EPROTO;
+                       goto out;
+               }
+
+               if (recalculate)
+                       tcp_hdr(skb)->check =
+                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                                  ip_hdr(skb)->daddr,
+                                                  skb->len - off,
+                                                  IPPROTO_TCP, 0);
+               break;
+       case IPPROTO_UDP:
+               err = skb_maybe_pull_tail(skb,
+                                         off + sizeof(struct udphdr),
+                                         MAX_IP_HDR_LEN);
+               if (err < 0)
+                       goto out;
+
+               if (!skb_partial_csum_set(skb, off,
+                                         offsetof(struct udphdr, check))) {
+                       err = -EPROTO;
+                       goto out;
+               }
+
+               if (recalculate)
+                       udp_hdr(skb)->check =
+                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                                  ip_hdr(skb)->daddr,
+                                                  skb->len - off,
+                                                  IPPROTO_UDP, 0);
+               break;
+       default:
+               goto out;
+       }
+
+       err = 0;
+
+out:
+       return err;
+}
+
+/* This value should be large enough to cover a tagged ethernet header plus
+ * an IPv6 header, all options, and a maximal TCP or UDP header.
+ */
+#define MAX_IPV6_HDR_LEN 256
+
+#define OPT_HDR(type, skb, off) \
+       (type *)(skb_network_header(skb) + (off))
+
+static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
+{
+       int err;
+       u8 nexthdr;
+       unsigned int off;
+       unsigned int len;
+       bool fragment;
+       bool done;
+
+       fragment = false;
+       done = false;
+
+       off = sizeof(struct ipv6hdr);
+
+       err = skb_maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN);
+       if (err < 0)
+               goto out;
+
+       nexthdr = ipv6_hdr(skb)->nexthdr;
+
+       len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len);
+       while (off <= len && !done) {
+               switch (nexthdr) {
+               case IPPROTO_DSTOPTS:
+               case IPPROTO_HOPOPTS:
+               case IPPROTO_ROUTING: {
+                       struct ipv6_opt_hdr *hp;
+
+                       err = skb_maybe_pull_tail(skb,
+                                                 off +
+                                                 sizeof(struct ipv6_opt_hdr),
+                                                 MAX_IPV6_HDR_LEN);
+                       if (err < 0)
+                               goto out;
+
+                       hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
+                       nexthdr = hp->nexthdr;
+                       off += ipv6_optlen(hp);
+                       break;
+               }
+               case IPPROTO_AH: {
+                       struct ip_auth_hdr *hp;
+
+                       err = skb_maybe_pull_tail(skb,
+                                                 off +
+                                                 sizeof(struct ip_auth_hdr),
+                                                 MAX_IPV6_HDR_LEN);
+                       if (err < 0)
+                               goto out;
+
+                       hp = OPT_HDR(struct ip_auth_hdr, skb, off);
+                       nexthdr = hp->nexthdr;
+                       off += ipv6_authlen(hp);
+                       break;
+               }
+               case IPPROTO_FRAGMENT: {
+                       struct frag_hdr *hp;
+
+                       err = skb_maybe_pull_tail(skb,
+                                                 off +
+                                                 sizeof(struct frag_hdr),
+                                                 MAX_IPV6_HDR_LEN);
+                       if (err < 0)
+                               goto out;
+
+                       hp = OPT_HDR(struct frag_hdr, skb, off);
+
+                       if (hp->frag_off & htons(IP6_OFFSET | IP6_MF))
+                               fragment = true;
+
+                       nexthdr = hp->nexthdr;
+                       off += sizeof(struct frag_hdr);
+                       break;
+               }
+               default:
+                       done = true;
+                       break;
+               }
+       }
+
+       err = -EPROTO;
+
+       if (!done || fragment)
+               goto out;
+
+       switch (nexthdr) {
+       case IPPROTO_TCP:
+               err = skb_maybe_pull_tail(skb,
+                                         off + sizeof(struct tcphdr),
+                                         MAX_IPV6_HDR_LEN);
+               if (err < 0)
+                       goto out;
+
+               if (!skb_partial_csum_set(skb, off,
+                                         offsetof(struct tcphdr, check))) {
+                       err = -EPROTO;
+                       goto out;
+               }
+
+               if (recalculate)
+                       tcp_hdr(skb)->check =
+                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                                &ipv6_hdr(skb)->daddr,
+                                                skb->len - off,
+                                                IPPROTO_TCP, 0);
+               break;
+       case IPPROTO_UDP:
+               err = skb_maybe_pull_tail(skb,
+                                         off + sizeof(struct udphdr),
+                                         MAX_IPV6_HDR_LEN);
+               if (err < 0)
+                       goto out;
+
+               if (!skb_partial_csum_set(skb, off,
+                                         offsetof(struct udphdr, check))) {
+                       err = -EPROTO;
+                       goto out;
+               }
+
+               if (recalculate)
+                       udp_hdr(skb)->check =
+                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                                &ipv6_hdr(skb)->daddr,
+                                                skb->len - off,
+                                                IPPROTO_UDP, 0);
+               break;
+       default:
+               goto out;
+       }
+
+       err = 0;
+
+out:
+       return err;
+}
+
+/**
+ * skb_checksum_setup - set up partial checksum offset
+ * @skb: the skb to set up
+ * @recalculate: if true the pseudo-header checksum will be recalculated
+ */
+int skb_checksum_setup(struct sk_buff *skb, bool recalculate)
+{
+       int err;
+
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+               err = skb_checksum_setup_ip(skb, recalculate);
+               break;
+
+       case htons(ETH_P_IPV6):
+               err = skb_checksum_setup_ipv6(skb, recalculate);
+               break;
+
+       default:
+               err = -EPROTO;
+               break;
+       }
+
+       return err;
+}
+EXPORT_SYMBOL(skb_checksum_setup);
+
 void __skb_warn_lro_forwarding(const struct sk_buff *skb)
 {
        net_warn_ratelimited("%s: received packets cannot be forwarded while LRO is enabled\n",
index 512f0a2..301c05f 100644 (file)
@@ -122,7 +122,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
        DEFINE_WAIT(wait);
 
        if (sk_stream_memory_free(sk))
-               current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2;
+               current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2;
 
        while (1) {
                set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
index 66fbe19..5536444 100644 (file)
@@ -1688,21 +1688,17 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (!tb[DCB_ATTR_IFNAME])
                return -EINVAL;
 
-       netdev = dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME]));
+       netdev = __dev_get_by_name(net, nla_data(tb[DCB_ATTR_IFNAME]));
        if (!netdev)
                return -ENODEV;
 
-       if (!netdev->dcbnl_ops) {
-               ret = -EOPNOTSUPP;
-               goto out;
-       }
+       if (!netdev->dcbnl_ops)
+               return -EOPNOTSUPP;
 
        reply_skb = dcbnl_newmsg(fn->type, dcb->cmd, portid, nlh->nlmsg_seq,
                                 nlh->nlmsg_flags, &reply_nlh);
-       if (!reply_skb) {
-               ret = -ENOBUFS;
-               goto out;
-       }
+       if (!reply_skb)
+               return -ENOBUFS;
 
        ret = fn->cb(netdev, nlh, nlh->nlmsg_seq, tb, reply_skb);
        if (ret < 0) {
@@ -1714,7 +1710,6 @@ static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
 
        ret = rtnl_unicast(reply_skb, net, portid);
 out:
-       dev_put(netdev);
        return ret;
 }
 
index 88299c2..22b5d81 100644 (file)
@@ -989,6 +989,7 @@ static const struct net_protocol dccp_v4_protocol = {
        .err_handler    = dccp_v4_err,
        .no_policy      = 1,
        .netns_ok       = 1,
+       .icmp_strict_tag_validation = 1,
 };
 
 static const struct proto_ops inet_dccp_ops = {
index ad2efa5..ce0cbbf 100644 (file)
@@ -1666,12 +1666,8 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 
        if (fld.flowidn_iif) {
                struct net_device *dev;
-               if ((dev = dev_get_by_index(&init_net, fld.flowidn_iif)) == NULL) {
-                       kfree_skb(skb);
-                       return -ENODEV;
-               }
-               if (!dev->dn_ptr) {
-                       dev_put(dev);
+               dev = __dev_get_by_index(&init_net, fld.flowidn_iif);
+               if (!dev || !dev->dn_ptr) {
                        kfree_skb(skb);
                        return -ENODEV;
                }
@@ -1693,8 +1689,6 @@ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh)
                err = dn_route_output_key((struct dst_entry **)&rt, &fld, 0);
        }
 
-       if (skb->dev)
-               dev_put(skb->dev);
        skb->dev = NULL;
        if (err)
                goto out_free;
index a2d2456..48b25c0 100644 (file)
@@ -62,9 +62,6 @@
 
 #include "6lowpan.h"
 
-/* TTL uncompression values */
-static const u8 lowpan_ttl_values[] = {0, 1, 64, 255};
-
 static LIST_HEAD(lowpan_devices);
 
 /* private device info */
@@ -104,378 +101,14 @@ static inline void lowpan_address_flip(u8 *src, u8 *dest)
                (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
 }
 
-/* list of all 6lowpan devices, uses for package delivering */
-/* print data in line */
-static inline void lowpan_raw_dump_inline(const char *caller, char *msg,
-                                  unsigned char *buf, int len)
-{
-#ifdef DEBUG
-       if (msg)
-               pr_debug("(%s) %s: ", caller, msg);
-       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,
-                      16, 1, buf, len, false);
-#endif /* DEBUG */
-}
-
-/*
- * print data in a table format:
- *
- * addr: xx xx xx xx xx xx
- * addr: xx xx xx xx xx xx
- * ...
- */
-static inline void lowpan_raw_dump_table(const char *caller, char *msg,
-                                  unsigned char *buf, int len)
-{
-#ifdef DEBUG
-       if (msg)
-               pr_debug("(%s) %s:\n", caller, msg);
-       print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET,
-                      16, 1, buf, len, false);
-#endif /* DEBUG */
-}
-
-static u8
-lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
-                const unsigned char *lladdr)
-{
-       u8 val = 0;
-
-       if (is_addr_mac_addr_based(ipaddr, lladdr))
-               val = 3; /* 0-bits */
-       else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
-               /* compress IID to 16 bits xxxx::XXXX */
-               memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
-               *hc06_ptr += 2;
-               val = 2; /* 16-bits */
-       } else {
-               /* do not compress IID => xxxx::IID */
-               memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
-               *hc06_ptr += 8;
-               val = 1; /* 64-bits */
-       }
-
-       return rol8(val, shift);
-}
-
-/*
- * Uncompress address function for source and
- * destination address(non-multicast).
- *
- * address_mode is sam value or dam value.
- */
-static int
-lowpan_uncompress_addr(struct sk_buff *skb,
-               struct in6_addr *ipaddr,
-               const u8 address_mode,
-               const struct ieee802154_addr *lladdr)
-{
-       bool fail;
-
-       switch (address_mode) {
-       case LOWPAN_IPHC_ADDR_00:
-               /* for global link addresses */
-               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
-               break;
-       case LOWPAN_IPHC_ADDR_01:
-               /* fe:80::XXXX:XXXX:XXXX:XXXX */
-               ipaddr->s6_addr[0] = 0xFE;
-               ipaddr->s6_addr[1] = 0x80;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
-               break;
-       case LOWPAN_IPHC_ADDR_02:
-               /* fe:80::ff:fe00:XXXX */
-               ipaddr->s6_addr[0] = 0xFE;
-               ipaddr->s6_addr[1] = 0x80;
-               ipaddr->s6_addr[11] = 0xFF;
-               ipaddr->s6_addr[12] = 0xFE;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
-               break;
-       case LOWPAN_IPHC_ADDR_03:
-               fail = false;
-               switch (lladdr->addr_type) {
-               case IEEE802154_ADDR_LONG:
-                       /* fe:80::XXXX:XXXX:XXXX:XXXX
-                        *        \_________________/
-                        *              hwaddr
-                        */
-                       ipaddr->s6_addr[0] = 0xFE;
-                       ipaddr->s6_addr[1] = 0x80;
-                       memcpy(&ipaddr->s6_addr[8], lladdr->hwaddr,
-                                       IEEE802154_ADDR_LEN);
-                       /* second bit-flip (Universe/Local)
-                        * is done according RFC2464
-                        */
-                       ipaddr->s6_addr[8] ^= 0x02;
-                       break;
-               case IEEE802154_ADDR_SHORT:
-                       /* fe:80::ff:fe00:XXXX
-                        *                \__/
-                        *             short_addr
-                        *
-                        * Universe/Local bit is zero.
-                        */
-                       ipaddr->s6_addr[0] = 0xFE;
-                       ipaddr->s6_addr[1] = 0x80;
-                       ipaddr->s6_addr[11] = 0xFF;
-                       ipaddr->s6_addr[12] = 0xFE;
-                       ipaddr->s6_addr16[7] = htons(lladdr->short_addr);
-                       break;
-               default:
-                       pr_debug("Invalid addr_type set\n");
-                       return -EINVAL;
-               }
-               break;
-       default:
-               pr_debug("Invalid address mode value: 0x%x\n", address_mode);
-               return -EINVAL;
-       }
-
-       if (fail) {
-               pr_debug("Failed to fetch skb data\n");
-               return -EIO;
-       }
-
-       lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is:\n",
-                       ipaddr->s6_addr, 16);
-
-       return 0;
-}
-
-/* Uncompress address function for source context
- * based address(non-multicast).
- */
-static int
-lowpan_uncompress_context_based_src_addr(struct sk_buff *skb,
-               struct in6_addr *ipaddr,
-               const u8 sam)
-{
-       switch (sam) {
-       case LOWPAN_IPHC_ADDR_00:
-               /* unspec address ::
-                * Do nothing, address is already ::
-                */
-               break;
-       case LOWPAN_IPHC_ADDR_01:
-               /* TODO */
-       case LOWPAN_IPHC_ADDR_02:
-               /* TODO */
-       case LOWPAN_IPHC_ADDR_03:
-               /* TODO */
-               netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
-               return -EINVAL;
-       default:
-               pr_debug("Invalid sam value: 0x%x\n", sam);
-               return -EINVAL;
-       }
-
-       lowpan_raw_dump_inline(NULL,
-                       "Reconstructed context based ipv6 src addr is:\n",
-                       ipaddr->s6_addr, 16);
-
-       return 0;
-}
-
-/* Uncompress function for multicast destination address,
- * when M bit is set.
- */
-static int
-lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
-               struct in6_addr *ipaddr,
-               const u8 dam)
-{
-       bool fail;
-
-       switch (dam) {
-       case LOWPAN_IPHC_DAM_00:
-               /* 00:  128 bits.  The full address
-                * is carried in-line.
-                */
-               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
-               break;
-       case LOWPAN_IPHC_DAM_01:
-               /* 01:  48 bits.  The address takes
-                * the form ffXX::00XX:XXXX:XXXX.
-                */
-               ipaddr->s6_addr[0] = 0xFF;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
-               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
-               break;
-       case LOWPAN_IPHC_DAM_10:
-               /* 10:  32 bits.  The address takes
-                * the form ffXX::00XX:XXXX.
-                */
-               ipaddr->s6_addr[0] = 0xFF;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
-               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
-               break;
-       case LOWPAN_IPHC_DAM_11:
-               /* 11:  8 bits.  The address takes
-                * the form ff02::00XX.
-                */
-               ipaddr->s6_addr[0] = 0xFF;
-               ipaddr->s6_addr[1] = 0x02;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
-               break;
-       default:
-               pr_debug("DAM value has a wrong value: 0x%x\n", dam);
-               return -EINVAL;
-       }
-
-       if (fail) {
-               pr_debug("Failed to fetch skb data\n");
-               return -EIO;
-       }
-
-       lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is:\n",
-                       ipaddr->s6_addr, 16);
-
-       return 0;
-}
-
-static void
-lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
-{
-       struct udphdr *uh = udp_hdr(skb);
-
-       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("UDP header: both ports compression to 4 bits\n");
-               **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("UDP header: remove 8 bits of dest\n");
-               **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("UDP header: remove 8 bits of source\n");
-               **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("UDP header: can't compress\n");
-               **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;
-
-       /* skip the UDP header */
-       skb_pull(skb, sizeof(struct udphdr));
-}
-
-static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 1)))
-               return -EINVAL;
-
-       *val = skb->data[0];
-       skb_pull(skb, 1);
-
-       return 0;
-}
-
-static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 2)))
-               return -EINVAL;
-
-       *val = (skb->data[0] << 8) | skb->data[1];
-       skb_pull(skb, 2);
-
-       return 0;
-}
-
-static int
-lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
-{
-       u8 tmp;
-
-       if (!uh)
-               goto err;
-
-       if (lowpan_fetch_skb_u8(skb, &tmp))
-               goto err;
-
-       if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
-               pr_debug("UDP header uncompression\n");
-               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("ERROR: unknown UDP format\n");
-                       goto err;
-               }
-
-               pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
-                        uh->source, uh->dest);
-
-               /* copy checksum */
-               memcpy(&uh->check, &skb->data[0], 2);
-               skb_pull(skb, 2);
-
-               /*
-                * UDP lenght needs to be infered from the lower layers
-                * here, we obtain the hint from the remaining size of the
-                * frame
-                */
-               uh->len = htons(skb->len + sizeof(struct udphdr));
-               pr_debug("uncompressed UDP length: src = %d", uh->len);
-       } else {
-               pr_debug("ERROR: unsupported NH format\n");
-               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,
                           const void *_saddr, unsigned int len)
 {
-       u8 tmp, iphc0, iphc1, *hc06_ptr;
        struct ipv6hdr *hdr;
        const u8 *saddr = _saddr;
        const u8 *daddr = _daddr;
-       u8 head[100];
        struct ieee802154_addr sa, da;
 
        /* TODO:
@@ -485,181 +118,14 @@ static int lowpan_header_create(struct sk_buff *skb,
                return 0;
 
        hdr = ipv6_hdr(skb);
-       hc06_ptr = head + 2;
-
-       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
-                "\tnexthdr = 0x%02x\n\thop_lim = %d\n", hdr->version,
-                ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit);
-
-       lowpan_raw_dump_table(__func__, "raw skb network header dump",
-               skb_network_header(skb), sizeof(struct ipv6hdr));
 
        if (!saddr)
                saddr = dev->dev_addr;
 
-       lowpan_raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
-
-       /*
-        * As we copy some bit-length fields, in the IPHC encoding bytes,
-        * we sometimes use |=
-        * If the field is 0, and the current bit value in memory is 1,
-        * this does not work. We therefore reset the IPHC encoding here
-        */
-       iphc0 = LOWPAN_DISPATCH_IPHC;
-       iphc1 = 0;
-
-       /* TODO: context lookup */
+       raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
+       raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
 
-       lowpan_raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
-
-       /*
-        * Traffic class, flow label
-        * If flow label is 0, compress it. If traffic class is 0, compress it
-        * We have to process both in the same time as the offset of traffic
-        * class depends on the presence of version and flow label
-        */
-
-       /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
-       tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
-       tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
-
-       if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
-            (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
-               /* flow label can be compressed */
-               iphc0 |= LOWPAN_IPHC_FL_C;
-               if ((hdr->priority == 0) &&
-                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
-                       /* compress (elide) all */
-                       iphc0 |= LOWPAN_IPHC_TC_C;
-               } else {
-                       /* compress only the flow label */
-                       *hc06_ptr = tmp;
-                       hc06_ptr += 1;
-               }
-       } else {
-               /* Flow label cannot be compressed */
-               if ((hdr->priority == 0) &&
-                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
-                       /* compress only traffic class */
-                       iphc0 |= LOWPAN_IPHC_TC_C;
-                       *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
-                       memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
-                       hc06_ptr += 3;
-               } else {
-                       /* compress nothing */
-                       memcpy(hc06_ptr, hdr, 4);
-                       /* replace the top byte with new ECN | DSCP format */
-                       *hc06_ptr = tmp;
-                       hc06_ptr += 4;
-               }
-       }
-
-       /* NOTE: payload length is always compressed */
-
-       /* Next Header is compress if UDP */
-       if (hdr->nexthdr == UIP_PROTO_UDP)
-               iphc0 |= LOWPAN_IPHC_NH_C;
-
-       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
-               *hc06_ptr = hdr->nexthdr;
-               hc06_ptr += 1;
-       }
-
-       /*
-        * Hop limit
-        * if 1:   compress, encoding is 01
-        * if 64:  compress, encoding is 10
-        * if 255: compress, encoding is 11
-        * else do not compress
-        */
-       switch (hdr->hop_limit) {
-       case 1:
-               iphc0 |= LOWPAN_IPHC_TTL_1;
-               break;
-       case 64:
-               iphc0 |= LOWPAN_IPHC_TTL_64;
-               break;
-       case 255:
-               iphc0 |= LOWPAN_IPHC_TTL_255;
-               break;
-       default:
-               *hc06_ptr = hdr->hop_limit;
-               hc06_ptr += 1;
-               break;
-       }
-
-       /* source address compression */
-       if (is_addr_unspecified(&hdr->saddr)) {
-               pr_debug("source address is unspecified, setting SAC\n");
-               iphc1 |= LOWPAN_IPHC_SAC;
-       /* TODO: context lookup */
-       } else if (is_addr_link_local(&hdr->saddr)) {
-               pr_debug("source address is link-local\n");
-               iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
-                               LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr);
-       } else {
-               pr_debug("send the full source address\n");
-               memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
-               hc06_ptr += 16;
-       }
-
-       /* destination address compression */
-       if (is_addr_mcast(&hdr->daddr)) {
-               pr_debug("destination address is multicast: ");
-               iphc1 |= LOWPAN_IPHC_M;
-               if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
-                       pr_debug("compressed to 1 octet\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_11;
-                       /* use last byte */
-                       *hc06_ptr = hdr->daddr.s6_addr[15];
-                       hc06_ptr += 1;
-               } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
-                       pr_debug("compressed to 4 octets\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_10;
-                       /* second byte + the last three */
-                       *hc06_ptr = hdr->daddr.s6_addr[1];
-                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
-                       hc06_ptr += 4;
-               } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
-                       pr_debug("compressed to 6 octets\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_01;
-                       /* second byte + the last five */
-                       *hc06_ptr = hdr->daddr.s6_addr[1];
-                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
-                       hc06_ptr += 6;
-               } else {
-                       pr_debug("using full address\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_00;
-                       memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
-                       hc06_ptr += 16;
-               }
-       } else {
-               /* TODO: context lookup */
-               if (is_addr_link_local(&hdr->daddr)) {
-                       pr_debug("dest address is unicast and link-local\n");
-                       iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
-                               LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
-               } else {
-                       pr_debug("dest address is unicast: using full one\n");
-                       memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
-                       hc06_ptr += 16;
-               }
-       }
-
-       /* UDP header compression */
-       if (hdr->nexthdr == UIP_PROTO_UDP)
-               lowpan_compress_udp_header(&hc06_ptr, skb);
-
-       head[0] = iphc0;
-       head[1] = iphc1;
-
-       skb_pull(skb, sizeof(struct ipv6hdr));
-       skb_reset_transport_header(skb);
-       memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
-       skb_reset_network_header(skb);
-
-       lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
-                               skb->len);
+       lowpan_header_compress(skb, dev, type, daddr, saddr, len);
 
        /*
         * NOTE1: I'm still unsure about the fact that compression and WPAN
@@ -671,39 +137,38 @@ static int lowpan_header_create(struct sk_buff *skb,
         * from MAC subif of the 'dev' and 'real_dev' network devices, but
         * this isn't implemented in mainline yet, so currently we assign 0xff
         */
-       {
-               mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
-               mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+       mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+       mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
 
-               /* prepare wpan address data */
-               sa.addr_type = IEEE802154_ADDR_LONG;
-               sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       /* prepare wpan address data */
+       sa.addr_type = IEEE802154_ADDR_LONG;
+       sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-               memcpy(&(sa.hwaddr), saddr, 8);
-               /* intra-PAN communications */
-               da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       memcpy(&(sa.hwaddr), saddr, 8);
+       /* intra-PAN communications */
+       da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-               /*
-                * if the destination address is the broadcast address, use the
-                * corresponding short address
-                */
-               if (lowpan_is_addr_broadcast(daddr)) {
-                       da.addr_type = IEEE802154_ADDR_SHORT;
-                       da.short_addr = IEEE802154_ADDR_BROADCAST;
-               } else {
-                       da.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
-
-                       /* request acknowledgment */
-                       mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
-               }
+       /*
+        * if the destination address is the broadcast address, use the
+        * corresponding short address
+        */
+       if (lowpan_is_addr_broadcast(daddr)) {
+               da.addr_type = IEEE802154_ADDR_SHORT;
+               da.short_addr = IEEE802154_ADDR_BROADCAST;
+       } else {
+               da.addr_type = IEEE802154_ADDR_LONG;
+               memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
 
-               return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
-                               type, (void *)&da, (void *)&sa, skb->len);
+               /* request acknowledgment */
+               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
        }
+
+       return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
+                       type, (void *)&da, (void *)&sa, skb->len);
 }
 
-static int lowpan_give_skb_to_devices(struct sk_buff *skb)
+static int lowpan_give_skb_to_devices(struct sk_buff *skb,
+                                       struct net_device *dev)
 {
        struct lowpan_dev_record *entry;
        struct sk_buff *skb_cp;
@@ -726,31 +191,6 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb)
        return stat;
 }
 
-static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
-{
-       struct sk_buff *new;
-       int stat = NET_RX_SUCCESS;
-
-       new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
-                                                               GFP_ATOMIC);
-       kfree_skb(skb);
-
-       if (!new)
-               return -ENOMEM;
-
-       skb_push(new, sizeof(struct ipv6hdr));
-       skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
-
-       new->protocol = htons(ETH_P_IPV6);
-       new->pkt_type = PACKET_HOST;
-
-       stat = lowpan_give_skb_to_devices(new);
-
-       kfree_skb(new);
-
-       return stat;
-}
-
 static void lowpan_fragment_timer_expired(unsigned long entry_addr)
 {
        struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
@@ -814,16 +254,12 @@ frame_err:
        return NULL;
 }
 
-static int
-lowpan_process_data(struct sk_buff *skb)
+static int process_data(struct sk_buff *skb)
 {
-       struct ipv6hdr hdr = {};
-       u8 tmp, iphc0, iphc1, num_context = 0;
+       u8 iphc0, iphc1;
        const struct ieee802154_addr *_saddr, *_daddr;
-       int err;
 
-       lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
-                               skb->len);
+       raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
        /* at least two bytes will be used for the encoding */
        if (skb->len < 2)
                goto drop;
@@ -925,162 +361,11 @@ lowpan_process_data(struct sk_buff *skb)
        _saddr = &mac_cb(skb)->sa;
        _daddr = &mac_cb(skb)->da;
 
-       pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1);
-
-       /* another if the CID flag is set */
-       if (iphc1 & LOWPAN_IPHC_CID) {
-               pr_debug("CID flag is set, increase header with one\n");
-               if (lowpan_fetch_skb_u8(skb, &num_context))
-                       goto drop;
-       }
-
-       hdr.version = 6;
-
-       /* Traffic Class and Flow Label */
-       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
-       /*
-        * Traffic Class and FLow Label carried in-line
-        * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
-        */
-       case 0: /* 00b */
-               if (lowpan_fetch_skb_u8(skb, &tmp))
-                       goto drop;
-
-               memcpy(&hdr.flow_lbl, &skb->data[0], 3);
-               skb_pull(skb, 3);
-               hdr.priority = ((tmp >> 2) & 0x0f);
-               hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
-                                       (hdr.flow_lbl[0] & 0x0f);
-               break;
-       /*
-        * Traffic class carried in-line
-        * ECN + DSCP (1 byte), Flow Label is elided
-        */
-       case 2: /* 10b */
-               if (lowpan_fetch_skb_u8(skb, &tmp))
-                       goto drop;
-
-               hdr.priority = ((tmp >> 2) & 0x0f);
-               hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
-               break;
-       /*
-        * Flow Label carried in-line
-        * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
-        */
-       case 1: /* 01b */
-               if (lowpan_fetch_skb_u8(skb, &tmp))
-                       goto drop;
-
-               hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
-               memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
-               skb_pull(skb, 2);
-               break;
-       /* Traffic Class and Flow Label are elided */
-       case 3: /* 11b */
-               break;
-       default:
-               break;
-       }
-
-       /* Next Header */
-       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
-               /* Next header is carried inline */
-               if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
-                       goto drop;
-
-               pr_debug("NH flag is set, next header carried inline: %02x\n",
-                        hdr.nexthdr);
-       }
-
-       /* Hop Limit */
-       if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
-               hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
-       else {
-               if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
-                       goto drop;
-       }
-
-       /* Extract SAM to the tmp variable */
-       tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
-
-       if (iphc1 & LOWPAN_IPHC_SAC) {
-               /* Source address context based uncompression */
-               pr_debug("SAC bit is set. Handle context based source address.\n");
-               err = lowpan_uncompress_context_based_src_addr(
-                               skb, &hdr.saddr, tmp);
-       } else {
-               /* Source address uncompression */
-               pr_debug("source address stateless compression\n");
-               err = lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr);
-       }
-
-       /* Check on error of previous branch */
-       if (err)
-               goto drop;
-
-       /* Extract DAM to the tmp variable */
-       tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
-
-       /* check for Multicast Compression */
-       if (iphc1 & LOWPAN_IPHC_M) {
-               if (iphc1 & LOWPAN_IPHC_DAC) {
-                       pr_debug("dest: context-based mcast compression\n");
-                       /* TODO: implement this */
-               } else {
-                       err = lowpan_uncompress_multicast_daddr(
-                                       skb, &hdr.daddr, tmp);
-                       if (err)
-                               goto drop;
-               }
-       } else {
-               pr_debug("dest: stateless compression\n");
-               err = lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr);
-               if (err)
-                       goto drop;
-       }
-
-       /* UDP data uncompression */
-       if (iphc0 & LOWPAN_IPHC_NH_C) {
-               struct udphdr uh;
-               struct sk_buff *new;
-               if (lowpan_uncompress_udp_header(skb, &uh))
-                       goto drop;
-
-               /*
-                * replace the compressed UDP head by the uncompressed UDP
-                * header
-                */
-               new = skb_copy_expand(skb, sizeof(struct udphdr),
-                                     skb_tailroom(skb), GFP_ATOMIC);
-               kfree_skb(skb);
-
-               if (!new)
-                       return -ENOMEM;
-
-               skb = new;
-
-               skb_push(skb, sizeof(struct udphdr));
-               skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
-
-               lowpan_raw_dump_table(__func__, "raw UDP header dump",
-                                     (u8 *)&uh, sizeof(uh));
-
-               hdr.nexthdr = UIP_PROTO_UDP;
-       }
-
-       /* Not fragmented package */
-       hdr.payload_len = htons(skb->len);
-
-       pr_debug("skb headroom size = %d, data length = %d\n",
-                skb_headroom(skb), skb->len);
-
-       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
-                "nexthdr = 0x%02x\n\thop_lim = %d\n", hdr.version,
-                ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit);
-
-       lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
-                                                       sizeof(hdr));
-       return lowpan_skb_deliver(skb, &hdr);
+       return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr,
+                               _saddr->addr_type, IEEE802154_ADDR_LEN,
+                               (u8 *)_daddr->hwaddr, _daddr->addr_type,
+                               IEEE802154_ADDR_LEN, iphc0, iphc1,
+                               lowpan_give_skb_to_devices);
 
 unlock_and_drop:
        spin_unlock_bh(&flist_lock);
@@ -1112,7 +397,7 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
        hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
                        LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
 
-       lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
+       raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
 
        frag = netdev_alloc_skb(skb->dev,
                                hlen + mlen + plen + IEEE802154_MFR_SIZE);
@@ -1132,8 +417,7 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
        skb_copy_to_linear_data_offset(frag, mlen + hlen,
                                       skb_network_header(skb) + offset, plen);
 
-       lowpan_raw_dump_table(__func__, " raw fragment dump", frag->data,
-                                                               frag->len);
+       raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len);
 
        return dev_queue_xmit(frag);
 }
@@ -1316,7 +600,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                /* Pull off the 1-byte of 6lowpan header. */
                skb_pull(local_skb, 1);
 
-               lowpan_give_skb_to_devices(local_skb);
+               lowpan_give_skb_to_devices(local_skb, NULL);
 
                kfree_skb(local_skb);
                kfree_skb(skb);
@@ -1328,7 +612,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                        local_skb = skb_clone(skb, GFP_ATOMIC);
                        if (!local_skb)
                                goto drop;
-                       lowpan_process_data(local_skb);
+                       process_data(local_skb);
 
                        kfree_skb(skb);
                        break;
index 2869c05..2b835db 100644 (file)
 #define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline,
                                        dest = 16 bit inline */
 #define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
+#define LOWPAN_NHC_UDP_CS_C    0x04 /* checksum elided */
+
+#ifdef DEBUG
+/* print data in line */
+static inline void raw_dump_inline(const char *caller, char *msg,
+                                  unsigned char *buf, int len)
+{
+       if (msg)
+               pr_debug("%s():%s: ", caller, msg);
+
+       print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);
+}
+
+/* print data in a table format:
+ *
+ * addr: xx xx xx xx xx xx
+ * addr: xx xx xx xx xx xx
+ * ...
+ */
+static inline void raw_dump_table(const char *caller, char *msg,
+                                 unsigned char *buf, int len)
+{
+       if (msg)
+               pr_debug("%s():%s:\n", caller, msg);
+
+       print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
+}
+#else
+static inline void raw_dump_table(const char *caller, char *msg,
+                                 unsigned char *buf, int len) { }
+static inline void raw_dump_inline(const char *caller, char *msg,
+                                  unsigned char *buf, int len) { }
+#endif
+
+static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
+{
+       if (unlikely(!pskb_may_pull(skb, 1)))
+               return -EINVAL;
+
+       *val = skb->data[0];
+       skb_pull(skb, 1);
+
+       return 0;
+}
+
+static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
+{
+       if (unlikely(!pskb_may_pull(skb, 2)))
+               return -EINVAL;
+
+       *val = (skb->data[0] << 8) | skb->data[1];
+       skb_pull(skb, 2);
+
+       return 0;
+}
 
 static inline bool lowpan_fetch_skb(struct sk_buff *skb,
                void *data, const unsigned int len)
@@ -244,4 +299,21 @@ static inline bool lowpan_fetch_skb(struct sk_buff *skb,
        return false;
 }
 
+static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
+                                      const size_t len)
+{
+       memcpy(*hc_ptr, data, len);
+       *hc_ptr += len;
+}
+
+typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
+
+int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
+               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
+               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
+               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
+int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type, const void *_daddr,
+                       const void *_saddr, unsigned int len);
+
 #endif /* __6LOWPAN_H__ */
diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c
new file mode 100644 (file)
index 0000000..11840f9
--- /dev/null
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2011, Siemens AG
+ * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+/*
+ * Based on patches from Jon Smirl <jonsmirl@gmail.com>
+ * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Jon's code is based on 6lowpan implementation for Contiki which is:
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/bitops.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <net/ipv6.h>
+#include <net/af_ieee802154.h>
+
+#include "6lowpan.h"
+
+/*
+ * Uncompress address function for source and
+ * destination address(non-multicast).
+ *
+ * address_mode is sam value or dam value.
+ */
+static int uncompress_addr(struct sk_buff *skb,
+                               struct in6_addr *ipaddr, const u8 address_mode,
+                               const u8 *lladdr, const u8 addr_type,
+                               const u8 addr_len)
+{
+       bool fail;
+
+       switch (address_mode) {
+       case LOWPAN_IPHC_ADDR_00:
+               /* for global link addresses */
+               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
+               break;
+       case LOWPAN_IPHC_ADDR_01:
+               /* fe:80::XXXX:XXXX:XXXX:XXXX */
+               ipaddr->s6_addr[0] = 0xFE;
+               ipaddr->s6_addr[1] = 0x80;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
+               break;
+       case LOWPAN_IPHC_ADDR_02:
+               /* fe:80::ff:fe00:XXXX */
+               ipaddr->s6_addr[0] = 0xFE;
+               ipaddr->s6_addr[1] = 0x80;
+               ipaddr->s6_addr[11] = 0xFF;
+               ipaddr->s6_addr[12] = 0xFE;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
+               break;
+       case LOWPAN_IPHC_ADDR_03:
+               fail = false;
+               switch (addr_type) {
+               case IEEE802154_ADDR_LONG:
+                       /* fe:80::XXXX:XXXX:XXXX:XXXX
+                        *        \_________________/
+                        *              hwaddr
+                        */
+                       ipaddr->s6_addr[0] = 0xFE;
+                       ipaddr->s6_addr[1] = 0x80;
+                       memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
+                       /* second bit-flip (Universe/Local)
+                        * is done according RFC2464
+                        */
+                       ipaddr->s6_addr[8] ^= 0x02;
+                       break;
+               case IEEE802154_ADDR_SHORT:
+                       /* fe:80::ff:fe00:XXXX
+                        *                \__/
+                        *             short_addr
+                        *
+                        * Universe/Local bit is zero.
+                        */
+                       ipaddr->s6_addr[0] = 0xFE;
+                       ipaddr->s6_addr[1] = 0x80;
+                       ipaddr->s6_addr[11] = 0xFF;
+                       ipaddr->s6_addr[12] = 0xFE;
+                       ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
+                       break;
+               default:
+                       pr_debug("Invalid addr_type set\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               pr_debug("Invalid address mode value: 0x%x\n", address_mode);
+               return -EINVAL;
+       }
+
+       if (fail) {
+               pr_debug("Failed to fetch skb data\n");
+               return -EIO;
+       }
+
+       raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
+                       ipaddr->s6_addr, 16);
+
+       return 0;
+}
+
+/*
+ * Uncompress address function for source context
+ * based address(non-multicast).
+ */
+static int uncompress_context_based_src_addr(struct sk_buff *skb,
+                                               struct in6_addr *ipaddr,
+                                               const u8 sam)
+{
+       switch (sam) {
+       case LOWPAN_IPHC_ADDR_00:
+               /* unspec address ::
+                * Do nothing, address is already ::
+                */
+               break;
+       case LOWPAN_IPHC_ADDR_01:
+               /* TODO */
+       case LOWPAN_IPHC_ADDR_02:
+               /* TODO */
+       case LOWPAN_IPHC_ADDR_03:
+               /* TODO */
+               netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
+               return -EINVAL;
+       default:
+               pr_debug("Invalid sam value: 0x%x\n", sam);
+               return -EINVAL;
+       }
+
+       raw_dump_inline(NULL,
+                       "Reconstructed context based ipv6 src addr is",
+                       ipaddr->s6_addr, 16);
+
+       return 0;
+}
+
+static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
+               struct net_device *dev, skb_delivery_cb deliver_skb)
+{
+       struct sk_buff *new;
+       int stat;
+
+       new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
+                                                               GFP_ATOMIC);
+       kfree_skb(skb);
+
+       if (!new)
+               return -ENOMEM;
+
+       skb_push(new, sizeof(struct ipv6hdr));
+       skb_reset_network_header(new);
+       skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
+
+       new->protocol = htons(ETH_P_IPV6);
+       new->pkt_type = PACKET_HOST;
+       new->dev = dev;
+
+       raw_dump_table(__func__, "raw skb data dump before receiving",
+                       new->data, new->len);
+
+       stat = deliver_skb(new, dev);
+
+       kfree_skb(new);
+
+       return stat;
+}
+
+/* Uncompress function for multicast destination address,
+ * when M bit is set.
+ */
+static int
+lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
+               struct in6_addr *ipaddr,
+               const u8 dam)
+{
+       bool fail;
+
+       switch (dam) {
+       case LOWPAN_IPHC_DAM_00:
+               /* 00:  128 bits.  The full address
+                * is carried in-line.
+                */
+               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
+               break;
+       case LOWPAN_IPHC_DAM_01:
+               /* 01:  48 bits.  The address takes
+                * the form ffXX::00XX:XXXX:XXXX.
+                */
+               ipaddr->s6_addr[0] = 0xFF;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
+               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
+               break;
+       case LOWPAN_IPHC_DAM_10:
+               /* 10:  32 bits.  The address takes
+                * the form ffXX::00XX:XXXX.
+                */
+               ipaddr->s6_addr[0] = 0xFF;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
+               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
+               break;
+       case LOWPAN_IPHC_DAM_11:
+               /* 11:  8 bits.  The address takes
+                * the form ff02::00XX.
+                */
+               ipaddr->s6_addr[0] = 0xFF;
+               ipaddr->s6_addr[1] = 0x02;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
+               break;
+       default:
+               pr_debug("DAM value has a wrong value: 0x%x\n", dam);
+               return -EINVAL;
+       }
+
+       if (fail) {
+               pr_debug("Failed to fetch skb data\n");
+               return -EIO;
+       }
+
+       raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
+                               ipaddr->s6_addr, 16);
+
+       return 0;
+}
+
+static int
+uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
+{
+       bool fail;
+       u8 tmp = 0, val = 0;
+
+       if (!uh)
+               goto err;
+
+       fail = lowpan_fetch_skb(skb, &tmp, 1);
+
+       if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+               pr_debug("UDP header uncompression\n");
+               switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
+               case LOWPAN_NHC_UDP_CS_P_00:
+                       fail |= lowpan_fetch_skb(skb, &uh->source, 2);
+                       fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_01:
+                       fail |= lowpan_fetch_skb(skb, &uh->source, 2);
+                       fail |= lowpan_fetch_skb(skb, &val, 1);
+                       uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_10:
+                       fail |= lowpan_fetch_skb(skb, &val, 1);
+                       uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
+                       fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_11:
+                       fail |= lowpan_fetch_skb(skb, &val, 1);
+                       uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
+                                          (val >> 4));
+                       uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
+                                        (val & 0x0f));
+                       break;
+               default:
+                       pr_debug("ERROR: unknown UDP format\n");
+                       goto err;
+                       break;
+               }
+
+               pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
+                        ntohs(uh->source), ntohs(uh->dest));
+
+               /* checksum */
+               if (tmp & LOWPAN_NHC_UDP_CS_C) {
+                       pr_debug_ratelimited("checksum elided currently not supported\n");
+                       goto err;
+               } else {
+                       fail |= lowpan_fetch_skb(skb, &uh->check, 2);
+               }
+
+               /*
+                * UDP lenght needs to be infered from the lower layers
+                * here, we obtain the hint from the remaining size of the
+                * frame
+                */
+               uh->len = htons(skb->len + sizeof(struct udphdr));
+               pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
+       } else {
+               pr_debug("ERROR: unsupported NH format\n");
+               goto err;
+       }
+
+       if (fail)
+               goto err;
+
+       return 0;
+err:
+       return -EINVAL;
+}
+
+/* TTL uncompression values */
+static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
+
+int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
+               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
+               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
+               u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb)
+{
+       struct ipv6hdr hdr = {};
+       u8 tmp, num_context = 0;
+       int err;
+
+       raw_dump_table(__func__, "raw skb data dump uncompressed",
+                               skb->data, skb->len);
+
+       /* another if the CID flag is set */
+       if (iphc1 & LOWPAN_IPHC_CID) {
+               pr_debug("CID flag is set, increase header with one\n");
+               if (lowpan_fetch_skb_u8(skb, &num_context))
+                       goto drop;
+       }
+
+       hdr.version = 6;
+
+       /* Traffic Class and Flow Label */
+       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+       /*
+        * Traffic Class and FLow Label carried in-line
+        * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
+        */
+       case 0: /* 00b */
+               if (lowpan_fetch_skb_u8(skb, &tmp))
+                       goto drop;
+
+               memcpy(&hdr.flow_lbl, &skb->data[0], 3);
+               skb_pull(skb, 3);
+               hdr.priority = ((tmp >> 2) & 0x0f);
+               hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
+                                       (hdr.flow_lbl[0] & 0x0f);
+               break;
+       /*
+        * Traffic class carried in-line
+        * ECN + DSCP (1 byte), Flow Label is elided
+        */
+       case 2: /* 10b */
+               if (lowpan_fetch_skb_u8(skb, &tmp))
+                       goto drop;
+
+               hdr.priority = ((tmp >> 2) & 0x0f);
+               hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
+               break;
+       /*
+        * Flow Label carried in-line
+        * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
+        */
+       case 1: /* 01b */
+               if (lowpan_fetch_skb_u8(skb, &tmp))
+                       goto drop;
+
+               hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
+               memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
+               skb_pull(skb, 2);
+               break;
+       /* Traffic Class and Flow Label are elided */
+       case 3: /* 11b */
+               break;
+       default:
+               break;
+       }
+
+       /* Next Header */
+       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+               /* Next header is carried inline */
+               if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
+                       goto drop;
+
+               pr_debug("NH flag is set, next header carried inline: %02x\n",
+                        hdr.nexthdr);
+       }
+
+       /* Hop Limit */
+       if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
+               hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
+       else {
+               if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
+                       goto drop;
+       }
+
+       /* Extract SAM to the tmp variable */
+       tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
+
+       if (iphc1 & LOWPAN_IPHC_SAC) {
+               /* Source address context based uncompression */
+               pr_debug("SAC bit is set. Handle context based source address.\n");
+               err = uncompress_context_based_src_addr(
+                               skb, &hdr.saddr, tmp);
+       } else {
+               /* Source address uncompression */
+               pr_debug("source address stateless compression\n");
+               err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
+                                       saddr_type, saddr_len);
+       }
+
+       /* Check on error of previous branch */
+       if (err)
+               goto drop;
+
+       /* Extract DAM to the tmp variable */
+       tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
+
+       /* check for Multicast Compression */
+       if (iphc1 & LOWPAN_IPHC_M) {
+               if (iphc1 & LOWPAN_IPHC_DAC) {
+                       pr_debug("dest: context-based mcast compression\n");
+                       /* TODO: implement this */
+               } else {
+                       err = lowpan_uncompress_multicast_daddr(
+                                               skb, &hdr.daddr, tmp);
+                       if (err)
+                               goto drop;
+               }
+       } else {
+               err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
+                                       daddr_type, daddr_len);
+               pr_debug("dest: stateless compression mode %d dest %pI6c\n",
+                       tmp, &hdr.daddr);
+               if (err)
+                       goto drop;
+       }
+
+       /* UDP data uncompression */
+       if (iphc0 & LOWPAN_IPHC_NH_C) {
+               struct udphdr uh;
+               struct sk_buff *new;
+               if (uncompress_udp_header(skb, &uh))
+                       goto drop;
+
+               /*
+                * replace the compressed UDP head by the uncompressed UDP
+                * header
+                */
+               new = skb_copy_expand(skb, sizeof(struct udphdr),
+                                     skb_tailroom(skb), GFP_ATOMIC);
+               kfree_skb(skb);
+
+               if (!new)
+                       return -ENOMEM;
+
+               skb = new;
+
+               skb_push(skb, sizeof(struct udphdr));
+               skb_reset_transport_header(skb);
+               skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
+
+               raw_dump_table(__func__, "raw UDP header dump",
+                                     (u8 *)&uh, sizeof(uh));
+
+               hdr.nexthdr = UIP_PROTO_UDP;
+       }
+
+       hdr.payload_len = htons(skb->len);
+
+       pr_debug("skb headroom size = %d, data length = %d\n",
+                skb_headroom(skb), skb->len);
+
+       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
+                "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
+               hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
+               hdr.hop_limit, &hdr.daddr);
+
+       raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
+                                                       sizeof(hdr));
+
+       return skb_deliver(skb, &hdr, dev, deliver_skb);
+
+drop:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(lowpan_process_data);
+
+static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
+                               const struct in6_addr *ipaddr,
+                               const unsigned char *lladdr)
+{
+       u8 val = 0;
+
+       if (is_addr_mac_addr_based(ipaddr, lladdr)) {
+               val = 3; /* 0-bits */
+               pr_debug("address compression 0 bits\n");
+       } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+               /* compress IID to 16 bits xxxx::XXXX */
+               memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
+               *hc06_ptr += 2;
+               val = 2; /* 16-bits */
+               raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
+                       *hc06_ptr - 2, 2);
+       } else {
+               /* do not compress IID => xxxx::IID */
+               memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
+               *hc06_ptr += 8;
+               val = 1; /* 64-bits */
+               raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
+                       *hc06_ptr - 8, 8);
+       }
+
+       return rol8(val, shift);
+}
+
+static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+       u8 tmp;
+
+       if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
+            LOWPAN_NHC_UDP_4BIT_PORT) &&
+           ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
+            LOWPAN_NHC_UDP_4BIT_PORT)) {
+               pr_debug("UDP header: both ports compression to 4 bits\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_11;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source and destination port */
+               tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
+                     ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+       } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("UDP header: remove 8 bits of dest\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_01;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source port */
+               lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
+               /* destination port */
+               tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+       } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("UDP header: remove 8 bits of source\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_10;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source port */
+               tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* destination port */
+               lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
+       } else {
+               pr_debug("UDP header: can't compress\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_00;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source port */
+               lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
+               /* destination port */
+               lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
+       }
+
+       /* checksum is always inline */
+       lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check));
+
+       /* skip the UDP header */
+       skb_pull(skb, sizeof(struct udphdr));
+}
+
+int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type, const void *_daddr,
+                       const void *_saddr, unsigned int len)
+{
+       u8 tmp, iphc0, iphc1, *hc06_ptr;
+       struct ipv6hdr *hdr;
+       u8 head[100] = {};
+
+       if (type != ETH_P_IPV6)
+               return -EINVAL;
+
+       hdr = ipv6_hdr(skb);
+       hc06_ptr = head + 2;
+
+       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
+                "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
+               hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
+               hdr->hop_limit, &hdr->daddr);
+
+       raw_dump_table(__func__, "raw skb network header dump",
+               skb_network_header(skb), sizeof(struct ipv6hdr));
+
+       /*
+        * As we copy some bit-length fields, in the IPHC encoding bytes,
+        * we sometimes use |=
+        * If the field is 0, and the current bit value in memory is 1,
+        * this does not work. We therefore reset the IPHC encoding here
+        */
+       iphc0 = LOWPAN_DISPATCH_IPHC;
+       iphc1 = 0;
+
+       /* TODO: context lookup */
+
+       raw_dump_inline(__func__, "saddr",
+                       (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
+       raw_dump_inline(__func__, "daddr",
+                       (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
+
+       raw_dump_table(__func__,
+                       "sending raw skb network uncompressed packet",
+                       skb->data, skb->len);
+
+       /*
+        * Traffic class, flow label
+        * If flow label is 0, compress it. If traffic class is 0, compress it
+        * We have to process both in the same time as the offset of traffic
+        * class depends on the presence of version and flow label
+        */
+
+       /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
+       tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
+       tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
+
+       if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
+            (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
+               /* flow label can be compressed */
+               iphc0 |= LOWPAN_IPHC_FL_C;
+               if ((hdr->priority == 0) &&
+                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+                       /* compress (elide) all */
+                       iphc0 |= LOWPAN_IPHC_TC_C;
+               } else {
+                       /* compress only the flow label */
+                       *hc06_ptr = tmp;
+                       hc06_ptr += 1;
+               }
+       } else {
+               /* Flow label cannot be compressed */
+               if ((hdr->priority == 0) &&
+                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+                       /* compress only traffic class */
+                       iphc0 |= LOWPAN_IPHC_TC_C;
+                       *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
+                       memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
+                       hc06_ptr += 3;
+               } else {
+                       /* compress nothing */
+                       memcpy(hc06_ptr, &hdr, 4);
+                       /* replace the top byte with new ECN | DSCP format */
+                       *hc06_ptr = tmp;
+                       hc06_ptr += 4;
+               }
+       }
+
+       /* NOTE: payload length is always compressed */
+
+       /* Next Header is compress if UDP */
+       if (hdr->nexthdr == UIP_PROTO_UDP)
+               iphc0 |= LOWPAN_IPHC_NH_C;
+
+       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+               *hc06_ptr = hdr->nexthdr;
+               hc06_ptr += 1;
+       }
+
+       /*
+        * Hop limit
+        * if 1:   compress, encoding is 01
+        * if 64:  compress, encoding is 10
+        * if 255: compress, encoding is 11
+        * else do not compress
+        */
+       switch (hdr->hop_limit) {
+       case 1:
+               iphc0 |= LOWPAN_IPHC_TTL_1;
+               break;
+       case 64:
+               iphc0 |= LOWPAN_IPHC_TTL_64;
+               break;
+       case 255:
+               iphc0 |= LOWPAN_IPHC_TTL_255;
+               break;
+       default:
+               *hc06_ptr = hdr->hop_limit;
+               hc06_ptr += 1;
+               break;
+       }
+
+       /* source address compression */
+       if (is_addr_unspecified(&hdr->saddr)) {
+               pr_debug("source address is unspecified, setting SAC\n");
+               iphc1 |= LOWPAN_IPHC_SAC;
+       /* TODO: context lookup */
+       } else if (is_addr_link_local(&hdr->saddr)) {
+               iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+                               LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr);
+               pr_debug("source address unicast link-local %pI6c "
+                       "iphc1 0x%02x\n", &hdr->saddr, iphc1);
+       } else {
+               pr_debug("send the full source address\n");
+               memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
+               hc06_ptr += 16;
+       }
+
+       /* destination address compression */
+       if (is_addr_mcast(&hdr->daddr)) {
+               pr_debug("destination address is multicast: ");
+               iphc1 |= LOWPAN_IPHC_M;
+               if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
+                       pr_debug("compressed to 1 octet\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_11;
+                       /* use last byte */
+                       *hc06_ptr = hdr->daddr.s6_addr[15];
+                       hc06_ptr += 1;
+               } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
+                       pr_debug("compressed to 4 octets\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_10;
+                       /* second byte + the last three */
+                       *hc06_ptr = hdr->daddr.s6_addr[1];
+                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
+                       hc06_ptr += 4;
+               } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
+                       pr_debug("compressed to 6 octets\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_01;
+                       /* second byte + the last five */
+                       *hc06_ptr = hdr->daddr.s6_addr[1];
+                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
+                       hc06_ptr += 6;
+               } else {
+                       pr_debug("using full address\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_00;
+                       memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
+                       hc06_ptr += 16;
+               }
+       } else {
+               /* TODO: context lookup */
+               if (is_addr_link_local(&hdr->daddr)) {
+                       iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+                               LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
+                       pr_debug("dest address unicast link-local %pI6c "
+                               "iphc1 0x%02x\n", &hdr->daddr, iphc1);
+               } else {
+                       pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
+                       memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
+                       hc06_ptr += 16;
+               }
+       }
+
+       /* UDP header compression */
+       if (hdr->nexthdr == UIP_PROTO_UDP)
+               compress_udp_header(&hc06_ptr, skb);
+
+       head[0] = iphc0;
+       head[1] = iphc1;
+
+       skb_pull(skb, sizeof(struct ipv6hdr));
+       skb_reset_transport_header(skb);
+       memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
+       skb_reset_network_header(skb);
+
+       pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len);
+
+       raw_dump_table(__func__, "raw skb data dump compressed",
+                               skb->data, skb->len);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lowpan_header_compress);
index b2e06df..9c9879d 100644 (file)
@@ -13,5 +13,12 @@ config IEEE802154
 config IEEE802154_6LOWPAN
        tristate "6lowpan support over IEEE 802.15.4"
        depends on IEEE802154 && IPV6
+       select 6LOWPAN_IPHC
        ---help---
        IPv6 compression over IEEE 802.15.4.
+
+config 6LOWPAN_IPHC
+       tristate
+       ---help---
+         6lowpan compression code which is shared between IEEE 802.15.4 and Bluetooth
+         stacks.
index d7716d6..e8f0588 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
 obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
+obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
 
 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
index 6268a47..ecd2c3f 100644 (file)
@@ -1545,6 +1545,7 @@ static const struct net_protocol tcp_protocol = {
        .err_handler    =       tcp_v4_err,
        .no_policy      =       1,
        .netns_ok       =       1,
+       .icmp_strict_tag_validation = 1,
 };
 
 static const struct net_protocol udp_protocol = {
index 9809f7b..646023b 100644 (file)
@@ -464,7 +464,7 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
        }
 
        if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
-               net_srandom(ifa->ifa_local);
+               prandom_seed((__force u32) ifa->ifa_local);
                ifap = last_primary;
        }
 
index 746a7b1..29512e3 100644 (file)
@@ -26,7 +26,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
 {
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        netdev_features_t enc_features;
-       int ghl = GRE_HEADER_SECTION;
+       int ghl;
        struct gre_base_hdr *greh;
        u16 mac_offset = skb->mac_header;
        int mac_len = skb->mac_len;
@@ -49,15 +49,11 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
 
        greh = (struct gre_base_hdr *)skb_transport_header(skb);
 
-       if (greh->flags & GRE_KEY)
-               ghl += GRE_HEADER_SECTION;
-       if (greh->flags & GRE_SEQ)
-               ghl += GRE_HEADER_SECTION;
-       if (greh->flags & GRE_CSUM) {
-               ghl += GRE_HEADER_SECTION;
-               csum = true;
-       } else
-               csum = false;
+       ghl = skb_inner_network_header(skb) - skb_transport_header(skb);
+       if (unlikely(ghl < sizeof(*greh)))
+               goto out;
+
+       csum = !!(greh->flags & GRE_CSUM);
 
        if (unlikely(!pskb_may_pull(skb, ghl)))
                goto out;
@@ -250,7 +246,7 @@ out:
        return pp;
 }
 
-int gre_gro_complete(struct sk_buff *skb, int nhoff)
+static int gre_gro_complete(struct sk_buff *skb, int nhoff)
 {
        struct gre_base_hdr *greh = (struct gre_base_hdr *)(skb->data + nhoff);
        struct packet_offload *ptype;
index fb3c563..0134663 100644 (file)
@@ -668,6 +668,16 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
        rcu_read_unlock();
 }
 
+static bool icmp_tag_validation(int proto)
+{
+       bool ok;
+
+       rcu_read_lock();
+       ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation;
+       rcu_read_unlock();
+       return ok;
+}
+
 /*
  *     Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, ICMP_QUENCH, and
  *     ICMP_PARAMETERPROB.
@@ -705,12 +715,22 @@ static void icmp_unreach(struct sk_buff *skb)
                case ICMP_PORT_UNREACH:
                        break;
                case ICMP_FRAG_NEEDED:
-                       if (net->ipv4.sysctl_ip_no_pmtu_disc == 2) {
-                               goto out;
-                       } else if (net->ipv4.sysctl_ip_no_pmtu_disc) {
+                       /* for documentation of the ip_no_pmtu_disc
+                        * values please see
+                        * Documentation/networking/ip-sysctl.txt
+                        */
+                       switch (net->ipv4.sysctl_ip_no_pmtu_disc) {
+                       default:
                                LIMIT_NETDEBUG(KERN_INFO pr_fmt("%pI4: fragmentation needed and DF set\n"),
                                               &iph->daddr);
-                       } else {
+                               break;
+                       case 2:
+                               goto out;
+                       case 3:
+                               if (!icmp_tag_validation(iph->protocol))
+                                       goto out;
+                               /* fall through */
+                       case 0:
                                info = ntohs(icmph->un.frag.mtu);
                                if (!info)
                                        goto out;
index 84c4329..97e4d16 100644 (file)
@@ -211,7 +211,7 @@ static void igmp_stop_timer(struct ip_mc_list *im)
 /* It must be called with locked im->lock */
 static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
 {
-       int tv = net_random() % max_delay;
+       int tv = prandom_u32() % max_delay;
 
        im->tm_running = 1;
        if (!mod_timer(&im->timer, jiffies+tv+2))
@@ -220,7 +220,7 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
 
 static void igmp_gq_start_timer(struct in_device *in_dev)
 {
-       int tv = net_random() % in_dev->mr_maxdelay;
+       int tv = prandom_u32() % in_dev->mr_maxdelay;
 
        in_dev->mr_gq_running = 1;
        if (!mod_timer(&in_dev->mr_gq_timer, jiffies+tv+2))
@@ -229,7 +229,7 @@ static void igmp_gq_start_timer(struct in_device *in_dev)
 
 static void igmp_ifc_start_timer(struct in_device *in_dev, int delay)
 {
-       int tv = net_random() % delay;
+       int tv = prandom_u32() % delay;
 
        if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2))
                in_dev_hold(in_dev);
@@ -2762,6 +2762,7 @@ static struct pernet_operations igmp_net_ops = {
        .init = igmp_net_init,
        .exit = igmp_net_exit,
 };
+#endif
 
 static int igmp_netdev_event(struct notifier_block *this,
                             unsigned long event, void *ptr)
@@ -2785,8 +2786,9 @@ static struct notifier_block igmp_notifier = {
        .notifier_call = igmp_netdev_event,
 };
 
-int __init igmp_mc_proc_init(void)
+int __init igmp_mc_init(void)
 {
+#if defined(CONFIG_PROC_FS)
        int err;
 
        err = register_pernet_subsys(&igmp_net_ops);
@@ -2800,5 +2802,7 @@ int __init igmp_mc_proc_init(void)
 reg_notif_fail:
        unregister_pernet_subsys(&igmp_net_ops);
        return err;
-}
+#else
+       return register_netdevice_notifier(&igmp_notifier);
 #endif
+}
index fc0e649..0d1e2cb 100644 (file)
@@ -109,7 +109,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
 again:
                inet_get_local_port_range(net, &low, &high);
                remaining = (high - low) + 1;
-               smallest_rover = rover = net_random() % remaining + low;
+               smallest_rover = rover = prandom_u32() % remaining + low;
 
                smallest_size = -1;
                do {
index a0f52da..e34dccb 100644 (file)
@@ -930,12 +930,15 @@ skip_listen_ht:
                spin_lock_bh(lock);
                sk_nulls_for_each(sk, node, &head->chain) {
                        int res;
+                       int state;
 
                        if (!net_eq(sock_net(sk), net))
                                continue;
                        if (num < s_num)
                                goto next_normal;
-                       if (!(r->idiag_states & (1 << sk->sk_state)))
+                       state = (sk->sk_state == TCP_TIME_WAIT) ?
+                               inet_twsk(sk)->tw_substate : sk->sk_state;
+                       if (!(r->idiag_states & (1 << state)))
                                goto next_normal;
                        if (r->sdiag_family != AF_UNSPEC &&
                            sk->sk_family != r->sdiag_family)
index 694de3b..e9f1217 100644 (file)
@@ -54,6 +54,7 @@ static int ip_forward_finish(struct sk_buff *skb)
 
 int ip_forward(struct sk_buff *skb)
 {
+       u32 mtu;
        struct iphdr *iph;      /* Our header */
        struct rtable *rt;      /* Route we use */
        struct ip_options *opt  = &(IPCB(skb)->opt);
@@ -88,11 +89,13 @@ int ip_forward(struct sk_buff *skb)
        if (opt->is_strictroute && rt->rt_uses_gateway)
                goto sr_failed;
 
-       if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
+       IPCB(skb)->flags |= IPSKB_FORWARDED;
+       mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
+       if (unlikely(skb->len > mtu && !skb_is_gso(skb) &&
                     (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
                IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-                         htonl(dst_mtu(&rt->dst)));
+                         htonl(mtu));
                goto drop;
        }
 
index df18461..8971780 100644 (file)
@@ -449,6 +449,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        __be16 not_last_frag;
        struct rtable *rt = skb_rtable(skb);
        int err = 0;
+       bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
 
        dev = rt->dst.dev;
 
@@ -458,12 +459,13 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
        iph = ip_hdr(skb);
 
+       mtu = ip_dst_mtu_maybe_forward(&rt->dst, forwarding);
        if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) ||
                     (IPCB(skb)->frag_max_size &&
-                     IPCB(skb)->frag_max_size > dst_mtu(&rt->dst)))) {
+                     IPCB(skb)->frag_max_size > mtu))) {
                IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-                         htonl(ip_skb_dst_mtu(skb)));
+                         htonl(mtu));
                kfree_skb(skb);
                return -EMSGSIZE;
        }
@@ -473,7 +475,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
         */
 
        hlen = iph->ihl * 4;
-       mtu = dst_mtu(&rt->dst) - hlen; /* Size of data space */
+       mtu = mtu - hlen;       /* Size of data space */
 #ifdef CONFIG_BRIDGE_NETFILTER
        if (skb->nf_bridge)
                mtu -= nf_bridge_mtu_reduction(skb);
@@ -1551,7 +1553,7 @@ void __init ip_init(void)
        ip_rt_init();
        inet_initpeers();
 
-#if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)
-       igmp_mc_proc_init();
+#if defined(CONFIG_IP_MULTICAST)
+       igmp_mc_init();
 #endif
 }
index f8da282..25071b4 100644 (file)
 #define RT_FL_TOS(oldflp4) \
        ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
 
-/* IPv4 datagram length is stored into 16bit field (tot_len) */
-#define IP_MAX_MTU     0xFFFF
-
 #define RT_GC_TIMEOUT (300*HZ)
 
 static int ip_rt_max_size;
index 1d2480a..44eba05 100644 (file)
@@ -831,6 +831,13 @@ static struct ctl_table ipv4_net_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "ip_forward_use_pmtu",
+               .data           = &init_net.ipv4.sysctl_ip_fwd_use_pmtu,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        { }
 };
 
index 0649373..699a42f 100644 (file)
@@ -31,7 +31,8 @@ struct tcp_fastopen_metrics {
 
 struct tcp_metrics_block {
        struct tcp_metrics_block __rcu  *tcpm_next;
-       struct inetpeer_addr            tcpm_addr;
+       struct inetpeer_addr            tcpm_saddr;
+       struct inetpeer_addr            tcpm_daddr;
        unsigned long                   tcpm_stamp;
        u32                             tcpm_ts;
        u32                             tcpm_ts_stamp;
@@ -131,7 +132,8 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst,
 }
 
 static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
-                                         struct inetpeer_addr *addr,
+                                         struct inetpeer_addr *saddr,
+                                         struct inetpeer_addr *daddr,
                                          unsigned int hash,
                                          bool reclaim)
 {
@@ -155,7 +157,8 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
                if (!tm)
                        goto out_unlock;
        }
-       tm->tcpm_addr = *addr;
+       tm->tcpm_saddr = *saddr;
+       tm->tcpm_daddr = *daddr;
 
        tcpm_suck_dst(tm, dst, true);
 
@@ -189,7 +192,8 @@ static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, in
        return NULL;
 }
 
-static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *addr,
+static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr,
+                                                  const struct inetpeer_addr *daddr,
                                                   struct net *net, unsigned int hash)
 {
        struct tcp_metrics_block *tm;
@@ -197,7 +201,8 @@ static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *a
 
        for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
             tm = rcu_dereference(tm->tcpm_next)) {
-               if (addr_same(&tm->tcpm_addr, addr))
+               if (addr_same(&tm->tcpm_saddr, saddr) &&
+                   addr_same(&tm->tcpm_daddr, daddr))
                        break;
                depth++;
        }
@@ -208,19 +213,22 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
                                                       struct dst_entry *dst)
 {
        struct tcp_metrics_block *tm;
-       struct inetpeer_addr addr;
+       struct inetpeer_addr saddr, daddr;
        unsigned int hash;
        struct net *net;
 
-       addr.family = req->rsk_ops->family;
-       switch (addr.family) {
+       saddr.family = req->rsk_ops->family;
+       daddr.family = req->rsk_ops->family;
+       switch (daddr.family) {
        case AF_INET:
-               addr.addr.a4 = inet_rsk(req)->ir_rmt_addr;
-               hash = (__force unsigned int) addr.addr.a4;
+               saddr.addr.a4 = inet_rsk(req)->ir_loc_addr;
+               daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr;
+               hash = (__force unsigned int) daddr.addr.a4;
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case AF_INET6:
-               *(struct in6_addr *)addr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr;
+               *(struct in6_addr *)saddr.addr.a6 = inet_rsk(req)->ir_v6_loc_addr;
+               *(struct in6_addr *)daddr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr;
                hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr);
                break;
 #endif
@@ -233,7 +241,8 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
 
        for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
             tm = rcu_dereference(tm->tcpm_next)) {
-               if (addr_same(&tm->tcpm_addr, &addr))
+               if (addr_same(&tm->tcpm_saddr, &saddr) &&
+                   addr_same(&tm->tcpm_daddr, &daddr))
                        break;
        }
        tcpm_check_stamp(tm, dst);
@@ -243,19 +252,22 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
 static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw)
 {
        struct tcp_metrics_block *tm;
-       struct inetpeer_addr addr;
+       struct inetpeer_addr saddr, daddr;
        unsigned int hash;
        struct net *net;
 
-       addr.family = tw->tw_family;
-       switch (addr.family) {
+       saddr.family = tw->tw_family;
+       daddr.family = tw->tw_family;
+       switch (daddr.family) {
        case AF_INET:
-               addr.addr.a4 = tw->tw_daddr;
-               hash = (__force unsigned int) addr.addr.a4;
+               saddr.addr.a4 = tw->tw_rcv_saddr;
+               daddr.addr.a4 = tw->tw_daddr;
+               hash = (__force unsigned int) daddr.addr.a4;
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case AF_INET6:
-               *(struct in6_addr *)addr.addr.a6 = tw->tw_v6_daddr;
+               *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr;
+               *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr;
                hash = ipv6_addr_hash(&tw->tw_v6_daddr);
                break;
 #endif
@@ -268,7 +280,8 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock
 
        for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
             tm = rcu_dereference(tm->tcpm_next)) {
-               if (addr_same(&tm->tcpm_addr, &addr))
+               if (addr_same(&tm->tcpm_saddr, &saddr) &&
+                   addr_same(&tm->tcpm_daddr, &daddr))
                        break;
        }
        return tm;
@@ -279,20 +292,23 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
                                                 bool create)
 {
        struct tcp_metrics_block *tm;
-       struct inetpeer_addr addr;
+       struct inetpeer_addr saddr, daddr;
        unsigned int hash;
        struct net *net;
        bool reclaim;
 
-       addr.family = sk->sk_family;
-       switch (addr.family) {
+       saddr.family = sk->sk_family;
+       daddr.family = sk->sk_family;
+       switch (daddr.family) {
        case AF_INET:
-               addr.addr.a4 = inet_sk(sk)->inet_daddr;
-               hash = (__force unsigned int) addr.addr.a4;
+               saddr.addr.a4 = inet_sk(sk)->inet_saddr;
+               daddr.addr.a4 = inet_sk(sk)->inet_daddr;
+               hash = (__force unsigned int) daddr.addr.a4;
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case AF_INET6:
-               *(struct in6_addr *)addr.addr.a6 = sk->sk_v6_daddr;
+               *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr;
+               *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr;
                hash = ipv6_addr_hash(&sk->sk_v6_daddr);
                break;
 #endif
@@ -303,14 +319,14 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
        net = dev_net(dst->dev);
        hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
 
-       tm = __tcp_get_metrics(&addr, net, hash);
+       tm = __tcp_get_metrics(&saddr, &daddr, net, hash);
        reclaim = false;
        if (tm == TCP_METRICS_RECLAIM_PTR) {
                reclaim = true;
                tm = NULL;
        }
        if (!tm && create)
-               tm = tcpm_new(dst, &addr, hash, reclaim);
+               tm = tcpm_new(dst, &saddr, &daddr, hash, reclaim);
        else
                tcpm_check_stamp(tm, dst);
 
@@ -724,15 +740,21 @@ static int tcp_metrics_fill_info(struct sk_buff *msg,
        struct nlattr *nest;
        int i;
 
-       switch (tm->tcpm_addr.family) {
+       switch (tm->tcpm_daddr.family) {
        case AF_INET:
                if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4,
-                               tm->tcpm_addr.addr.a4) < 0)
+                               tm->tcpm_daddr.addr.a4) < 0)
+                       goto nla_put_failure;
+               if (nla_put_be32(msg, TCP_METRICS_ATTR_SADDR_IPV4,
+                               tm->tcpm_saddr.addr.a4) < 0)
                        goto nla_put_failure;
                break;
        case AF_INET6:
                if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16,
-                           tm->tcpm_addr.addr.a6) < 0)
+                           tm->tcpm_daddr.addr.a6) < 0)
+                       goto nla_put_failure;
+               if (nla_put(msg, TCP_METRICS_ATTR_SADDR_IPV6, 16,
+                           tm->tcpm_saddr.addr.a6) < 0)
                        goto nla_put_failure;
                break;
        default:
@@ -855,44 +877,66 @@ done:
        return skb->len;
 }
 
-static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
-                        unsigned int *hash, int optional)
+static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
+                          unsigned int *hash, int optional, int v4, int v6)
 {
        struct nlattr *a;
 
-       a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV4];
+       a = info->attrs[v4];
        if (a) {
                addr->family = AF_INET;
                addr->addr.a4 = nla_get_be32(a);
-               *hash = (__force unsigned int) addr->addr.a4;
+               if (hash)
+                       *hash = (__force unsigned int) addr->addr.a4;
                return 0;
        }
-       a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV6];
+       a = info->attrs[v6];
        if (a) {
                if (nla_len(a) != sizeof(struct in6_addr))
                        return -EINVAL;
                addr->family = AF_INET6;
                memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6));
-               *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6);
+               if (hash)
+                       *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6);
                return 0;
        }
        return optional ? 1 : -EAFNOSUPPORT;
 }
 
+static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
+                        unsigned int *hash, int optional)
+{
+       return __parse_nl_addr(info, addr, hash, optional,
+                              TCP_METRICS_ATTR_ADDR_IPV4,
+                              TCP_METRICS_ATTR_ADDR_IPV6);
+}
+
+static int parse_nl_saddr(struct genl_info *info, struct inetpeer_addr *addr)
+{
+       return __parse_nl_addr(info, addr, NULL, 0,
+                              TCP_METRICS_ATTR_SADDR_IPV4,
+                              TCP_METRICS_ATTR_SADDR_IPV6);
+}
+
 static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
 {
        struct tcp_metrics_block *tm;
-       struct inetpeer_addr addr;
+       struct inetpeer_addr saddr, daddr;
        unsigned int hash;
        struct sk_buff *msg;
        struct net *net = genl_info_net(info);
        void *reply;
        int ret;
+       bool src = true;
 
-       ret = parse_nl_addr(info, &addr, &hash, 0);
+       ret = parse_nl_addr(info, &daddr, &hash, 0);
        if (ret < 0)
                return ret;
 
+       ret = parse_nl_saddr(info, &saddr);
+       if (ret < 0)
+               src = false;
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
@@ -907,7 +951,8 @@ static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
        rcu_read_lock();
        for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
             tm = rcu_dereference(tm->tcpm_next)) {
-               if (addr_same(&tm->tcpm_addr, &addr)) {
+               if (addr_same(&tm->tcpm_daddr, &daddr) &&
+                   (!src || addr_same(&tm->tcpm_saddr, &saddr))) {
                        ret = tcp_metrics_fill_info(msg, tm);
                        break;
                }
@@ -960,34 +1005,44 @@ static int tcp_metrics_flush_all(struct net *net)
 static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
        struct tcpm_hash_bucket *hb;
-       struct tcp_metrics_block *tm;
+       struct tcp_metrics_block *tm, *tmlist = NULL;
        struct tcp_metrics_block __rcu **pp;
-       struct inetpeer_addr addr;
+       struct inetpeer_addr saddr, daddr;
        unsigned int hash;
        struct net *net = genl_info_net(info);
        int ret;
+       bool src = true;
 
-       ret = parse_nl_addr(info, &addr, &hash, 1);
+       ret = parse_nl_addr(info, &daddr, &hash, 1);
        if (ret < 0)
                return ret;
        if (ret > 0)
                return tcp_metrics_flush_all(net);
+       ret = parse_nl_saddr(info, &saddr);
+       if (ret < 0)
+               src = false;
 
        hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
        hb = net->ipv4.tcp_metrics_hash + hash;
        pp = &hb->chain;
        spin_lock_bh(&tcp_metrics_lock);
-       for (tm = deref_locked_genl(*pp); tm;
-            pp = &tm->tcpm_next, tm = deref_locked_genl(*pp)) {
-               if (addr_same(&tm->tcpm_addr, &addr)) {
+       for (tm = deref_locked_genl(*pp); tm; tm = deref_locked_genl(*pp)) {
+               if (addr_same(&tm->tcpm_daddr, &daddr) &&
+                   (!src || addr_same(&tm->tcpm_saddr, &saddr))) {
                        *pp = tm->tcpm_next;
-                       break;
+                       tm->tcpm_next = tmlist;
+                       tmlist = tm;
+               } else {
+                       pp = &tm->tcpm_next;
                }
        }
        spin_unlock_bh(&tcp_metrics_lock);
-       if (!tm)
+       if (!tmlist)
                return -ESRCH;
-       kfree_rcu(tm, rcu_head);
+       for (tm = tmlist; tm; tm = tmlist) {
+               tmlist = tm->tcpm_next;
+               kfree_rcu(tm, rcu_head);
+       }
        return 0;
 }
 
index 771a395..b92b817 100644 (file)
@@ -138,7 +138,6 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
 out:
        return segs;
 }
-EXPORT_SYMBOL(tcp_gso_segment);
 
 struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 {
@@ -235,7 +234,6 @@ out:
 
        return pp;
 }
-EXPORT_SYMBOL(tcp_gro_receive);
 
 int tcp_gro_complete(struct sk_buff *skb)
 {
index 80f649f..3d3141f 100644 (file)
@@ -223,7 +223,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                inet_get_local_port_range(net, &low, &high);
                remaining = (high - low) + 1;
 
-               rand = net_random();
+               rand = prandom_u32();
                first = (((u64)rand * remaining) >> 32) + low;
                /*
                 * force rand to be an odd multiple of UDP_HTABLE_SIZE
index 31f75ea..6913a82 100644 (file)
@@ -900,15 +900,95 @@ out:
        goto out2;
 }
 
+enum cleanup_prefix_rt_t {
+       CLEANUP_PREFIX_RT_NOP,    /* no cleanup action for prefix route */
+       CLEANUP_PREFIX_RT_DEL,    /* delete the prefix route */
+       CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */
+};
+
+/*
+ * Check, whether the prefix for ifp would still need a prefix route
+ * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_*
+ * constants.
+ *
+ * 1) we don't purge prefix if address was not permanent.
+ *    prefix is managed by its own lifetime.
+ * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE.
+ * 3) if there are no addresses, delete prefix.
+ * 4) if there are still other permanent address(es),
+ *    corresponding prefix is still permanent.
+ * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE,
+ *    don't purge the prefix, assume user space is managing it.
+ * 6) otherwise, update prefix lifetime to the
+ *    longest valid lifetime among the corresponding
+ *    addresses on the device.
+ *    Note: subsequent RA will update lifetime.
+ **/
+static enum cleanup_prefix_rt_t
+check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)
+{
+       struct inet6_ifaddr *ifa;
+       struct inet6_dev *idev = ifp->idev;
+       unsigned long lifetime;
+       enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL;
+
+       *expires = jiffies;
+
+       list_for_each_entry(ifa, &idev->addr_list, if_list) {
+               if (ifa == ifp)
+                       continue;
+               if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr,
+                                      ifp->prefix_len))
+                       continue;
+               if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE))
+                       return CLEANUP_PREFIX_RT_NOP;
+
+               action = CLEANUP_PREFIX_RT_EXPIRE;
+
+               spin_lock(&ifa->lock);
+
+               lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
+               /*
+                * Note: Because this address is
+                * not permanent, lifetime <
+                * LONG_MAX / HZ here.
+                */
+               if (time_before(*expires, ifa->tstamp + lifetime * HZ))
+                       *expires = ifa->tstamp + lifetime * HZ;
+               spin_unlock(&ifa->lock);
+       }
+
+       return action;
+}
+
+static void
+cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt)
+{
+       struct rt6_info *rt;
+
+       rt = addrconf_get_prefix_route(&ifp->addr,
+                                      ifp->prefix_len,
+                                      ifp->idev->dev,
+                                      0, RTF_GATEWAY | RTF_DEFAULT);
+       if (rt) {
+               if (del_rt)
+                       ip6_del_rt(rt);
+               else {
+                       if (!(rt->rt6i_flags & RTF_EXPIRES))
+                               rt6_set_expires(rt, expires);
+                       ip6_rt_put(rt);
+               }
+       }
+}
+
+
 /* This function wants to get referenced ifp and releases it before return */
 
 static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 {
-       struct inet6_ifaddr *ifa, *ifn;
-       struct inet6_dev *idev = ifp->idev;
        int state;
-       int deleted = 0, onlink = 0;
-       unsigned long expires = jiffies;
+       enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP;
+       unsigned long expires;
 
        spin_lock_bh(&ifp->state_lock);
        state = ifp->state;
@@ -922,7 +1002,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
        hlist_del_init_rcu(&ifp->addr_lst);
        spin_unlock_bh(&addrconf_hash_lock);
 
-       write_lock_bh(&idev->lock);
+       write_lock_bh(&ifp->idev->lock);
 
        if (ifp->flags&IFA_F_TEMPORARY) {
                list_del(&ifp->tmp_list);
@@ -933,45 +1013,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
                __in6_ifa_put(ifp);
        }
 
-       list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) {
-               if (ifa == ifp) {
-                       list_del_init(&ifp->if_list);
-                       __in6_ifa_put(ifp);
+       if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE))
+               action = check_cleanup_prefix_route(ifp, &expires);
 
-                       if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
-                               break;
-                       deleted = 1;
-                       continue;
-               } else if (ifp->flags & IFA_F_PERMANENT) {
-                       if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,
-                                             ifp->prefix_len)) {
-                               if (ifa->flags & IFA_F_PERMANENT) {
-                                       onlink = 1;
-                                       if (deleted)
-                                               break;
-                               } else {
-                                       unsigned long lifetime;
-
-                                       if (!onlink)
-                                               onlink = -1;
-
-                                       spin_lock(&ifa->lock);
-
-                                       lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
-                                       /*
-                                        * Note: Because this address is
-                                        * not permanent, lifetime <
-                                        * LONG_MAX / HZ here.
-                                        */
-                                       if (time_before(expires,
-                                                       ifa->tstamp + lifetime * HZ))
-                                               expires = ifa->tstamp + lifetime * HZ;
-                                       spin_unlock(&ifa->lock);
-                               }
-                       }
-               }
-       }
-       write_unlock_bh(&idev->lock);
+       list_del_init(&ifp->if_list);
+       __in6_ifa_put(ifp);
+
+       write_unlock_bh(&ifp->idev->lock);
 
        addrconf_del_dad_timer(ifp);
 
@@ -979,38 +1027,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 
        inet6addr_notifier_call_chain(NETDEV_DOWN, ifp);
 
-       /*
-        * Purge or update corresponding prefix
-        *
-        * 1) we don't purge prefix here if address was not permanent.
-        *    prefix is managed by its own lifetime.
-        * 2) if there're no addresses, delete prefix.
-        * 3) if there're still other permanent address(es),
-        *    corresponding prefix is still permanent.
-        * 4) otherwise, update prefix lifetime to the
-        *    longest valid lifetime among the corresponding
-        *    addresses on the device.
-        *    Note: subsequent RA will update lifetime.
-        *
-        * --yoshfuji
-        */
-       if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
-               struct rt6_info *rt;
-
-               rt = addrconf_get_prefix_route(&ifp->addr,
-                                              ifp->prefix_len,
-                                              ifp->idev->dev,
-                                              0, RTF_GATEWAY | RTF_DEFAULT);
-
-               if (rt) {
-                       if (onlink == 0) {
-                               ip6_del_rt(rt);
-                               rt = NULL;
-                       } else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
-                               rt6_set_expires(rt, expires);
-                       }
-               }
-               ip6_rt_put(rt);
+       if (action != CLEANUP_PREFIX_RT_NOP) {
+               cleanup_prefix_route(ifp, expires,
+                       action == CLEANUP_PREFIX_RT_DEL);
        }
 
        /* clean up prefsrc entries */
@@ -1206,7 +1225,7 @@ static int ipv6_get_saddr_eval(struct net *net,
                 *       |             d is scope of the destination.
                 *  B-d  |  \
                 *       |   \      <- smaller scope is better if
-                *  B-15 |    \        if scope is enough for destinaion.
+                *  B-15 |    \        if scope is enough for destination.
                 *       |             ret = B - scope (-1 <= scope >= d <= 15).
                 * d-C-1 | /
                 *       |/         <- greater is better
@@ -1822,6 +1841,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
                return addrconf_ifid_sit(eui, dev);
        case ARPHRD_IPGRE:
                return addrconf_ifid_gre(eui, dev);
+       case ARPHRD_6LOWPAN:
        case ARPHRD_IEEE802154:
                return addrconf_ifid_eui64(eui, dev);
        case ARPHRD_IEEE1394:
@@ -2433,8 +2453,11 @@ static int inet6_addr_add(struct net *net, int ifindex,
                            valid_lft, prefered_lft);
 
        if (!IS_ERR(ifp)) {
-               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
-                                     expires, flags);
+               if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
+                       addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
+                                             expires, flags);
+               }
+
                /*
                 * Note that section 3.1 of RFC 4429 indicates
                 * that the Optimistic flag should not be set for
@@ -2528,7 +2551,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
        struct inet6_ifaddr *ifp;
 
        ifp = ipv6_add_addr(idev, addr, NULL, plen,
-                           scope, IFA_F_PERMANENT, 0, 0);
+                           scope, IFA_F_PERMANENT,
+                           INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
        if (!IS_ERR(ifp)) {
                spin_lock_bh(&ifp->lock);
                ifp->flags &= ~IFA_F_TENTATIVE;
@@ -2656,7 +2680,8 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
 #endif
 
 
-       ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0);
+       ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags,
+                           INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
        if (!IS_ERR(ifp)) {
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp);
@@ -2677,7 +2702,8 @@ static void addrconf_dev_config(struct net_device *dev)
            (dev->type != ARPHRD_INFINIBAND) &&
            (dev->type != ARPHRD_IEEE802154) &&
            (dev->type != ARPHRD_IEEE1394) &&
-           (dev->type != ARPHRD_TUNNEL6)) {
+           (dev->type != ARPHRD_TUNNEL6) &&
+           (dev->type != ARPHRD_6LOWPAN)) {
                /* Alas, we support only Ethernet autoconfiguration. */
                return;
        }
@@ -2874,7 +2900,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                }
 
                /*
-                * MTU falled under IPV6_MIN_MTU.
+                * if MTU under IPV6_MIN_MTU.
                 * Stop IPv6 on this interface.
                 */
 
@@ -3100,7 +3126,7 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
        if (ifp->flags & IFA_F_OPTIMISTIC)
                rand_num = 0;
        else
-               rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
+               rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);
 
        ifp->dad_probes = idev->cnf.dad_transmits;
        addrconf_mod_dad_timer(ifp, rand_num);
@@ -3113,7 +3139,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp)
 
        addrconf_join_solict(dev, &ifp->addr);
 
-       net_srandom(ifp->addr.s6_addr32[3]);
+       prandom_seed((__force u32) ifp->addr.s6_addr32[3]);
 
        read_lock_bh(&idev->lock);
        spin_lock(&ifp->lock);
@@ -3629,6 +3655,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
        clock_t expires;
        unsigned long timeout;
        bool was_managetempaddr;
+       bool had_prefixroute;
 
        if (!valid_lft || (prefered_lft > valid_lft))
                return -EINVAL;
@@ -3657,8 +3684,11 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
 
        spin_lock_bh(&ifp->lock);
        was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
+       had_prefixroute = ifp->flags & IFA_F_PERMANENT &&
+                         !(ifp->flags & IFA_F_NOPREFIXROUTE);
        ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD |
-                       IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR);
+                       IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
+                       IFA_F_NOPREFIXROUTE);
        ifp->flags |= ifa_flags;
        ifp->tstamp = jiffies;
        ifp->valid_lft = valid_lft;
@@ -3668,8 +3698,22 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
        if (!(ifp->flags&IFA_F_TENTATIVE))
                ipv6_ifa_notify(0, ifp);
 
-       addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
-                             expires, flags);
+       if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
+                                     expires, flags);
+       } else if (had_prefixroute) {
+               enum cleanup_prefix_rt_t action;
+               unsigned long rt_expires;
+
+               write_lock_bh(&ifp->idev->lock);
+               action = check_cleanup_prefix_route(ifp, &rt_expires);
+               write_unlock_bh(&ifp->idev->lock);
+
+               if (action != CLEANUP_PREFIX_RT_NOP) {
+                       cleanup_prefix_route(ifp, rt_expires,
+                               action == CLEANUP_PREFIX_RT_DEL);
+               }
+       }
 
        if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) {
                if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR))
@@ -3723,13 +3767,14 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
        ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags;
 
        /* We ignore other flags so far. */
-       ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR;
+       ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
+                    IFA_F_NOPREFIXROUTE;
 
        ifa = ipv6_get_ifaddr(net, pfx, dev, 1);
        if (ifa == NULL) {
                /*
                 * It would be best to check for !NLM_F_CREATE here but
-                * userspace alreay relies on not having to provide this.
+                * userspace already relies on not having to provide this.
                 */
                return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx,
                                      ifm->ifa_prefixlen, ifa_flags,
index 3fd0a57..b4d5e1d 100644 (file)
@@ -169,7 +169,7 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
                        return 0;
        }
 
-       if (r->tclass && r->tclass != ((ntohl(fl6->flowlabel) >> 20) & 0xff))
+       if (r->tclass && r->tclass != ip6_tclass(fl6->flowlabel))
                return 0;
 
        return 1;
index 9a809a4..902405d 100644 (file)
@@ -67,6 +67,7 @@
 #include <net/icmp.h>
 #include <net/xfrm.h>
 #include <net/inet_common.h>
+#include <net/dsfield.h>
 
 #include <asm/uaccess.h>
 
@@ -553,11 +554,12 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
        struct dst_entry *dst;
        int err = 0;
        int hlimit;
+       u8 tclass;
 
        saddr = &ipv6_hdr(skb)->daddr;
 
        if (!ipv6_unicast_destination(skb) &&
-           !(net->ipv6.anycast_src_echo_reply &&
+           !(net->ipv6.sysctl.anycast_src_echo_reply &&
              ipv6_anycast_destination(skb)))
                saddr = NULL;
 
@@ -603,8 +605,9 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
        msg.offset = 0;
        msg.type = ICMPV6_ECHO_REPLY;
 
+       tclass = ipv6_get_dsfield(ipv6_hdr(skb));
        err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
-                               sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl6,
+                               sizeof(struct icmp6hdr), hlimit, tclass, NULL, &fl6,
                                (struct rt6_info *)dst, MSG_DONTWAIT,
                                np->dontfrag);
 
index e7fb710..cbc9351 100644 (file)
@@ -210,7 +210,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net,
        spin_lock_bh(&ip6_fl_lock);
        if (label == 0) {
                for (;;) {
-                       fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK;
+                       fl->label = htonl(prandom_u32())&IPV6_FLOWLABEL_MASK;
                        if (fl->label) {
                                lfl = __fl_lookup(net, fl->label);
                                if (lfl == NULL)
index e7a440d..f3ffb43 100644 (file)
@@ -61,8 +61,6 @@ static bool log_ecn_error = true;
 module_param(log_ecn_error, bool, 0644);
 MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
 
-#define IPV6_TCLASS_SHIFT 20
-
 #define HASH_SIZE_SHIFT  5
 #define HASH_SIZE (1 << HASH_SIZE_SHIFT)
 
index d1de956..ef02b26 100644 (file)
@@ -321,6 +321,27 @@ static inline int ip6_forward_finish(struct sk_buff *skb)
        return dst_output(skb);
 }
 
+static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
+{
+       unsigned int mtu;
+       struct inet6_dev *idev;
+
+       if (dst_metric_locked(dst, RTAX_MTU)) {
+               mtu = dst_metric_raw(dst, RTAX_MTU);
+               if (mtu)
+                       return mtu;
+       }
+
+       mtu = IPV6_MIN_MTU;
+       rcu_read_lock();
+       idev = __in6_dev_get(dst->dev);
+       if (idev)
+               mtu = idev->cnf.mtu6;
+       rcu_read_unlock();
+
+       return mtu;
+}
+
 int ip6_forward(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
@@ -441,7 +462,7 @@ int ip6_forward(struct sk_buff *skb)
                }
        }
 
-       mtu = dst_mtu(dst);
+       mtu = ip6_dst_mtu_forward(dst);
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
 
index 1e5e240..5db8d31 100644 (file)
@@ -69,8 +69,6 @@ MODULE_ALIAS_NETDEV("ip6tnl0");
 #define IP6_TNL_TRACE(x...) do {;} while(0)
 #endif
 
-#define IPV6_TCLASS_SHIFT 20
-
 #define HASH_SIZE_SHIFT  5
 #define HASH_SIZE (1 << HASH_SIZE_SHIFT)
 
index b50acd5..2d19272 100644 (file)
@@ -731,12 +731,18 @@ static void vti6_dev_setup(struct net_device *dev)
 static inline int vti6_dev_init_gen(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
+       int i;
 
        t->dev = dev;
        t->net = dev_net(dev);
        dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
+       for_each_possible_cpu(i) {
+               struct pcpu_sw_netstats *stats;
+               stats = per_cpu_ptr(dev->tstats, i);
+               u64_stats_init(&stats->syncp);
+       }
        return 0;
 }
 
index af0ecb9..2855b00 100644 (file)
@@ -1019,7 +1019,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                                put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);
                        }
                        if (np->rxopt.bits.rxtclass) {
-                               int tclass = ntohl(np->rcv_flowinfo & IPV6_TCLASS_MASK) >> 20;
+                               int tclass = (int)ip6_tclass(np->rcv_flowinfo);
+
                                put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
                        }
                        if (np->rxopt.bits.rxoinfo) {
index d18f9f9..7ff82b3 100644 (file)
@@ -999,7 +999,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
 
 static void mld_gq_start_timer(struct inet6_dev *idev)
 {
-       unsigned long tv = net_random() % idev->mc_maxdelay;
+       unsigned long tv = prandom_u32() % idev->mc_maxdelay;
 
        idev->mc_gq_running = 1;
        if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2))
@@ -1015,7 +1015,7 @@ static void mld_gq_stop_timer(struct inet6_dev *idev)
 
 static void mld_ifc_start_timer(struct inet6_dev *idev, unsigned long delay)
 {
-       unsigned long tv = net_random() % delay;
+       unsigned long tv = prandom_u32() % delay;
 
        if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2))
                in6_dev_hold(idev);
@@ -1030,7 +1030,7 @@ static void mld_ifc_stop_timer(struct inet6_dev *idev)
 
 static void mld_dad_start_timer(struct inet6_dev *idev, unsigned long delay)
 {
-       unsigned long tv = net_random() % delay;
+       unsigned long tv = prandom_u32() % delay;
 
        if (!mod_timer(&idev->mc_dad_timer, jiffies+tv+2))
                in6_dev_hold(idev);
@@ -1061,7 +1061,7 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
        }
 
        if (delay >= resptime)
-               delay = net_random() % resptime;
+               delay = prandom_u32() % resptime;
 
        ma->mca_timer.expires = jiffies + delay;
        if (!mod_timer(&ma->mca_timer, jiffies + delay))
@@ -2328,7 +2328,7 @@ static void igmp6_join_group(struct ifmcaddr6 *ma)
 
        igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
 
-       delay = net_random() % unsolicited_report_interval(ma->idev);
+       delay = prandom_u32() % unsolicited_report_interval(ma->idev);
 
        spin_lock_bh(&ma->mca_lock);
        if (del_timer(&ma->mca_timer)) {
index 6b6a2c8..b51b268 100644 (file)
@@ -26,7 +26,7 @@ static struct ctl_table ipv6_table_template[] = {
        },
        {
                .procname       = "anycast_src_echo_reply",
-               .data           = &init_net.ipv6.anycast_src_echo_reply,
+               .data           = &init_net.ipv6.sysctl.anycast_src_echo_reply,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec
@@ -58,7 +58,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net)
        if (!ipv6_table)
                goto out;
        ipv6_table[0].data = &net->ipv6.sysctl.bindv6only;
-       ipv6_table[1].data = &net->ipv6.anycast_src_echo_reply;
+       ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply;
 
        ipv6_route_table = ipv6_route_sysctl_init(net);
        if (!ipv6_route_table)
index 9af77d9..735d0f6 100644 (file)
@@ -176,7 +176,7 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
  * owned by userspace.  A struct sock returned from this function must be
  * released using l2tp_tunnel_sock_put once you're done with it.
  */
-struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
+static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
 {
        int err = 0;
        struct socket *sock = NULL;
@@ -202,10 +202,9 @@ struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
 out:
        return sk;
 }
-EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_lookup);
 
 /* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */
-void l2tp_tunnel_sock_put(struct sock *sk)
+static void l2tp_tunnel_sock_put(struct sock *sk)
 {
        struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
        if (tunnel) {
@@ -217,7 +216,6 @@ void l2tp_tunnel_sock_put(struct sock *sk)
        }
        sock_put(sk);
 }
-EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put);
 
 /* Lookup a session by id in the global session list
  */
index 1ee9f69..1f01ba3 100644 (file)
@@ -238,8 +238,6 @@ out:
        return tunnel;
 }
 
-struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel);
-void l2tp_tunnel_sock_put(struct sock *sk);
 struct l2tp_session *l2tp_session_find(struct net *net,
                                       struct l2tp_tunnel *tunnel,
                                       u32 session_id);
index 537488c..9b9009f 100644 (file)
@@ -111,7 +111,7 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
 }
 
 
-struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
+struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[])
 {
        struct crypto_cipher *tfm;
 
index 20785a6..0ce6487 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/crypto.h>
 
-struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]);
+struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]);
 void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
                        const u8 *data, size_t data_len, u8 *mic);
 void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
index ac18528..09d2e58 100644 (file)
@@ -828,6 +828,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
        if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
                return 0;
 
+       mutex_lock(&local->mtx);
        mutex_lock(&local->iflist_mtx);
        if (local->use_chanctx) {
                sdata = rcu_dereference_protected(
@@ -846,6 +847,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
        if (ret == 0)
                local->monitor_chandef = *chandef;
        mutex_unlock(&local->iflist_mtx);
+       mutex_unlock(&local->mtx);
 
        return ret;
 }
@@ -951,6 +953,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                              struct cfg80211_ap_settings *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
        struct beacon_data *old;
        struct ieee80211_sub_if_data *vlan;
        u32 changed = BSS_CHANGED_BEACON_INT |
@@ -969,8 +972,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        sdata->needed_rx_chains = sdata->local->rx_chains;
        sdata->radar_required = params->radar_required;
 
+       mutex_lock(&local->mtx);
        err = ieee80211_vif_use_channel(sdata, &params->chandef,
                                        IEEE80211_CHANCTX_SHARED);
+       mutex_unlock(&local->mtx);
        if (err)
                return err;
        ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
@@ -1121,7 +1126,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        skb_queue_purge(&sdata->u.ap.ps.bc_buf);
 
        ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 
        return 0;
 }
@@ -1944,8 +1951,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
 
+       mutex_lock(&sdata->local->mtx);
        err = ieee80211_vif_use_channel(sdata, &setup->chandef,
                                        IEEE80211_CHANCTX_SHARED);
+       mutex_unlock(&sdata->local->mtx);
        if (err)
                return err;
 
@@ -1957,7 +1966,9 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        ieee80211_stop_mesh(sdata);
+       mutex_lock(&sdata->local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&sdata->local->mtx);
 
        return 0;
 }
@@ -2895,26 +2906,29 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
        unsigned long timeout;
        int err;
 
-       if (!list_empty(&local->roc_list) || local->scanning)
-               return -EBUSY;
+       mutex_lock(&local->mtx);
+       if (!list_empty(&local->roc_list) || local->scanning) {
+               err = -EBUSY;
+               goto out_unlock;
+       }
 
        /* whatever, but channel contexts should not complain about that one */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = local->rx_chains;
        sdata->radar_required = true;
 
-       mutex_lock(&local->iflist_mtx);
        err = ieee80211_vif_use_channel(sdata, chandef,
                                        IEEE80211_CHANCTX_SHARED);
-       mutex_unlock(&local->iflist_mtx);
        if (err)
-               return err;
+               goto out_unlock;
 
        timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
        ieee80211_queue_delayed_work(&sdata->local->hw,
                                     &sdata->dfs_cac_timer_work, timeout);
 
-       return 0;
+ out_unlock:
+       mutex_unlock(&local->mtx);
+       return err;
 }
 
 static struct cfg80211_beacon_data *
@@ -2990,7 +3004,9 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
                goto unlock;
 
        sdata->radar_required = sdata->csa_radar_required;
+       mutex_lock(&local->mtx);
        err = ieee80211_vif_change_channel(sdata, &changed);
+       mutex_unlock(&local->mtx);
        if (WARN_ON(err < 0))
                goto unlock;
 
@@ -3821,6 +3837,31 @@ static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
 }
 #endif
 
+static int ieee80211_set_qos_map(struct wiphy *wiphy,
+                                struct net_device *dev,
+                                struct cfg80211_qos_map *qos_map)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct mac80211_qos_map *new_qos_map, *old_qos_map;
+
+       if (qos_map) {
+               new_qos_map = kzalloc(sizeof(*new_qos_map), GFP_KERNEL);
+               if (!new_qos_map)
+                       return -ENOMEM;
+               memcpy(&new_qos_map->qos_map, qos_map, sizeof(*qos_map));
+       } else {
+               /* A NULL qos_map was passed to disable QoS mapping */
+               new_qos_map = NULL;
+       }
+
+       old_qos_map = rtnl_dereference(sdata->qos_map);
+       rcu_assign_pointer(sdata->qos_map, new_qos_map);
+       if (old_qos_map)
+               kfree_rcu(old_qos_map, rcu_head);
+
+       return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -3900,4 +3941,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .get_channel = ieee80211_cfg_get_channel,
        .start_radar_detection = ieee80211_start_radar_detection,
        .channel_switch = ieee80211_channel_switch,
+       .set_qos_map = ieee80211_set_qos_map,
 };
index a57d5d9..f43613a 100644 (file)
@@ -232,8 +232,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
        if (!local->use_chanctx)
                local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-       /* acquire mutex to prevent idle from changing */
-       mutex_lock(&local->mtx);
+       /* we hold the mutex to prevent idle from changing */
+       lockdep_assert_held(&local->mtx);
        /* turn idle off *before* setting channel -- some drivers need that */
        changed = ieee80211_idle_off(local);
        if (changed)
@@ -246,19 +246,14 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
                err = drv_add_chanctx(local, ctx);
                if (err) {
                        kfree(ctx);
-                       ctx = ERR_PTR(err);
-
                        ieee80211_recalc_idle(local);
-                       goto out;
+                       return ERR_PTR(err);
                }
        }
 
        /* and keep the mutex held until the new chanctx is on the list */
        list_add_rcu(&ctx->list, &local->chanctx_list);
 
- out:
-       mutex_unlock(&local->mtx);
-
        return ctx;
 }
 
@@ -294,9 +289,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
        /* throw a warning if this wasn't the only channel context. */
        WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
 
-       mutex_lock(&local->mtx);
        ieee80211_recalc_idle(local);
-       mutex_unlock(&local->mtx);
 }
 
 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
@@ -358,6 +351,31 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
        ieee80211_change_chanctx(local, ctx, compat);
 }
 
+static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
+                                          struct ieee80211_chanctx *chanctx)
+{
+       bool radar_enabled;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+       /* for setting local->radar_detect_enabled */
+       lockdep_assert_held(&local->mtx);
+
+       radar_enabled = ieee80211_is_radar_required(local);
+
+       if (radar_enabled == chanctx->conf.radar_enabled)
+               return;
+
+       chanctx->conf.radar_enabled = radar_enabled;
+       local->radar_detect_enabled = chanctx->conf.radar_enabled;
+
+       if (!local->use_chanctx) {
+               local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
+               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       }
+
+       drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
+}
+
 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
                                           struct ieee80211_chanctx *ctx)
 {
@@ -404,29 +422,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
                ieee80211_free_chanctx(local, ctx);
 }
 
-void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
-                                   struct ieee80211_chanctx *chanctx)
-{
-       bool radar_enabled;
-
-       lockdep_assert_held(&local->chanctx_mtx);
-
-       radar_enabled = ieee80211_is_radar_required(local);
-
-       if (radar_enabled == chanctx->conf.radar_enabled)
-               return;
-
-       chanctx->conf.radar_enabled = radar_enabled;
-       local->radar_detect_enabled = chanctx->conf.radar_enabled;
-
-       if (!local->use_chanctx) {
-               local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       }
-
-       drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
-}
-
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx)
 {
@@ -518,6 +513,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_chanctx *ctx;
        int ret;
 
+       lockdep_assert_held(&local->mtx);
+
        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 
        mutex_lock(&local->chanctx_mtx);
@@ -558,6 +555,8 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
        int ret;
        u32 chanctx_changed = 0;
 
+       lockdep_assert_held(&local->mtx);
+
        /* should never be called if not performing a channel switch. */
        if (WARN_ON(!sdata->vif.csa_active))
                return -EINVAL;
@@ -655,6 +654,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 {
        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 
+       lockdep_assert_held(&sdata->local->mtx);
+
        mutex_lock(&sdata->local->chanctx_mtx);
        __ieee80211_vif_release_channel(sdata);
        mutex_unlock(&sdata->local->chanctx_mtx);
index d6ba841..771080e 100644 (file)
@@ -293,14 +293,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                radar_required = true;
        }
 
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
        if (ieee80211_vif_use_channel(sdata, &chandef,
                                      ifibss->fixed_channel ?
                                        IEEE80211_CHANCTX_SHARED :
                                        IEEE80211_CHANCTX_EXCLUSIVE)) {
                sdata_info(sdata, "Failed to join IBSS, no channel context\n");
+               mutex_unlock(&local->mtx);
                return;
        }
+       mutex_unlock(&local->mtx);
 
        memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
@@ -363,7 +366,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.ssid_len = 0;
                RCU_INIT_POINTER(ifibss->presp, NULL);
                kfree_rcu(presp, rcu_head);
+               mutex_lock(&local->mtx);
                ieee80211_vif_release_channel(sdata);
+               mutex_unlock(&local->mtx);
                sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
                           err);
                return;
@@ -747,7 +752,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_IBSS);
        drv_leave_ibss(local, sdata);
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 }
 
 static void ieee80211_csa_connection_drop_work(struct work_struct *work)
index fb5dbcb..953b9e2 100644 (file)
@@ -246,7 +246,8 @@ struct ps_data {
        /* yes, this looks ugly, but guarantees that we can later use
         * bitmap_empty :)
         * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
-       u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
+       u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]
+                       __aligned(__alignof__(unsigned long));
        struct sk_buff_head bc_buf;
        atomic_t num_sta_ps; /* number of stations in PS mode */
        int dtim_count;
@@ -693,6 +694,11 @@ struct ieee80211_chanctx {
        struct ieee80211_chanctx_conf conf;
 };
 
+struct mac80211_qos_map {
+       struct cfg80211_qos_map qos_map;
+       struct rcu_head rcu_head;
+};
+
 struct ieee80211_sub_if_data {
        struct list_head list;
 
@@ -738,6 +744,7 @@ struct ieee80211_sub_if_data {
        int encrypt_headroom;
 
        struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
+       struct mac80211_qos_map __rcu *qos_map;
 
        struct work_struct csa_finalize_work;
        int csa_counter_offset_beacon;
@@ -1775,8 +1782,6 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
-void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
-                                   struct ieee80211_chanctx *chanctx);
 void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
                                      struct ieee80211_chanctx *ctx);
 
index d624ed4..3dfd20a 100644 (file)
@@ -418,8 +418,10 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
                return ret;
        }
 
+       mutex_lock(&local->mtx);
        ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
                                        IEEE80211_CHANCTX_EXCLUSIVE);
+       mutex_unlock(&local->mtx);
        if (ret) {
                drv_remove_interface(local, sdata);
                kfree(sdata);
@@ -456,7 +458,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 
        synchronize_net();
 
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 
        drv_remove_interface(local, sdata);
 
@@ -826,9 +830,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        if (sdata->wdev.cac_started) {
                chandef = sdata->vif.bss_conf.chandef;
                WARN_ON(local->suspended);
-               mutex_lock(&local->iflist_mtx);
+               mutex_lock(&local->mtx);
                ieee80211_vif_release_channel(sdata);
-               mutex_unlock(&local->iflist_mtx);
+               mutex_unlock(&local->mtx);
                cfg80211_cac_event(sdata->dev, &chandef,
                                   NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
@@ -1041,7 +1045,8 @@ static void ieee80211_uninit(struct net_device *dev)
 }
 
 static u16 ieee80211_netdev_select_queue(struct net_device *dev,
-                                        struct sk_buff *skb)
+                                        struct sk_buff *skb,
+                                        void *accel_priv)
 {
        return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
 }
@@ -1058,7 +1063,8 @@ static const struct net_device_ops ieee80211_dataif_ops = {
 };
 
 static u16 ieee80211_monitor_select_queue(struct net_device *dev,
-                                         struct sk_buff *skb)
+                                         struct sk_buff *skb,
+                                         void *accel_priv)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
index 9c2c7ee..fc1d824 100644 (file)
@@ -888,7 +888,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        if (!ifmgd->associated)
                goto out;
 
+       mutex_lock(&local->mtx);
        ret = ieee80211_vif_change_channel(sdata, &changed);
+       mutex_unlock(&local->mtx);
        if (ret) {
                sdata_info(sdata,
                           "vif channel switch failed, disconnecting\n");
@@ -1401,10 +1403,14 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
                             dfs_cac_timer_work);
        struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
 
-       ieee80211_vif_release_channel(sdata);
-       cfg80211_cac_event(sdata->dev, &chandef,
-                          NL80211_RADAR_CAC_FINISHED,
-                          GFP_KERNEL);
+       mutex_lock(&sdata->local->mtx);
+       if (sdata->wdev.cac_started) {
+               ieee80211_vif_release_channel(sdata);
+               cfg80211_cac_event(sdata->dev, &chandef,
+                                  NL80211_RADAR_CAC_FINISHED,
+                                  GFP_KERNEL);
+       }
+       mutex_unlock(&sdata->local->mtx);
 }
 
 /* MLME */
@@ -1747,7 +1753,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        ifmgd->have_beacon = false;
 
        ifmgd->flags = 0;
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 
        sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 }
@@ -2070,7 +2078,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
+               mutex_lock(&sdata->local->mtx);
                ieee80211_vif_release_channel(sdata);
+               mutex_unlock(&sdata->local->mtx);
        }
 
        cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
@@ -2319,7 +2329,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
+               mutex_lock(&sdata->local->mtx);
                ieee80211_vif_release_channel(sdata);
+               mutex_unlock(&sdata->local->mtx);
        }
 
        kfree(assoc_data);
@@ -3670,6 +3682,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        /* will change later if needed */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
 
+       mutex_lock(&local->mtx);
        /*
         * If this fails (possibly due to channel context sharing
         * on incompatible channels, e.g. 80+80 and 160 sharing the
@@ -3681,13 +3694,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        /* don't downgrade for 5 and 10 MHz channels, though. */
        if (chandef.width == NL80211_CHAN_WIDTH_5 ||
            chandef.width == NL80211_CHAN_WIDTH_10)
-               return ret;
+               goto out;
 
        while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
                ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
                ret = ieee80211_vif_use_channel(sdata, &chandef,
                                                IEEE80211_CHANCTX_SHARED);
        }
+ out:
+       mutex_unlock(&local->mtx);
        return ret;
 }
 
index d2f19f7..f3d88b0 100644 (file)
@@ -135,7 +135,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
        u32 usecs;
        int i;
 
-       for (i=0; i < MAX_THR_RATES; i++)
+       for (i = 0; i < MAX_THR_RATES; i++)
            tmp_tp_rate[i] = 0;
 
        for (i = 0; i < mi->n_rates; i++) {
@@ -190,7 +190,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
                 * choose the maximum throughput rate as max_prob_rate
                 * (2) if all success probabilities < 95%, the rate with
                 * highest success probability is choosen as max_prob_rate */
-               if (mr->probability >= MINSTREL_FRAC(95,100)) {
+               if (mr->probability >= MINSTREL_FRAC(95, 100)) {
                        if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
                                tmp_prob_rate = i;
                } else {
@@ -220,7 +220,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
 
 static void
 minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
-                   struct ieee80211_sta *sta, void *priv_sta,
+                  struct ieee80211_sta *sta, void *priv_sta,
                   struct sk_buff *skb)
 {
        struct minstrel_priv *mp = priv;
@@ -260,7 +260,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 static inline unsigned int
 minstrel_get_retry_count(struct minstrel_rate *mr,
-                         struct ieee80211_tx_info *info)
+                        struct ieee80211_tx_info *info)
 {
        unsigned int retry = mr->adjusted_retry_count;
 
index d2ed18d..c1b5b73 100644 (file)
@@ -63,7 +63,7 @@
 
 #define CCK_DURATION(_bitrate, _short, _len)           \
        (1000 * (10 /* SIFS */ +                        \
-        (_short ? 72 + 24 : 144 + 48 ) +               \
+        (_short ? 72 + 24 : 144 + 48) +                \
         (8 * (_len + 4) * 10) / (_bitrate)))
 
 #define CCK_ACK_DURATION(_bitrate, _short)                     \
index 124b1fd..0ae2077 100644 (file)
@@ -186,7 +186,7 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf,
 EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv);
 
 void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf,
-                               const u8 *ta, u32 iv32, u16 *p1k)
+                              const u8 *ta, u32 iv32, u16 *p1k)
 {
        const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
        struct tkip_ctx ctx;
index 3a669d7..da93666 100644 (file)
@@ -553,7 +553,7 @@ TRACE_EVENT(drv_update_tkip_key,
 
        TP_printk(
                LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
-               LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->iv32
        )
 );
 
index 2f0e176..ef3555e 100644 (file)
@@ -464,7 +464,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
        struct sta_info *sta = tx->sta;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_local *local = tx->local;
 
        if (unlikely(!sta))
@@ -475,15 +474,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                     !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
                int ac = skb_get_queue_mapping(tx->skb);
 
-               /* only deauth, disassoc and action are bufferable MMPDUs */
-               if (ieee80211_is_mgmt(hdr->frame_control) &&
-                   !ieee80211_is_deauth(hdr->frame_control) &&
-                   !ieee80211_is_disassoc(hdr->frame_control) &&
-                   !ieee80211_is_action(hdr->frame_control)) {
-                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
-                       return TX_CONTINUE;
-               }
-
                ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
                       sta->sta.addr, sta->sta.aid, ac);
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
@@ -526,9 +516,22 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
 {
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
        if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
                return TX_CONTINUE;
 
+       /* only deauth, disassoc and action are bufferable MMPDUs */
+       if (ieee80211_is_mgmt(hdr->frame_control) &&
+           !ieee80211_is_deauth(hdr->frame_control) &&
+           !ieee80211_is_disassoc(hdr->frame_control) &&
+           !ieee80211_is_action(hdr->frame_control)) {
+               if (tx->flags & IEEE80211_TX_UNICAST)
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+               return TX_CONTINUE;
+       }
+
        if (tx->flags & IEEE80211_TX_UNICAST)
                return ieee80211_tx_h_unicast_ps_buf(tx);
        else
@@ -2161,7 +2164,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (ieee80211_is_data_qos(fc)) {
                __le16 *qos_control;
 
-               qos_control = (__le16*) skb_push(skb, 2);
+               qos_control = (__le16 *) skb_push(skb, 2);
                memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
                /*
                 * Maybe we could actually set some fields here, for now just
@@ -2323,7 +2326,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
        if (atomic_read(&ps->num_sta_ps) > 0)
                /* in the hope that this is faster than
                 * checking byte-for-byte */
-               have_bits = !bitmap_empty((unsigned long*)ps->tim,
+               have_bits = !bitmap_empty((unsigned long *)ps->tim,
                                          IEEE80211_MAX_AID+1);
 
        if (ps->dtim_count == 0)
index 591b46b..df00f19 100644 (file)
@@ -76,7 +76,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
        }
 
        if (ieee80211_is_ctl(fc)) {
-               if(ieee80211_is_pspoll(fc))
+               if (ieee80211_is_pspoll(fc))
                        return hdr->addr1;
 
                if (ieee80211_is_back_req(fc)) {
@@ -2315,9 +2315,14 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
        struct ieee80211_sub_if_data *sdata;
        struct cfg80211_chan_def chandef;
 
+       mutex_lock(&local->mtx);
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
-               cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
+               /* it might be waiting for the local->mtx, but then
+                * by the time it gets it, sdata->wdev.cac_started
+                * will no longer be true
+                */
+               cancel_delayed_work(&sdata->dfs_cac_timer_work);
 
                if (sdata->wdev.cac_started) {
                        chandef = sdata->vif.bss_conf.chandef;
@@ -2329,6 +2334,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
                }
        }
        mutex_unlock(&local->iflist_mtx);
+       mutex_unlock(&local->mtx);
 }
 
 void ieee80211_dfs_radar_detected_work(struct work_struct *work)
@@ -2588,3 +2594,143 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
 
        return headroom;
 }
+
+static bool
+ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
+{
+       s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1);
+       int skip;
+
+       if (end > 0)
+               return false;
+
+       /* End time is in the past, check for repetitions */
+       skip = DIV_ROUND_UP(-end, data->desc[i].interval);
+       if (data->count[i] < 255) {
+               if (data->count[i] <= skip) {
+                       data->count[i] = 0;
+                       return false;
+               }
+
+               data->count[i] -= skip;
+       }
+
+       data->desc[i].start += skip * data->desc[i].interval;
+
+       return true;
+}
+
+static bool
+ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf,
+                            s32 *offset)
+{
+       bool ret = false;
+       int i;
+
+       for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
+               s32 cur;
+
+               if (!data->count[i])
+                       continue;
+
+               if (ieee80211_extend_noa_desc(data, tsf + *offset, i))
+                       ret = true;
+
+               cur = data->desc[i].start - tsf;
+               if (cur > *offset)
+                       continue;
+
+               cur = data->desc[i].start + data->desc[i].duration - tsf;
+               if (cur > *offset)
+                       *offset = cur;
+       }
+
+       return ret;
+}
+
+static u32
+ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf)
+{
+       s32 offset = 0;
+       int tries = 0;
+       /*
+        * arbitrary limit, used to avoid infinite loops when combined NoA
+        * descriptors cover the full time period.
+        */
+       int max_tries = 5;
+
+       ieee80211_extend_absent_time(data, tsf, &offset);
+       do {
+               if (!ieee80211_extend_absent_time(data, tsf, &offset))
+                       break;
+
+               tries++;
+       } while (tries < max_tries);
+
+       return offset;
+}
+
+void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf)
+{
+       u32 next_offset = BIT(31) - 1;
+       int i;
+
+       data->absent = 0;
+       data->has_next_tsf = false;
+       for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
+               s32 start;
+
+               if (!data->count[i])
+                       continue;
+
+               ieee80211_extend_noa_desc(data, tsf, i);
+               start = data->desc[i].start - tsf;
+               if (start <= 0)
+                       data->absent |= BIT(i);
+
+               if (next_offset > start)
+                       next_offset = start;
+
+               data->has_next_tsf = true;
+       }
+
+       if (data->absent)
+               next_offset = ieee80211_get_noa_absent_time(data, tsf);
+
+       data->next_tsf = tsf + next_offset;
+}
+EXPORT_SYMBOL(ieee80211_update_p2p_noa);
+
+int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
+                           struct ieee80211_noa_data *data, u32 tsf)
+{
+       int ret = 0;
+       int i;
+
+       memset(data, 0, sizeof(*data));
+
+       for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
+               const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i];
+
+               if (!desc->count || !desc->duration)
+                       continue;
+
+               data->count[i] = desc->count;
+               data->desc[i].start = le32_to_cpu(desc->start_time);
+               data->desc[i].duration = le32_to_cpu(desc->duration);
+               data->desc[i].interval = le32_to_cpu(desc->interval);
+
+               if (data->count[i] > 1 &&
+                   data->desc[i].interval < data->desc[i].duration)
+                       continue;
+
+               ieee80211_extend_noa_desc(data, tsf, i);
+               ret++;
+       }
+
+       if (ret)
+               ieee80211_update_p2p_noa(data, tsf);
+
+       return ret;
+}
+EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
index afba19c..21211c6 100644 (file)
@@ -106,6 +106,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta = NULL;
        const u8 *ra = NULL;
        bool qos = false;
+       struct mac80211_qos_map *qos_map;
 
        if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
                skb->priority = 0; /* required for correct WPA/11i MIC */
@@ -155,7 +156,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
 
        /* use the data classifier to determine what 802.1d tag the
         * data frame has */
-       skb->priority = cfg80211_classify8021d(skb);
+       rcu_read_lock();
+       qos_map = rcu_dereference(sdata->qos_map);
+       skb->priority = cfg80211_classify8021d(skb, qos_map ?
+                                              &qos_map->qos_map : NULL);
+       rcu_read_unlock();
 
        return ieee80211_downgrade_queue(sdata, skb);
 }
index 6941a4f..c374675 100644 (file)
@@ -1139,6 +1139,16 @@ config NETFILTER_XT_MATCH_IPVS
 
          If unsure, say N.
 
+config NETFILTER_XT_MATCH_L2TP
+       tristate '"l2tp" match support'
+       depends on NETFILTER_ADVANCED
+       default L2TP
+       ---help---
+       This option adds an "L2TP" match, which allows you to match against
+       L2TP protocol header fields.
+
+       To compile it as a module, choose M here. If unsure, say N.
+
 config NETFILTER_XT_MATCH_LENGTH
        tristate '"length" match support'
        depends on NETFILTER_ADVANCED
index 74c0661..ee9c4de 100644 (file)
@@ -138,6 +138,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_IPCOMP) += xt_ipcomp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_L2TP) += xt_l2tp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
index 4c8e5c0..59a1a85 100644 (file)
@@ -1209,7 +1209,7 @@ void ip_vs_random_dropentry(struct net *net)
         * Randomly scan 1/32 of the whole table every second
         */
        for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) {
-               unsigned int hash = net_random() & ip_vs_conn_tab_mask;
+               unsigned int hash = prandom_u32() & ip_vs_conn_tab_mask;
 
                hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {
                        if (cp->flags & IP_VS_CONN_F_TEMPLATE)
index b2d38da..f6e2ae9 100644 (file)
@@ -37,7 +37,7 @@ int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
                return 0;
 
        if (unlikely(!seqadj)) {
-               WARN(1, "Wrong seqadj usage, missing nfct_seqadj_ext_add()\n");
+               WARN_ONCE(1, "Missing nfct_seqadj_ext_add() setup call\n");
                return 0;
        }
 
index f02b360..1fb2258 100644 (file)
@@ -34,10 +34,14 @@ static unsigned int help(struct sk_buff *skb,
                         struct nf_conntrack_expect *exp)
 {
        char buffer[sizeof("4294967296 65635")];
+       struct nf_conn *ct = exp->master;
+       union nf_inet_addr newaddr;
        u_int16_t port;
        unsigned int ret;
 
        /* Reply comes from server. */
+       newaddr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3;
+
        exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
        exp->dir = IP_CT_DIR_REPLY;
        exp->expectfn = nf_nat_follow_master;
@@ -57,17 +61,35 @@ static unsigned int help(struct sk_buff *skb,
        }
 
        if (port == 0) {
-               nf_ct_helper_log(skb, exp->master, "all ports in use");
+               nf_ct_helper_log(skb, ct, "all ports in use");
                return NF_DROP;
        }
 
-       ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
-                                      protoff, matchoff, matchlen, buffer,
-                                      strlen(buffer));
+       /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
+        * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
+        * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
+        * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
+        * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
+        *
+        * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
+        *                        255.255.255.255==4294967296, 10 digits)
+        * P:         bound port (min 1 d, max 5d (65635))
+        * F:         filename   (min 1 d )
+        * S:         size       (min 1 d )
+        * 0x01, \n:  terminators
+        */
+       /* AAA = "us", ie. where server normally talks to. */
+       snprintf(buffer, sizeof(buffer), "%u %u", ntohl(newaddr.ip), port);
+       pr_debug("nf_nat_irc: inserting '%s' == %pI4, port %u\n",
+                buffer, &newaddr.ip, port);
+
+       ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, matchoff,
+                                      matchlen, buffer, strlen(buffer));
        if (ret != NF_ACCEPT) {
-               nf_ct_helper_log(skb, exp->master, "cannot mangle packet");
+               nf_ct_helper_log(skb, ct, "cannot mangle packet");
                nf_ct_unexpect_related(exp);
        }
+
        return ret;
 }
 
diff --git a/net/netfilter/xt_l2tp.c b/net/netfilter/xt_l2tp.c
new file mode 100644 (file)
index 0000000..8aee572
--- /dev/null
@@ -0,0 +1,354 @@
+/* Kernel module to match L2TP header parameters. */
+
+/* (C) 2013      James Chapman <jchapman@katalix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/udp.h>
+#include <linux/l2tp.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter/xt_l2tp.h>
+
+/* L2TP header masks */
+#define L2TP_HDR_T_BIT 0x8000
+#define L2TP_HDR_L_BIT 0x4000
+#define L2TP_HDR_VER   0x000f
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("Xtables: L2TP header match");
+MODULE_ALIAS("ipt_l2tp");
+MODULE_ALIAS("ip6t_l2tp");
+
+/* The L2TP fields that can be matched */
+struct l2tp_data {
+       u32 tid;
+       u32 sid;
+       u8 type;
+       u8 version;
+};
+
+union l2tp_val {
+       __be16 val16[2];
+       __be32 val32;
+};
+
+static bool l2tp_match(const struct xt_l2tp_info *info, struct l2tp_data *data)
+{
+       if ((info->flags & XT_L2TP_TYPE) && (info->type != data->type))
+               return false;
+
+       if ((info->flags & XT_L2TP_VERSION) && (info->version != data->version))
+               return false;
+
+       /* Check tid only for L2TPv3 control or any L2TPv2 packets */
+       if ((info->flags & XT_L2TP_TID) &&
+           ((data->type == XT_L2TP_TYPE_CONTROL) || (data->version == 2)) &&
+           (info->tid != data->tid))
+               return false;
+
+       /* Check sid only for L2TP data packets */
+       if ((info->flags & XT_L2TP_SID) && (data->type == XT_L2TP_TYPE_DATA) &&
+           (info->sid != data->sid))
+               return false;
+
+       return true;
+}
+
+/* Parse L2TP header fields when UDP encapsulation is used. Handles
+ * L2TPv2 and L2TPv3. Note the L2TPv3 control and data packets have a
+ * different format. See
+ * RFC2661, Section 3.1, L2TPv2 Header Format
+ * RFC3931, Section 3.2.1, L2TPv3 Control Message Header
+ * RFC3931, Section 3.2.2, L2TPv3 Data Message Header
+ * RFC3931, Section 4.1.2.1, L2TPv3 Session Header over UDP
+ */
+static bool l2tp_udp_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 thoff)
+{
+       const struct xt_l2tp_info *info = par->matchinfo;
+       int uhlen = sizeof(struct udphdr);
+       int offs = thoff + uhlen;
+       union l2tp_val *lh;
+       union l2tp_val lhbuf;
+       u16 flags;
+       struct l2tp_data data = { 0, };
+
+       if (par->fragoff != 0)
+               return false;
+
+       /* Extract L2TP header fields. The flags in the first 16 bits
+        * tell us where the other fields are.
+        */
+       lh = skb_header_pointer(skb, offs, 2, &lhbuf);
+       if (lh == NULL)
+               return false;
+
+       flags = ntohs(lh->val16[0]);
+       if (flags & L2TP_HDR_T_BIT)
+               data.type = XT_L2TP_TYPE_CONTROL;
+       else
+               data.type = XT_L2TP_TYPE_DATA;
+       data.version = (u8) flags & L2TP_HDR_VER;
+
+       /* Now extract the L2TP tid/sid. These are in different places
+        * for L2TPv2 (rfc2661) and L2TPv3 (rfc3931). For L2TPv2, we
+        * must also check to see if the length field is present,
+        * since this affects the offsets into the packet of the
+        * tid/sid fields.
+        */
+       if (data.version == 3) {
+               lh = skb_header_pointer(skb, offs + 4, 4, &lhbuf);
+               if (lh == NULL)
+                       return false;
+               if (data.type == XT_L2TP_TYPE_CONTROL)
+                       data.tid = ntohl(lh->val32);
+               else
+                       data.sid = ntohl(lh->val32);
+       } else if (data.version == 2) {
+               if (flags & L2TP_HDR_L_BIT)
+                       offs += 2;
+               lh = skb_header_pointer(skb, offs + 2, 4, &lhbuf);
+               if (lh == NULL)
+                       return false;
+               data.tid = (u32) ntohs(lh->val16[0]);
+               data.sid = (u32) ntohs(lh->val16[1]);
+       } else
+               return false;
+
+       return l2tp_match(info, &data);
+}
+
+/* Parse L2TP header fields for IP encapsulation (no UDP header).
+ * L2TPv3 data packets have a different form with IP encap. See
+ * RC3931, Section 4.1.1.1, L2TPv3 Session Header over IP.
+ * RC3931, Section 4.1.1.2, L2TPv3 Control and Data Traffic over IP.
+ */
+static bool l2tp_ip_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 thoff)
+{
+       const struct xt_l2tp_info *info = par->matchinfo;
+       union l2tp_val *lh;
+       union l2tp_val lhbuf;
+       struct l2tp_data data = { 0, };
+
+       /* For IP encap, the L2TP sid is the first 32-bits. */
+       lh = skb_header_pointer(skb, thoff, sizeof(lhbuf), &lhbuf);
+       if (lh == NULL)
+               return false;
+       if (lh->val32 == 0) {
+               /* Must be a control packet. The L2TP tid is further
+                * into the packet.
+                */
+               data.type = XT_L2TP_TYPE_CONTROL;
+               lh = skb_header_pointer(skb, thoff + 8, sizeof(lhbuf),
+                                       &lhbuf);
+               if (lh == NULL)
+                       return false;
+               data.tid = ntohl(lh->val32);
+       } else {
+               data.sid = ntohl(lh->val32);
+               data.type = XT_L2TP_TYPE_DATA;
+       }
+
+       data.version = 3;
+
+       return l2tp_match(info, &data);
+}
+
+static bool l2tp_mt4(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       struct iphdr *iph = ip_hdr(skb);
+       u8 ipproto = iph->protocol;
+
+       /* l2tp_mt_check4 already restricts the transport protocol */
+       switch (ipproto) {
+       case IPPROTO_UDP:
+               return l2tp_udp_mt(skb, par, par->thoff);
+       case IPPROTO_L2TP:
+               return l2tp_ip_mt(skb, par, par->thoff);
+       }
+
+       return false;
+}
+
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+static bool l2tp_mt6(const struct sk_buff *skb, struct xt_action_param *par)
+{
+       unsigned int thoff = 0;
+       unsigned short fragoff = 0;
+       int ipproto;
+
+       ipproto = ipv6_find_hdr(skb, &thoff, -1, &fragoff, NULL);
+       if (fragoff != 0)
+               return false;
+
+       /* l2tp_mt_check6 already restricts the transport protocol */
+       switch (ipproto) {
+       case IPPROTO_UDP:
+               return l2tp_udp_mt(skb, par, thoff);
+       case IPPROTO_L2TP:
+               return l2tp_ip_mt(skb, par, thoff);
+       }
+
+       return false;
+}
+#endif
+
+static int l2tp_mt_check(const struct xt_mtchk_param *par)
+{
+       const struct xt_l2tp_info *info = par->matchinfo;
+
+       /* Check for invalid flags */
+       if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION |
+                           XT_L2TP_TYPE)) {
+               pr_info("unknown flags: %x\n", info->flags);
+               return -EINVAL;
+       }
+
+       /* At least one of tid, sid or type=control must be specified */
+       if ((!(info->flags & XT_L2TP_TID)) &&
+           (!(info->flags & XT_L2TP_SID)) &&
+           ((!(info->flags & XT_L2TP_TYPE)) ||
+            (info->type != XT_L2TP_TYPE_CONTROL))) {
+               pr_info("invalid flags combination: %x\n", info->flags);
+               return -EINVAL;
+       }
+
+       /* If version 2 is specified, check that incompatible params
+        * are not supplied
+        */
+       if (info->flags & XT_L2TP_VERSION) {
+               if ((info->version < 2) || (info->version > 3)) {
+                       pr_info("wrong L2TP version: %u\n", info->version);
+                       return -EINVAL;
+               }
+
+               if (info->version == 2) {
+                       if ((info->flags & XT_L2TP_TID) &&
+                           (info->tid > 0xffff)) {
+                               pr_info("v2 tid > 0xffff: %u\n", info->tid);
+                               return -EINVAL;
+                       }
+                       if ((info->flags & XT_L2TP_SID) &&
+                           (info->sid > 0xffff)) {
+                               pr_info("v2 sid > 0xffff: %u\n", info->sid);
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int l2tp_mt_check4(const struct xt_mtchk_param *par)
+{
+       const struct xt_l2tp_info *info = par->matchinfo;
+       const struct ipt_entry *e = par->entryinfo;
+       const struct ipt_ip *ip = &e->ip;
+       int ret;
+
+       ret = l2tp_mt_check(par);
+       if (ret != 0)
+               return ret;
+
+       if ((ip->proto != IPPROTO_UDP) &&
+           (ip->proto != IPPROTO_L2TP)) {
+               pr_info("missing protocol rule (udp|l2tpip)\n");
+               return -EINVAL;
+       }
+
+       if ((ip->proto == IPPROTO_L2TP) &&
+           (info->version == 2)) {
+               pr_info("v2 doesn't support IP mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+static int l2tp_mt_check6(const struct xt_mtchk_param *par)
+{
+       const struct xt_l2tp_info *info = par->matchinfo;
+       const struct ip6t_entry *e = par->entryinfo;
+       const struct ip6t_ip6 *ip = &e->ipv6;
+       int ret;
+
+       ret = l2tp_mt_check(par);
+       if (ret != 0)
+               return ret;
+
+       if ((ip->proto != IPPROTO_UDP) &&
+           (ip->proto != IPPROTO_L2TP)) {
+               pr_info("missing protocol rule (udp|l2tpip)\n");
+               return -EINVAL;
+       }
+
+       if ((ip->proto == IPPROTO_L2TP) &&
+           (info->version == 2)) {
+               pr_info("v2 doesn't support IP mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#endif
+
+static struct xt_match l2tp_mt_reg[] __read_mostly = {
+       {
+               .name      = "l2tp",
+               .revision  = 0,
+               .family    = NFPROTO_IPV4,
+               .match     = l2tp_mt4,
+               .matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)),
+               .checkentry = l2tp_mt_check4,
+               .hooks     = ((1 << NF_INET_PRE_ROUTING) |
+                             (1 << NF_INET_LOCAL_IN) |
+                             (1 << NF_INET_LOCAL_OUT) |
+                             (1 << NF_INET_FORWARD)),
+               .me        = THIS_MODULE,
+       },
+#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
+       {
+               .name      = "l2tp",
+               .revision  = 0,
+               .family    = NFPROTO_IPV6,
+               .match     = l2tp_mt6,
+               .matchsize = XT_ALIGN(sizeof(struct xt_l2tp_info)),
+               .checkentry = l2tp_mt_check6,
+               .hooks     = ((1 << NF_INET_PRE_ROUTING) |
+                             (1 << NF_INET_LOCAL_IN) |
+                             (1 << NF_INET_LOCAL_OUT) |
+                             (1 << NF_INET_FORWARD)),
+               .me        = THIS_MODULE,
+       },
+#endif
+};
+
+static int __init l2tp_mt_init(void)
+{
+       return xt_register_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg));
+}
+
+static void __exit l2tp_mt_exit(void)
+{
+       xt_unregister_matches(&l2tp_mt_reg[0], ARRAY_SIZE(l2tp_mt_reg));
+}
+
+module_init(l2tp_mt_init);
+module_exit(l2tp_mt_exit);
index 4fe4fb4..11de55e 100644 (file)
@@ -37,7 +37,7 @@ statistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
 
        switch (info->mode) {
        case XT_STATISTIC_MODE_RANDOM:
-               if ((net_random() & 0x7FFFFFFF) < info->u.random.probability)
+               if ((prandom_u32() & 0x7FFFFFFF) < info->u.random.probability)
                        ret = !ret;
                break;
        case XT_STATISTIC_MODE_NTH:
index 02ab341..b675fa4 100644 (file)
@@ -382,7 +382,7 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
 {
        dev->dep_link_up = true;
 
-       if (!dev->active_target) {
+       if (!dev->active_target && rf_mode == NFC_RF_INITIATOR) {
                struct nfc_target *target;
 
                target = nfc_find_target(dev, target_idx);
index 719ad0a..401c7e2 100644 (file)
@@ -298,7 +298,7 @@ static void llc_shdlc_rcv_rej(struct llc_shdlc *shdlc, int y_nr)
 {
        struct sk_buff *skb;
 
-       pr_debug("remote asks retransmition from frame %d\n", y_nr);
+       pr_debug("remote asks retransmission from frame %d\n", y_nr);
 
        if (llc_shdlc_x_lteq_y_lt_z(shdlc->dnr, y_nr, shdlc->ns)) {
                if (shdlc->t2_active) {
index 716b7ee..2c77e7b 100644 (file)
@@ -445,7 +445,7 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
                 a = nla_next(a, &rem)) {
                switch (nla_type(a)) {
                case OVS_SAMPLE_ATTR_PROBABILITY:
-                       if (net_random() >= nla_get_u32(a))
+                       if (prandom_u32() >= nla_get_u32(a))
                                return 0;
                        break;
 
index b5ad65a..a2e6562 100644 (file)
@@ -117,7 +117,7 @@ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port)
                rover = be16_to_cpu(*port);
                last = rover;
        } else {
-               rover = max_t(u16, net_random(), 2);
+               rover = max_t(u16, prandom_u32(), 2);
                last = rover - 1;
        }
 
index f63e146..35f89e9 100644 (file)
@@ -173,16 +173,16 @@ struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
 }
 EXPORT_SYMBOL(tcf_hash_lookup);
 
-u32 tcf_hash_new_index(u32 *idx_gen, struct tcf_hashinfo *hinfo)
+u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo)
 {
-       u32 val = *idx_gen;
+       u32 val = hinfo->index;
 
        do {
                if (++val == 0)
                        val = 1;
        } while (tcf_hash_lookup(val, hinfo));
 
-       *idx_gen = val;
+       hinfo->index = val;
        return val;
 }
 EXPORT_SYMBOL(tcf_hash_new_index);
@@ -215,7 +215,7 @@ EXPORT_SYMBOL(tcf_hash_check);
 
 struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
                                   struct tc_action *a, int size, int bind,
-                                  u32 *idx_gen, struct tcf_hashinfo *hinfo)
+                                  struct tcf_hashinfo *hinfo)
 {
        struct tcf_common *p = kzalloc(size, GFP_KERNEL);
 
@@ -227,7 +227,7 @@ struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
 
        spin_lock_init(&p->tcfc_lock);
        INIT_HLIST_NODE(&p->tcfc_head);
-       p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
+       p->tcfc_index = index ? index : tcf_hash_new_index(hinfo);
        p->tcfc_tm.install = jiffies;
        p->tcfc_tm.lastuse = jiffies;
        if (est) {
@@ -556,9 +556,9 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
 {
        int err = 0;
        struct gnet_dump d;
-       struct tcf_act_hdr *h = a->priv;
+       struct tcf_common *p = a->priv;
 
-       if (h == NULL)
+       if (p == NULL)
                goto errout;
 
        /* compat_mode being true specifies a call that is supposed
@@ -567,20 +567,20 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
        if (compat_mode) {
                if (a->type == TCA_OLD_COMPAT)
                        err = gnet_stats_start_copy_compat(skb, 0,
-                               TCA_STATS, TCA_XSTATS, &h->tcf_lock, &d);
+                               TCA_STATS, TCA_XSTATS, &p->tcfc_lock, &d);
                else
                        return 0;
        } else
                err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
-                                           &h->tcf_lock, &d);
+                                           &p->tcfc_lock, &d);
 
        if (err < 0)
                goto errout;
 
-       if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
-           gnet_stats_copy_rate_est(&d, &h->tcf_bstats,
-                                    &h->tcf_rate_est) < 0 ||
-           gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
+       if (gnet_stats_copy_basic(&d, &p->tcfc_bstats) < 0 ||
+           gnet_stats_copy_rate_est(&d, &p->tcfc_bstats,
+                                    &p->tcfc_rate_est) < 0 ||
+           gnet_stats_copy_queue(&d, &p->tcfc_qstats) < 0)
                goto errout;
 
        if (gnet_stats_finish_copy(&d) < 0)
@@ -789,6 +789,33 @@ noflush_out:
 }
 
 static int
+tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
+              u32 portid)
+{
+       int ret;
+       struct sk_buff *skb;
+
+       skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!skb)
+               return -ENOBUFS;
+
+       if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, RTM_DELACTION,
+                        0, 1) <= 0) {
+               kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       /* now do the delete */
+       tcf_action_destroy(actions, 0);
+
+       ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
+                            n->nlmsg_flags & NLM_F_ECHO);
+       if (ret > 0)
+               return 0;
+       return ret;
+}
+
+static int
 tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
              u32 portid, int event)
 {
@@ -821,27 +848,9 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
        if (event == RTM_GETACTION)
                ret = act_get_notify(net, portid, n, &actions, event);
        else { /* delete */
-               struct sk_buff *skb;
-
-               skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
-               if (!skb) {
-                       ret = -ENOBUFS;
-                       goto err;
-               }
-
-               if (tca_get_fill(skb, &actions, portid, n->nlmsg_seq, 0, event,
-                                0, 1) <= 0) {
-                       kfree_skb(skb);
-                       ret = -EINVAL;
+               ret = tcf_del_notify(net, n, &actions, portid);
+               if (ret)
                        goto err;
-               }
-
-               /* now do the delete */
-               tcf_action_destroy(&actions, 0);
-               ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
-                                    n->nlmsg_flags & NLM_F_ECHO);
-               if (ret > 0)
-                       return 0;
                return ret;
        }
 err:
@@ -849,60 +858,36 @@ err:
        return ret;
 }
 
-static int tcf_add_notify(struct net *net, struct list_head *actions,
-                         u32 portid, u32 seq, int event, u16 flags)
+static int
+tcf_add_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
+              u32 portid)
 {
-       struct tcamsg *t;
-       struct nlmsghdr *nlh;
        struct sk_buff *skb;
-       struct nlattr *nest;
-       unsigned char *b;
        int err = 0;
 
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!skb)
                return -ENOBUFS;
 
-       b = skb_tail_pointer(skb);
-
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(*t), flags);
-       if (!nlh)
-               goto out_kfree_skb;
-       t = nlmsg_data(nlh);
-       t->tca_family = AF_UNSPEC;
-       t->tca__pad1 = 0;
-       t->tca__pad2 = 0;
-
-       nest = nla_nest_start(skb, TCA_ACT_TAB);
-       if (nest == NULL)
-               goto out_kfree_skb;
-
-       if (tcf_action_dump(skb, actions, 0, 0) < 0)
-               goto out_kfree_skb;
-
-       nla_nest_end(skb, nest);
-
-       nlh->nlmsg_len = skb_tail_pointer(skb) - b;
-       NETLINK_CB(skb).dst_group = RTNLGRP_TC;
+       if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, n->nlmsg_flags,
+                        RTM_NEWACTION, 0, 0) <= 0) {
+               kfree_skb(skb);
+               return -EINVAL;
+       }
 
-       err = rtnetlink_send(skb, net, portid, RTNLGRP_TC, flags & NLM_F_ECHO);
+       err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
+                            n->nlmsg_flags & NLM_F_ECHO);
        if (err > 0)
                err = 0;
        return err;
-
-out_kfree_skb:
-       kfree_skb(skb);
-       return -1;
 }
 
-
 static int
 tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
               u32 portid, int ovr)
 {
        int ret = 0;
        LIST_HEAD(actions);
-       u32 seq = n->nlmsg_seq;
 
        ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
        if (ret)
@@ -911,7 +896,7 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
        /* dump then free all the actions after update; inserted policy
         * stays intact
         */
-       ret = tcf_add_notify(net, &actions, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
+       ret = tcf_add_notify(net, n, &actions, portid);
        cleanup_a(&actions);
 done:
        return ret;
index 8b1d657..ee28e1c 100644 (file)
@@ -37,7 +37,6 @@
 #include <net/tc_act/tc_csum.h>
 
 #define CSUM_TAB_MASK 15
-static u32 csum_idx_gen;
 static struct tcf_hashinfo csum_hash_info;
 
 static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
@@ -67,7 +66,7 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
        pc = tcf_hash_check(parm->index, a, bind, &csum_hash_info);
        if (!pc) {
                pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
-                                    &csum_idx_gen, &csum_hash_info);
+                                    &csum_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
                ret = ACT_P_CREATED;
index af5641c..3133307 100644 (file)
 #include <net/tc_act/tc_gact.h>
 
 #define GACT_TAB_MASK  15
-static u32 gact_idx_gen;
 static struct tcf_hashinfo gact_hash_info;
 
 #ifdef CONFIG_GACT_PROB
 static int gact_net_rand(struct tcf_gact *gact)
 {
-       if (!gact->tcfg_pval || net_random() % gact->tcfg_pval)
+       if (!gact->tcfg_pval || prandom_u32() % gact->tcfg_pval)
                return gact->tcf_action;
        return gact->tcfg_paction;
 }
@@ -90,7 +89,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
        if (!pc) {
                pc = tcf_hash_create(parm->index, est, a, sizeof(*gact),
-                                    bind, &gact_idx_gen, &gact_hash_info);
+                                    bind, &gact_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
                ret = ACT_P_CREATED;
index 2426369..484bd19 100644 (file)
@@ -29,7 +29,6 @@
 
 
 #define IPT_TAB_MASK     15
-static u32 ipt_idx_gen;
 static struct tcf_hashinfo ipt_hash_info;
 
 static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook)
@@ -129,7 +128,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        pc = tcf_hash_check(index, a, bind, &ipt_hash_info);
        if (!pc) {
                pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
-                                    &ipt_idx_gen, &ipt_hash_info);
+                                    &ipt_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
                ret = ACT_P_CREATED;
index 9dbb8cd..5d05b57 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/if_arp.h>
 
 #define MIRRED_TAB_MASK     7
-static u32 mirred_idx_gen;
 static LIST_HEAD(mirred_list);
 static struct tcf_hashinfo mirred_hash_info;
 
@@ -107,7 +106,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                if (dev == NULL)
                        return -EINVAL;
                pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
-                                    &mirred_idx_gen, &mirred_hash_info);
+                                    &mirred_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
                ret = ACT_P_CREATED;
index 584e655..a49fa23 100644 (file)
@@ -30,7 +30,6 @@
 
 
 #define NAT_TAB_MASK   15
-static u32 nat_idx_gen;
 
 static struct tcf_hashinfo nat_hash_info;
 
@@ -61,7 +60,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info);
        if (!pc) {
                pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
-                                    &nat_idx_gen, &nat_hash_info);
+                                    &nat_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
                ret = ACT_P_CREATED;
index 7291893..f361e4e 100644 (file)
@@ -24,7 +24,6 @@
 #include <net/tc_act/tc_pedit.h>
 
 #define PEDIT_TAB_MASK 15
-static u32 pedit_idx_gen;
 
 static struct tcf_hashinfo pedit_hash_info;
 
@@ -63,7 +62,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
                if (!parm->nkeys)
                        return -EINVAL;
                pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
-                                    &pedit_idx_gen, &pedit_hash_info);
+                                    &pedit_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
                p = to_pedit(pc);
index 9295b86..a719fdf 100644 (file)
@@ -41,7 +41,6 @@ struct tcf_police {
        container_of(pc, struct tcf_police, common)
 
 #define POL_TAB_MASK     15
-static u32 police_idx_gen;
 static struct tcf_hashinfo police_hash_info;
 
 /* old policer structure from before tc actions */
@@ -251,7 +250,7 @@ override:
 
        police->tcfp_t_c = ktime_to_ns(ktime_get());
        police->tcf_index = parm->index ? parm->index :
-               tcf_hash_new_index(&police_idx_gen, &police_hash_info);
+               tcf_hash_new_index(&police_hash_info);
        h = tcf_hash(police->tcf_index, POL_TAB_MASK);
        spin_lock_bh(&police_hash_info.lock);
        hlist_add_head(&police->tcf_head, &police_hash_info.htab[h]);
index b44491e..f7d5406 100644 (file)
@@ -25,7 +25,6 @@
 #include <net/tc_act/tc_defact.h>
 
 #define SIMP_TAB_MASK     7
-static u32 simp_idx_gen;
 static struct tcf_hashinfo simp_hash_info;
 
 #define SIMP_MAX_DATA  32
@@ -118,7 +117,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
        pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info);
        if (!pc) {
                pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
-                                    &simp_idx_gen, &simp_hash_info);
+                                    &simp_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
 
index 0fa1aad..74af461 100644 (file)
@@ -28,7 +28,6 @@
 #include <net/tc_act/tc_skbedit.h>
 
 #define SKBEDIT_TAB_MASK     15
-static u32 skbedit_idx_gen;
 static struct tcf_hashinfo skbedit_hash_info;
 
 static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
@@ -104,7 +103,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
        pc = tcf_hash_check(parm->index, a, bind, &skbedit_hash_info);
        if (!pc) {
                pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
-                                    &skbedit_idx_gen, &skbedit_hash_info);
+                                    &skbedit_hash_info);
                if (IS_ERR(pc))
                        return PTR_ERR(pc);
 
index d8c42b1..29a30a1 100644 (file)
@@ -340,7 +340,7 @@ errout:
        return err;
 }
 
-static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
+static int tcf_fill_node(struct net *net, struct sk_buff *skb, struct tcf_proto *tp,
                         unsigned long fh, u32 portid, u32 seq, u16 flags, int event)
 {
        struct tcmsg *tcm;
@@ -362,7 +362,7 @@ static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
        tcm->tcm_handle = fh;
        if (RTM_DELTFILTER != event) {
                tcm->tcm_handle = 0;
-               if (tp->ops->dump && tp->ops->dump(tp, fh, skb, tcm) < 0)
+               if (tp->ops->dump && tp->ops->dump(net, tp, fh, skb, tcm) < 0)
                        goto nla_put_failure;
        }
        nlh->nlmsg_len = skb_tail_pointer(skb) - b;
@@ -385,7 +385,7 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
        if (!skb)
                return -ENOBUFS;
 
-       if (tcf_fill_node(skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) {
+       if (tcf_fill_node(net, skb, tp, fh, portid, n->nlmsg_seq, 0, event) <= 0) {
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -404,8 +404,9 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
                         struct tcf_walker *arg)
 {
        struct tcf_dump_args *a = (void *)arg;
+       struct net *net = sock_net(a->skb->sk);
 
-       return tcf_fill_node(a->skb, tp, n, NETLINK_CB(a->cb->skb).portid,
+       return tcf_fill_node(net, a->skb, tp, n, NETLINK_CB(a->cb->skb).portid,
                             a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER);
 }
 
@@ -463,7 +464,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
                if (t > s_t)
                        memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
                if (cb->args[1] == 0) {
-                       if (tcf_fill_node(skb, tp, 0, NETLINK_CB(cb->skb).portid,
+                       if (tcf_fill_node(net, skb, tp, 0, NETLINK_CB(cb->skb).portid,
                                          cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                          RTM_NEWTFILTER) <= 0)
                                break;
index b655203..e98ca99 100644 (file)
@@ -38,7 +38,7 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                          struct tcf_result *res)
 {
        int r;
-       struct basic_head *head = (struct basic_head *) tp->root;
+       struct basic_head *head = tp->root;
        struct basic_filter *f;
 
        list_for_each_entry(f, &head->flist, link) {
@@ -56,7 +56,7 @@ static int basic_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 static unsigned long basic_get(struct tcf_proto *tp, u32 handle)
 {
        unsigned long l = 0UL;
-       struct basic_head *head = (struct basic_head *) tp->root;
+       struct basic_head *head = tp->root;
        struct basic_filter *f;
 
        if (head == NULL)
@@ -107,7 +107,7 @@ static void basic_destroy(struct tcf_proto *tp)
 
 static int basic_delete(struct tcf_proto *tp, unsigned long arg)
 {
-       struct basic_head *head = (struct basic_head *) tp->root;
+       struct basic_head *head = tp->root;
        struct basic_filter *t, *f = (struct basic_filter *) arg;
 
        list_for_each_entry(t, &head->flist, link)
@@ -164,7 +164,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
                        struct nlattr **tca, unsigned long *arg)
 {
        int err;
-       struct basic_head *head = (struct basic_head *) tp->root;
+       struct basic_head *head = tp->root;
        struct nlattr *tb[TCA_BASIC_MAX + 1];
        struct basic_filter *f = (struct basic_filter *) *arg;
 
@@ -225,7 +225,7 @@ errout:
 
 static void basic_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 {
-       struct basic_head *head = (struct basic_head *) tp->root;
+       struct basic_head *head = tp->root;
        struct basic_filter *f;
 
        list_for_each_entry(f, &head->flist, link) {
@@ -241,7 +241,7 @@ skip:
        }
 }
 
-static int basic_dump(struct tcf_proto *tp, unsigned long fh,
+static int basic_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                      struct sk_buff *skb, struct tcmsg *t)
 {
        struct basic_filter *f = (struct basic_filter *) fh;
index 00a5a58..8e3cf49 100644 (file)
@@ -295,7 +295,7 @@ errout:
        return ret;
 }
 
-static int cls_bpf_dump(struct tcf_proto *tp, unsigned long fh,
+static int cls_bpf_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                        struct sk_buff *skb, struct tcmsg *tm)
 {
        struct cls_bpf_prog *prog = (struct cls_bpf_prog *) fh;
index 8349fcd..8e2158a 100644 (file)
@@ -164,7 +164,7 @@ skip:
        arg->count++;
 }
 
-static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh,
+static int cls_cgroup_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                           struct sk_buff *skb, struct tcmsg *t)
 {
        struct cls_cgroup_head *head = tp->root;
index dfd18a5..257029c 100644 (file)
@@ -563,7 +563,7 @@ static void flow_put(struct tcf_proto *tp, unsigned long f)
 {
 }
 
-static int flow_dump(struct tcf_proto *tp, unsigned long fh,
+static int flow_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                     struct sk_buff *skb, struct tcmsg *t)
 {
        struct flow_filter *f = (struct flow_filter *)fh;
index 3f9cece..ed00e8c 100644 (file)
@@ -41,7 +41,7 @@ struct fw_filter {
        u32                     id;
        struct tcf_result       res;
 #ifdef CONFIG_NET_CLS_IND
-       char                    indev[IFNAMSIZ];
+       int                     ifindex;
 #endif /* CONFIG_NET_CLS_IND */
        struct tcf_exts         exts;
 };
@@ -75,7 +75,7 @@ static inline int fw_hash(u32 handle)
 static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                          struct tcf_result *res)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        struct fw_filter *f;
        int r;
        u32 id = skb->mark;
@@ -86,7 +86,7 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                        if (f->id == id) {
                                *res = f->res;
 #ifdef CONFIG_NET_CLS_IND
-                               if (!tcf_match_indev(skb, f->indev))
+                               if (!tcf_match_indev(skb, f->ifindex))
                                        continue;
 #endif /* CONFIG_NET_CLS_IND */
                                r = tcf_exts_exec(skb, &f->exts, res);
@@ -111,7 +111,7 @@ static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 
 static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        struct fw_filter *f;
 
        if (head == NULL)
@@ -160,7 +160,7 @@ static void fw_destroy(struct tcf_proto *tp)
 
 static int fw_delete(struct tcf_proto *tp, unsigned long arg)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        struct fw_filter *f = (struct fw_filter *)arg;
        struct fw_filter **fp;
 
@@ -190,7 +190,7 @@ static int
 fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
        struct nlattr **tb, struct nlattr **tca, unsigned long base)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        struct tcf_exts e;
        u32 mask;
        int err;
@@ -207,9 +207,11 @@ fw_change_attrs(struct net *net, struct tcf_proto *tp, struct fw_filter *f,
 
 #ifdef CONFIG_NET_CLS_IND
        if (tb[TCA_FW_INDEV]) {
-               err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV]);
-               if (err < 0)
+               int ret;
+               ret = tcf_change_indev(net, tb[TCA_FW_INDEV]);
+               if (ret < 0)
                        goto errout;
+               f->ifindex = ret;
        }
 #endif /* CONFIG_NET_CLS_IND */
 
@@ -235,7 +237,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
                     struct nlattr **tca,
                     unsigned long *arg)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        struct fw_filter *f = (struct fw_filter *) *arg;
        struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_FW_MAX + 1];
@@ -298,7 +300,7 @@ errout:
 
 static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        int h;
 
        if (head == NULL)
@@ -324,10 +326,10 @@ static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
        }
 }
 
-static int fw_dump(struct tcf_proto *tp, unsigned long fh,
+static int fw_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                   struct sk_buff *skb, struct tcmsg *t)
 {
-       struct fw_head *head = (struct fw_head *)tp->root;
+       struct fw_head *head = tp->root;
        struct fw_filter *f = (struct fw_filter *)fh;
        unsigned char *b = skb_tail_pointer(skb);
        struct nlattr *nest;
@@ -348,9 +350,12 @@ static int fw_dump(struct tcf_proto *tp, unsigned long fh,
            nla_put_u32(skb, TCA_FW_CLASSID, f->res.classid))
                goto nla_put_failure;
 #ifdef CONFIG_NET_CLS_IND
-       if (strlen(f->indev) &&
-           nla_put_string(skb, TCA_FW_INDEV, f->indev))
-               goto nla_put_failure;
+       if (f->ifindex) {
+               struct net_device *dev;
+               dev = __dev_get_by_index(net, f->ifindex);
+               if (dev && nla_put_string(skb, TCA_FW_INDEV, dev->name))
+                       goto nla_put_failure;
+       }
 #endif /* CONFIG_NET_CLS_IND */
        if (head->mask != 0xFFFFFFFF &&
            nla_put_u32(skb, TCA_FW_MASK, head->mask))
index 2473953..1ad3068 100644 (file)
@@ -123,7 +123,7 @@ static inline int route4_hash_wild(void)
 static int route4_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                           struct tcf_result *res)
 {
-       struct route4_head *head = (struct route4_head *)tp->root;
+       struct route4_head *head = tp->root;
        struct dst_entry *dst;
        struct route4_bucket *b;
        struct route4_filter *f;
@@ -213,7 +213,7 @@ static inline u32 from_hash(u32 id)
 
 static unsigned long route4_get(struct tcf_proto *tp, u32 handle)
 {
-       struct route4_head *head = (struct route4_head *)tp->root;
+       struct route4_head *head = tp->root;
        struct route4_bucket *b;
        struct route4_filter *f;
        unsigned int h1, h2;
@@ -284,7 +284,7 @@ static void route4_destroy(struct tcf_proto *tp)
 
 static int route4_delete(struct tcf_proto *tp, unsigned long arg)
 {
-       struct route4_head *head = (struct route4_head *)tp->root;
+       struct route4_head *head = tp->root;
        struct route4_filter **fp, *f = (struct route4_filter *)arg;
        unsigned int h = 0;
        struct route4_bucket *b;
@@ -551,7 +551,7 @@ static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg)
        }
 }
 
-static int route4_dump(struct tcf_proto *tp, unsigned long fh,
+static int route4_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                       struct sk_buff *skb, struct tcmsg *t)
 {
        struct route4_filter *f = (struct route4_filter *)fh;
index 4f25c2a..19f8e5d 100644 (file)
@@ -594,7 +594,7 @@ static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg)
        }
 }
 
-static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
+static int rsvp_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                     struct sk_buff *skb, struct tcmsg *t)
 {
        struct rsvp_filter *f = (struct rsvp_filter *)fh;
index ffad187..eed8404 100644 (file)
@@ -24,9 +24,6 @@
 #define DEFAULT_HASH_SIZE      64      /* optimized for diffserv */
 
 
-#define        PRIV(tp)        ((struct tcindex_data *) (tp)->root)
-
-
 struct tcindex_filter_result {
        struct tcf_exts         exts;
        struct tcf_result       res;
@@ -77,7 +74,7 @@ tcindex_lookup(struct tcindex_data *p, u16 key)
 static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                            struct tcf_result *res)
 {
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcindex_filter_result *f;
        int key = (skb->tc_index & p->mask) >> p->shift;
 
@@ -102,7 +99,7 @@ static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp,
 
 static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle)
 {
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcindex_filter_result *r;
 
        pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle);
@@ -140,7 +137,7 @@ static int tcindex_init(struct tcf_proto *tp)
 static int
 __tcindex_delete(struct tcf_proto *tp, unsigned long arg, int lock)
 {
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
        struct tcindex_filter *f = NULL;
 
@@ -338,7 +335,7 @@ tcindex_change(struct net *net, struct sk_buff *in_skb,
 {
        struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_TCINDEX_MAX + 1];
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg;
        int err;
 
@@ -360,7 +357,7 @@ tcindex_change(struct net *net, struct sk_buff *in_skb,
 
 static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
 {
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcindex_filter *f, *next;
        int i;
 
@@ -407,7 +404,7 @@ static int tcindex_destroy_element(struct tcf_proto *tp,
 
 static void tcindex_destroy(struct tcf_proto *tp)
 {
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcf_walker walker;
 
        pr_debug("tcindex_destroy(tp %p),p %p\n", tp, p);
@@ -422,10 +419,10 @@ static void tcindex_destroy(struct tcf_proto *tp)
 }
 
 
-static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
+static int tcindex_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
     struct sk_buff *skb, struct tcmsg *t)
 {
-       struct tcindex_data *p = PRIV(tp);
+       struct tcindex_data *p = tp->root;
        struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh;
        unsigned char *b = skb_tail_pointer(skb);
        struct nlattr *nest;
index 20f2fb7..84c28da 100644 (file)
@@ -48,7 +48,7 @@ struct tc_u_knode {
        struct tc_u_hnode       *ht_up;
        struct tcf_exts         exts;
 #ifdef CONFIG_NET_CLS_IND
-       char                     indev[IFNAMSIZ];
+       int                     ifindex;
 #endif
        u8                      fshift;
        struct tcf_result       res;
@@ -95,7 +95,7 @@ static int u32_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct
                unsigned int      off;
        } stack[TC_U32_MAXDEPTH];
 
-       struct tc_u_hnode *ht = (struct tc_u_hnode *)tp->root;
+       struct tc_u_hnode *ht = tp->root;
        unsigned int off = skb_network_offset(skb);
        struct tc_u_knode *n;
        int sdepth = 0;
@@ -152,7 +152,7 @@ check_terminal:
 
                                *res = n->res;
 #ifdef CONFIG_NET_CLS_IND
-                               if (!tcf_match_indev(skb, n->indev)) {
+                               if (!tcf_match_indev(skb, n->ifindex)) {
                                        n = n->next;
                                        goto next_knode;
                                }
@@ -527,9 +527,11 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp,
 
 #ifdef CONFIG_NET_CLS_IND
        if (tb[TCA_U32_INDEV]) {
-               err = tcf_change_indev(tp, n->indev, tb[TCA_U32_INDEV]);
-               if (err < 0)
+               int ret;
+               ret = tcf_change_indev(net, tb[TCA_U32_INDEV]);
+               if (ret < 0)
                        goto errout;
+               n->ifindex = ret;
        }
 #endif
        tcf_exts_change(tp, &n->exts, &e);
@@ -712,7 +714,7 @@ static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg)
        }
 }
 
-static int u32_dump(struct tcf_proto *tp, unsigned long fh,
+static int u32_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                     struct sk_buff *skb, struct tcmsg *t)
 {
        struct tc_u_knode *n = (struct tc_u_knode *)fh;
@@ -760,9 +762,12 @@ static int u32_dump(struct tcf_proto *tp, unsigned long fh,
                        goto nla_put_failure;
 
 #ifdef CONFIG_NET_CLS_IND
-               if (strlen(n->indev) &&
-                   nla_put_string(skb, TCA_U32_INDEV, n->indev))
-                       goto nla_put_failure;
+               if (n->ifindex) {
+                       struct net_device *dev;
+                       dev = __dev_get_by_index(net, n->ifindex);
+                       if (dev && nla_put_string(skb, TCA_U32_INDEV, dev->name))
+                               goto nla_put_failure;
+               }
 #endif
 #ifdef CONFIG_CLS_U32_PERF
                if (nla_put(skb, TCA_U32_PCNT,
index 5578628..ba5bc92 100644 (file)
@@ -390,7 +390,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt)
        sch->limit = 10*1024;
        q->flows_cnt = 1024;
        q->quantum = psched_mtu(qdisc_dev(sch));
-       q->perturbation = net_random();
+       q->perturbation = prandom_u32();
        INIT_LIST_HEAD(&q->new_flows);
        INIT_LIST_HEAD(&q->old_flows);
        codel_params_init(&q->cparams);
index 32bb942..e82e43b 100644 (file)
@@ -126,7 +126,7 @@ int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
        if (!netif_xmit_frozen_or_stopped(txq))
-               ret = dev_hard_start_xmit(skb, dev, txq, NULL);
+               ret = dev_hard_start_xmit(skb, dev, txq);
 
        HARD_TX_UNLOCK(dev, txq);
 
index cf7f614..647680b 100644 (file)
@@ -574,18 +574,18 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt)
                q->hh_flows_limit = nla_get_u32(tb[TCA_HHF_HH_FLOWS_LIMIT]);
 
        if (tb[TCA_HHF_RESET_TIMEOUT]) {
-               u32 ms = nla_get_u32(tb[TCA_HHF_RESET_TIMEOUT]);
+               u32 us = nla_get_u32(tb[TCA_HHF_RESET_TIMEOUT]);
 
-               q->hhf_reset_timeout = msecs_to_jiffies(ms);
+               q->hhf_reset_timeout = usecs_to_jiffies(us);
        }
 
        if (tb[TCA_HHF_ADMIT_BYTES])
                q->hhf_admit_bytes = nla_get_u32(tb[TCA_HHF_ADMIT_BYTES]);
 
        if (tb[TCA_HHF_EVICT_TIMEOUT]) {
-               u32 ms = nla_get_u32(tb[TCA_HHF_EVICT_TIMEOUT]);
+               u32 us = nla_get_u32(tb[TCA_HHF_EVICT_TIMEOUT]);
 
-               q->hhf_evict_timeout = msecs_to_jiffies(ms);
+               q->hhf_evict_timeout = usecs_to_jiffies(us);
        }
 
        qlen = sch->q.qlen;
@@ -607,7 +607,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt)
 
        sch->limit = 1000;
        q->quantum = psched_mtu(qdisc_dev(sch));
-       q->perturbation = net_random();
+       q->perturbation = prandom_u32();
        INIT_LIST_HEAD(&q->new_buckets);
        INIT_LIST_HEAD(&q->old_buckets);
 
@@ -684,10 +684,10 @@ static int hhf_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u32(skb, TCA_HHF_QUANTUM, q->quantum) ||
            nla_put_u32(skb, TCA_HHF_HH_FLOWS_LIMIT, q->hh_flows_limit) ||
            nla_put_u32(skb, TCA_HHF_RESET_TIMEOUT,
-                       jiffies_to_msecs(q->hhf_reset_timeout)) ||
+                       jiffies_to_usecs(q->hhf_reset_timeout)) ||
            nla_put_u32(skb, TCA_HHF_ADMIT_BYTES, q->hhf_admit_bytes) ||
            nla_put_u32(skb, TCA_HHF_EVICT_TIMEOUT,
-                       jiffies_to_msecs(q->hhf_evict_timeout)) ||
+                       jiffies_to_usecs(q->hhf_evict_timeout)) ||
            nla_put_u32(skb, TCA_HHF_NON_HH_WEIGHT, q->hhf_non_hh_weight))
                goto nla_put_failure;
 
index 090a4e3..3019c10 100644 (file)
@@ -169,7 +169,7 @@ static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
 static void init_crandom(struct crndstate *state, unsigned long rho)
 {
        state->rho = rho;
-       state->last = net_random();
+       state->last = prandom_u32();
 }
 
 /* get_crandom - correlated random number generator
@@ -182,9 +182,9 @@ static u32 get_crandom(struct crndstate *state)
        unsigned long answer;
 
        if (state->rho == 0)    /* no correlation */
-               return net_random();
+               return prandom_u32();
 
-       value = net_random();
+       value = prandom_u32();
        rho = (u64)state->rho + 1;
        answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
        state->last = answer;
@@ -198,7 +198,7 @@ static u32 get_crandom(struct crndstate *state)
 static bool loss_4state(struct netem_sched_data *q)
 {
        struct clgstate *clg = &q->clg;
-       u32 rnd = net_random();
+       u32 rnd = prandom_u32();
 
        /*
         * Makes a comparison between rnd and the transition
@@ -264,15 +264,15 @@ static bool loss_gilb_ell(struct netem_sched_data *q)
 
        switch (clg->state) {
        case 1:
-               if (net_random() < clg->a1)
+               if (prandom_u32() < clg->a1)
                        clg->state = 2;
-               if (net_random() < clg->a4)
+               if (prandom_u32() < clg->a4)
                        return true;
                break;
        case 2:
-               if (net_random() < clg->a2)
+               if (prandom_u32() < clg->a2)
                        clg->state = 1;
-               if (net_random() > clg->a3)
+               if (prandom_u32() > clg->a3)
                        return true;
        }
 
@@ -457,7 +457,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                     skb_checksum_help(skb)))
                        return qdisc_drop(skb, sch);
 
-               skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
+               skb->data[prandom_u32() % skb_headlen(skb)] ^=
+                       1<<(prandom_u32() % 8);
        }
 
        if (unlikely(skb_queue_len(&sch->q) >= sch->limit))
index fe65340..a255d02 100644 (file)
@@ -122,7 +122,7 @@ static bool drop_early(struct Qdisc *sch, u32 packet_size)
        else
                local_prob = q->vars.prob;
 
-       rnd = net_random();
+       rnd = prandom_u32();
        if (rnd < local_prob)
                return true;
 
index 30ea467..9b0f709 100644 (file)
@@ -220,7 +220,7 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_da
 
 static void sfb_init_perturbation(u32 slot, struct sfb_sched_data *q)
 {
-       q->bins[slot].perturbation = net_random();
+       q->bins[slot].perturbation = prandom_u32();
 }
 
 static void sfb_swap_slot(struct sfb_sched_data *q)
@@ -381,7 +381,7 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                goto enqueue;
        }
 
-       r = net_random() & SFB_MAX_PROB;
+       r = prandom_u32() & SFB_MAX_PROB;
 
        if (unlikely(r < p_min)) {
                if (unlikely(p_min > SFB_MAX_PROB / 2)) {
index 76f01e0..87317ff 100644 (file)
@@ -629,7 +629,7 @@ static void sfq_perturbation(unsigned long arg)
        spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
 
        spin_lock(root_lock);
-       q->perturbation = net_random();
+       q->perturbation = prandom_u32();
        if (!q->filter_list && q->tail)
                sfq_rehash(sch);
        spin_unlock(root_lock);
@@ -698,7 +698,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
        del_timer(&q->perturb_timer);
        if (q->perturb_period) {
                mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
-               q->perturbation = net_random();
+               q->perturbation = prandom_u32();
        }
        sch_tree_unlock(sch);
        kfree(p);
@@ -759,7 +759,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
        q->quantum = psched_mtu(qdisc_dev(sch));
        q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
        q->perturb_period = 0;
-       q->perturbation = net_random();
+       q->perturbation = prandom_u32();
 
        if (opt) {
                int err = sfq_change(sch, opt);
index 34b7726..7c16108 100644 (file)
@@ -1030,6 +1030,7 @@ static const struct net_protocol sctp_protocol = {
        .err_handler = sctp_v4_err,
        .no_policy   = 1,
        .netns_ok    = 1,
+       .icmp_strict_tag_validation = 1,
 };
 
 /* IPv4 address related functions.  */
index e5f7cdb..632090b 100644 (file)
@@ -78,6 +78,8 @@ static int sctp_process_param(struct sctp_association *asoc,
                              gfp_t gfp);
 static void *sctp_addto_param(struct sctp_chunk *chunk, int len,
                              const void *data);
+static void  *sctp_addto_chunk_fixed(struct sctp_chunk *, int len,
+                                    const void *data);
 
 /* Control chunk destructor */
 static void sctp_control_release_owner(struct sk_buff *skb)
@@ -1475,8 +1477,8 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
 /* Append bytes to the end of a chunk. Returns NULL if there isn't sufficient
  * space in the chunk
  */
-void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
-                            int len, const void *data)
+static void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
+                                   int len, const void *data)
 {
        if (skb_tailroom(chunk->skb) >= len)
                return sctp_addto_chunk(chunk, len, data);
index d32dae7..fd7337a 100644 (file)
@@ -1743,7 +1743,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                 * either the default or the user specified stream counts.
                 */
                if (sinfo) {
-                       if (!sinit || (sinit && !sinit->sinit_num_ostreams)) {
+                       if (!sinit || !sinit->sinit_num_ostreams) {
                                /* Check against the defaults. */
                                if (sinfo->sinfo_stream >=
                                    sp->initmsg.sinit_num_ostreams) {
@@ -2527,6 +2527,16 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
        return 0;
 }
 
+static inline __u32 sctp_spp_sackdelay_enable(__u32 param_flags)
+{
+       return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_ENABLE;
+}
+
+static inline __u32 sctp_spp_sackdelay_disable(__u32 param_flags)
+{
+       return (param_flags & ~SPP_SACKDELAY) | SPP_SACKDELAY_DISABLE;
+}
+
 /*
  * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
  *
@@ -2610,37 +2620,31 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
                        asoc->sackdelay =
                                msecs_to_jiffies(params.sack_delay);
                        asoc->param_flags =
-                               (asoc->param_flags & ~SPP_SACKDELAY) |
-                               SPP_SACKDELAY_ENABLE;
+                               sctp_spp_sackdelay_enable(asoc->param_flags);
                } else {
                        sp->sackdelay = params.sack_delay;
                        sp->param_flags =
-                               (sp->param_flags & ~SPP_SACKDELAY) |
-                               SPP_SACKDELAY_ENABLE;
+                               sctp_spp_sackdelay_enable(sp->param_flags);
                }
        }
 
        if (params.sack_freq == 1) {
                if (asoc) {
                        asoc->param_flags =
-                               (asoc->param_flags & ~SPP_SACKDELAY) |
-                               SPP_SACKDELAY_DISABLE;
+                               sctp_spp_sackdelay_disable(asoc->param_flags);
                } else {
                        sp->param_flags =
-                               (sp->param_flags & ~SPP_SACKDELAY) |
-                               SPP_SACKDELAY_DISABLE;
+                               sctp_spp_sackdelay_disable(sp->param_flags);
                }
        } else if (params.sack_freq > 1) {
                if (asoc) {
                        asoc->sackfreq = params.sack_freq;
                        asoc->param_flags =
-                               (asoc->param_flags & ~SPP_SACKDELAY) |
-                               SPP_SACKDELAY_ENABLE;
+                               sctp_spp_sackdelay_enable(asoc->param_flags);
                } else {
                        sp->sackfreq = params.sack_freq;
                        sp->param_flags =
-                               (sp->param_flags & ~SPP_SACKDELAY) |
-                               SPP_SACKDELAY_ENABLE;
+                               sctp_spp_sackdelay_enable(sp->param_flags);
                }
        }
 
@@ -2652,18 +2656,15 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
                                trans->sackdelay =
                                        msecs_to_jiffies(params.sack_delay);
                                trans->param_flags =
-                                       (trans->param_flags & ~SPP_SACKDELAY) |
-                                       SPP_SACKDELAY_ENABLE;
+                                       sctp_spp_sackdelay_enable(trans->param_flags);
                        }
                        if (params.sack_freq == 1) {
                                trans->param_flags =
-                                       (trans->param_flags & ~SPP_SACKDELAY) |
-                                       SPP_SACKDELAY_DISABLE;
+                                       sctp_spp_sackdelay_disable(trans->param_flags);
                        } else if (params.sack_freq > 1) {
                                trans->sackfreq = params.sack_freq;
                                trans->param_flags =
-                                       (trans->param_flags & ~SPP_SACKDELAY) |
-                                       SPP_SACKDELAY_ENABLE;
+                                       sctp_spp_sackdelay_enable(trans->param_flags);
                        }
                }
        }
@@ -5926,7 +5927,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 
                inet_get_local_port_range(sock_net(sk), &low, &high);
                remaining = (high - low) + 1;
-               rover = net_random() % remaining + low;
+               rover = prandom_u32() % remaining + low;
 
                do {
                        rover++;
index a72de07..e521d20 100644 (file)
@@ -619,7 +619,7 @@ static void cache_limit_defers(void)
 
        /* Consider removing either the first or the last */
        if (cache_defer_cnt > DFR_MAX) {
-               if (net_random() & 1)
+               if (prandom_u32() & 1)
                        discard = list_entry(cache_defer_list.next,
                                             struct cache_deferred_req, recent);
                else
index 04199bc..1750048 100644 (file)
@@ -1188,7 +1188,7 @@ static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
 
 static inline void xprt_init_xid(struct rpc_xprt *xprt)
 {
-       xprt->xid = net_random();
+       xprt->xid = prandom_u32();
 }
 
 static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
index dd9d295..75b045e 100644 (file)
@@ -1674,7 +1674,7 @@ static void xs_udp_timer(struct rpc_xprt *xprt, struct rpc_task *task)
 static unsigned short xs_get_random_port(void)
 {
        unsigned short range = xprt_max_resvport - xprt_min_resvport;
-       unsigned short rand = (unsigned short) net_random() % range;
+       unsigned short rand = (unsigned short) prandom_u32() % range;
        return rand + xprt_min_resvport;
 }
 
index 2d456ab..a38c899 100644 (file)
@@ -473,7 +473,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
 /**
  * tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface
  * @buf: the packet to be sent
- * @b_ptr: the bearer throught which the packet is to be sent
+ * @b_ptr: the bearer through which the packet is to be sent
  * @dest: peer destination address
  */
 int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
index 471973f..d4b5de4 100644 (file)
@@ -1438,6 +1438,7 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                int type;
 
                head = head->next;
+               buf->next = NULL;
 
                /* Ensure bearer is still enabled */
                if (unlikely(!b_ptr->active))
index fd3fa57..b635ca3 100644 (file)
@@ -55,7 +55,7 @@
  * @usr_data: user-specified field
  * @rx_action: what to do when connection socket is active
  * @outqueue: pointer to first outbound message in queue
- * @outqueue_lock: controll access to the outqueue
+ * @outqueue_lock: control access to the outqueue
  * @outqueue: list of connection objects for its server
  * @swork: send work item
  */
index d38bb45..7cb0bd5 100644 (file)
@@ -42,7 +42,7 @@
 /**
  * struct tipc_subscriber - TIPC network topology subscriber
  * @conid: connection identifier to server connecting to subscriber
- * @lock: controll access to subscriber
+ * @lock: control access to subscriber
  * @subscription_list: list of subscription objects for this subscriber
  */
 struct tipc_subscriber {
index 324e8d8..11ee4ed 100644 (file)
@@ -29,6 +29,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
                wdev->beacon_interval = 0;
                wdev->channel = NULL;
                wdev->ssid_len = 0;
+               rdev_set_qos_map(rdev, dev, NULL);
        }
 
        return err;
index 730147e..f911c5f 100644 (file)
@@ -183,6 +183,8 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
        kfree(wdev->connect_keys);
        wdev->connect_keys = NULL;
 
+       rdev_set_qos_map(rdev, dev, NULL);
+
        /*
         * Delete all the keys ... pairwise keys can't really
         * exist any more anyway, but default keys might.
index 9c7a11a..8858624 100644 (file)
@@ -277,6 +277,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
        if (!err) {
                wdev->mesh_id_len = 0;
                wdev->channel = NULL;
+               rdev_set_qos_map(rdev, dev, NULL);
        }
 
        return err;
index 04681a4..4fa555e 100644 (file)
@@ -53,6 +53,7 @@ enum nl80211_multicast_groups {
        NL80211_MCGRP_SCAN,
        NL80211_MCGRP_REGULATORY,
        NL80211_MCGRP_MLME,
+       NL80211_MCGRP_VENDOR,
        NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
 };
 
@@ -61,6 +62,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
        [NL80211_MCGRP_SCAN] = { .name = "scan", },
        [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
        [NL80211_MCGRP_MLME] = { .name = "mlme", },
+       [NL80211_MCGRP_VENDOR] = { .name = "vendor", },
 #ifdef CONFIG_NL80211_TESTMODE
        [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
 #endif
@@ -163,7 +165,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
 
        if (attrs[NL80211_ATTR_IFINDEX]) {
                int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
-               netdev = dev_get_by_index(netns, ifindex);
+               netdev = __dev_get_by_index(netns, ifindex);
                if (netdev) {
                        if (netdev->ieee80211_ptr)
                                tmp = wiphy_to_dev(
@@ -171,8 +173,6 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
                        else
                                tmp = NULL;
 
-                       dev_put(netdev);
-
                        /* not wireless device -- return error */
                        if (!tmp)
                                return ERR_PTR(-EINVAL);
@@ -380,6 +380,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
        [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
        [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
+       [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
+                                  .len = IEEE80211_QOS_MAP_LEN_MAX },
 };
 
 /* policy for the key attributes */
@@ -1188,7 +1190,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
        struct nlattr *nl_bands, *nl_band;
        struct nlattr *nl_freqs, *nl_freq;
        struct nlattr *nl_cmds;
-       struct nlattr *nl_vendor_cmds;
        enum ieee80211_band band;
        struct ieee80211_channel *chan;
        int i;
@@ -1455,6 +1456,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
                                CMD(channel_switch, CHANNEL_SWITCH);
                }
+               CMD(set_qos_map, SET_QOS_MAP);
 
 #ifdef CONFIG_NL80211_TESTMODE
                CMD(testmode_cmd, TESTMODE);
@@ -1587,16 +1589,38 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                state->split_start++;
                break;
        case 11:
-               nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
-               if (!nl_vendor_cmds)
-                       goto nla_put_failure;
+               if (dev->wiphy.n_vendor_commands) {
+                       const struct nl80211_vendor_cmd_info *info;
+                       struct nlattr *nested;
 
-               for (i = 0; i < dev->wiphy.n_vendor_commands; i++)
-                       if (nla_put(msg, i + 1,
-                                   sizeof(struct nl80211_vendor_cmd_info),
-                                   &dev->wiphy.vendor_commands[i].info))
+                       nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+                       if (!nested)
                                goto nla_put_failure;
-               nla_nest_end(msg, nl_vendor_cmds);
+
+                       for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
+                               info = &dev->wiphy.vendor_commands[i].info;
+                               if (nla_put(msg, i + 1, sizeof(*info), info))
+                                       goto nla_put_failure;
+                       }
+                       nla_nest_end(msg, nested);
+               }
+
+               if (dev->wiphy.n_vendor_events) {
+                       const struct nl80211_vendor_cmd_info *info;
+                       struct nlattr *nested;
+
+                       nested = nla_nest_start(msg,
+                                               NL80211_ATTR_VENDOR_EVENTS);
+                       if (!nested)
+                               goto nla_put_failure;
+
+                       for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
+                               info = &dev->wiphy.vendor_events[i];
+                               if (nla_put(msg, i + 1, sizeof(*info), info))
+                                       goto nla_put_failure;
+                       }
+                       nla_nest_end(msg, nested);
+               }
 
                /* done */
                state->split_start = 0;
@@ -1630,7 +1654,7 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
                struct cfg80211_registered_device *rdev;
                int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
-               netdev = dev_get_by_index(sock_net(skb->sk), ifidx);
+               netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
                if (!netdev)
                        return -ENODEV;
                if (netdev->ieee80211_ptr) {
@@ -1638,7 +1662,6 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
                                netdev->ieee80211_ptr->wiphy);
                        state->filter_wiphy = rdev->wiphy_idx;
                }
-               dev_put(netdev);
        }
 
        return 0;
@@ -1961,7 +1984,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_IFINDEX]) {
                int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
 
-               netdev = dev_get_by_index(genl_info_net(info), ifindex);
+               netdev = __dev_get_by_index(genl_info_net(info), ifindex);
                if (netdev && netdev->ieee80211_ptr)
                        rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
                else
@@ -1989,32 +2012,24 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
 
        if (result)
-               goto bad_res;
+               return result;
 
        if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
                struct ieee80211_txq_params txq_params;
                struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1];
 
-               if (!rdev->ops->set_txq_params) {
-                       result = -EOPNOTSUPP;
-                       goto bad_res;
-               }
+               if (!rdev->ops->set_txq_params)
+                       return -EOPNOTSUPP;
 
-               if (!netdev) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+               if (!netdev)
+                       return -EINVAL;
 
                if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-                   netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+                   netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+                       return -EINVAL;
 
-               if (!netif_running(netdev)) {
-                       result = -ENETDOWN;
-                       goto bad_res;
-               }
+               if (!netif_running(netdev))
+                       return -ENETDOWN;
 
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
@@ -2025,12 +2040,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                                  txq_params_policy);
                        result = parse_txq_params(tb, &txq_params);
                        if (result)
-                               goto bad_res;
+                               return result;
 
                        result = rdev_set_txq_params(rdev, netdev,
                                                     &txq_params);
                        if (result)
-                               goto bad_res;
+                               return result;
                }
        }
 
@@ -2039,7 +2054,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                                nl80211_can_set_dev_channel(wdev) ? wdev : NULL,
                                info);
                if (result)
-                       goto bad_res;
+                       return result;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
@@ -2050,19 +2065,15 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
                        txp_wdev = NULL;
 
-               if (!rdev->ops->set_tx_power) {
-                       result = -EOPNOTSUPP;
-                       goto bad_res;
-               }
+               if (!rdev->ops->set_tx_power)
+                       return -EOPNOTSUPP;
 
                idx = NL80211_ATTR_WIPHY_TX_POWER_SETTING;
                type = nla_get_u32(info->attrs[idx]);
 
                if (!info->attrs[NL80211_ATTR_WIPHY_TX_POWER_LEVEL] &&
-                   (type != NL80211_TX_POWER_AUTOMATIC)) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+                   (type != NL80211_TX_POWER_AUTOMATIC))
+                       return -EINVAL;
 
                if (type != NL80211_TX_POWER_AUTOMATIC) {
                        idx = NL80211_ATTR_WIPHY_TX_POWER_LEVEL;
@@ -2071,7 +2082,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
                result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
                if (result)
-                       goto bad_res;
+                       return result;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] &&
@@ -2079,10 +2090,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                u32 tx_ant, rx_ant;
                if ((!rdev->wiphy.available_antennas_tx &&
                     !rdev->wiphy.available_antennas_rx) ||
-                   !rdev->ops->set_antenna) {
-                       result = -EOPNOTSUPP;
-                       goto bad_res;
-               }
+                   !rdev->ops->set_antenna)
+                       return -EOPNOTSUPP;
 
                tx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX]);
                rx_ant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]);
@@ -2090,17 +2099,15 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                /* reject antenna configurations which don't match the
                 * available antenna masks, except for the "all" mask */
                if ((~tx_ant && (tx_ant & ~rdev->wiphy.available_antennas_tx)) ||
-                   (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx))) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+                   (~rx_ant && (rx_ant & ~rdev->wiphy.available_antennas_rx)))
+                       return -EINVAL;
 
                tx_ant = tx_ant & rdev->wiphy.available_antennas_tx;
                rx_ant = rx_ant & rdev->wiphy.available_antennas_rx;
 
                result = rdev_set_antenna(rdev, tx_ant, rx_ant);
                if (result)
-                       goto bad_res;
+                       return result;
        }
 
        changed = 0;
@@ -2108,30 +2115,27 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) {
                retry_short = nla_get_u8(
                        info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]);
-               if (retry_short == 0) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+               if (retry_short == 0)
+                       return -EINVAL;
+
                changed |= WIPHY_PARAM_RETRY_SHORT;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) {
                retry_long = nla_get_u8(
                        info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]);
-               if (retry_long == 0) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+               if (retry_long == 0)
+                       return -EINVAL;
+
                changed |= WIPHY_PARAM_RETRY_LONG;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) {
                frag_threshold = nla_get_u32(
                        info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]);
-               if (frag_threshold < 256) {
-                       result = -EINVAL;
-                       goto bad_res;
-               }
+               if (frag_threshold < 256)
+                       return -EINVAL;
+
                if (frag_threshold != (u32) -1) {
                        /*
                         * Fragments (apart from the last one) are required to
@@ -2161,10 +2165,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                u32 old_frag_threshold, old_rts_threshold;
                u8 old_coverage_class;
 
-               if (!rdev->ops->set_wiphy_params) {
-                       result = -EOPNOTSUPP;
-                       goto bad_res;
-               }
+               if (!rdev->ops->set_wiphy_params)
+                       return -EOPNOTSUPP;
 
                old_retry_short = rdev->wiphy.retry_short;
                old_retry_long = rdev->wiphy.retry_long;
@@ -2192,11 +2194,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        rdev->wiphy.coverage_class = old_coverage_class;
                }
        }
-
- bad_res:
-       if (netdev)
-               dev_put(netdev);
-       return result;
+       return 0;
 }
 
 static inline u64 wdev_id(struct wireless_dev *wdev)
@@ -6726,7 +6724,9 @@ static struct sk_buff *
 __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
                            int approxlen, u32 portid, u32 seq,
                            enum nl80211_commands cmd,
-                           enum nl80211_attrs attr, gfp_t gfp)
+                           enum nl80211_attrs attr,
+                           const struct nl80211_vendor_cmd_info *info,
+                           gfp_t gfp)
 {
        struct sk_buff *skb;
        void *hdr;
@@ -6744,6 +6744,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
 
        if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
                goto nla_put_failure;
+
+       if (info) {
+               if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
+                               info->vendor_id))
+                       goto nla_put_failure;
+               if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
+                               info->subcmd))
+                       goto nla_put_failure;
+       }
+
        data = nla_nest_start(skb, attr);
 
        ((void **)skb->cb)[0] = rdev;
@@ -6884,29 +6894,54 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
        return err;
 }
 
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
-                                                 int approxlen, gfp_t gfp)
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int vendor_event_idx,
+                                          int approxlen, gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       const struct nl80211_vendor_cmd_info *info;
+
+       switch (cmd) {
+       case NL80211_CMD_TESTMODE:
+               if (WARN_ON(vendor_event_idx != -1))
+                       return NULL;
+               info = NULL;
+               break;
+       case NL80211_CMD_VENDOR:
+               if (WARN_ON(vendor_event_idx < 0 ||
+                           vendor_event_idx >= wiphy->n_vendor_events))
+                       return NULL;
+               info = &wiphy->vendor_events[vendor_event_idx];
+               break;
+       default:
+               WARN_ON(1);
+               return NULL;
+       }
 
        return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
-                                          NL80211_CMD_TESTMODE,
-                                          NL80211_ATTR_TESTDATA, gfp);
+                                          cmd, attr, info, gfp);
 }
-EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
+EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
 
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
        void *hdr = ((void **)skb->cb)[1];
        struct nlattr *data = ((void **)skb->cb)[2];
+       enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
 
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
+
+       if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
+               mcgrp = NL80211_MCGRP_VENDOR;
+
        genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
-                               NL80211_MCGRP_TESTMODE, gfp);
+                               mcgrp, gfp);
 }
-EXPORT_SYMBOL(cfg80211_testmode_event);
+EXPORT_SYMBOL(__cfg80211_send_event_skb);
 #endif
 
 static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
@@ -9039,7 +9074,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
        return __cfg80211_alloc_vendor_skb(rdev, approxlen,
                                           rdev->cur_cmd_info->snd_portid,
                                           rdev->cur_cmd_info->snd_seq,
-                                          cmd, attr, GFP_KERNEL);
+                                          cmd, attr, NULL, GFP_KERNEL);
 }
 EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
 
@@ -9061,6 +9096,57 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
 EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
 
 
+static int nl80211_set_qos_map(struct sk_buff *skb,
+                              struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct cfg80211_qos_map *qos_map = NULL;
+       struct net_device *dev = info->user_ptr[1];
+       u8 *pos, len, num_des, des_len, des;
+       int ret;
+
+       if (!rdev->ops->set_qos_map)
+               return -EOPNOTSUPP;
+
+       if (info->attrs[NL80211_ATTR_QOS_MAP]) {
+               pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
+               len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
+
+               if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
+                   len > IEEE80211_QOS_MAP_LEN_MAX)
+                       return -EINVAL;
+
+               qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
+               if (!qos_map)
+                       return -ENOMEM;
+
+               num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
+               if (num_des) {
+                       des_len = num_des *
+                               sizeof(struct cfg80211_dscp_exception);
+                       memcpy(qos_map->dscp_exception, pos, des_len);
+                       qos_map->num_des = num_des;
+                       for (des = 0; des < num_des; des++) {
+                               if (qos_map->dscp_exception[des].up > 7) {
+                                       kfree(qos_map);
+                                       return -EINVAL;
+                               }
+                       }
+                       pos += des_len;
+               }
+               memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
+       }
+
+       wdev_lock(dev->ieee80211_ptr);
+       ret = nl80211_key_allowed(dev->ieee80211_ptr);
+       if (!ret)
+               ret = rdev_set_qos_map(rdev, dev, qos_map);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       kfree(qos_map);
+       return ret;
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -9793,6 +9879,14 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_SET_QOS_MAP,
+               .doit = nl80211_set_qos_map,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 /* notification functions */
index a6c03ab..c8e2259 100644 (file)
@@ -932,4 +932,19 @@ static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
+                                  struct net_device *dev,
+                                  struct cfg80211_qos_map *qos_map)
+{
+       int ret = -EOPNOTSUPP;
+
+       if (rdev->ops->set_qos_map) {
+               trace_rdev_set_qos_map(&rdev->wiphy, dev, qos_map);
+               ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map);
+               trace_rdev_return_int(&rdev->wiphy, ret);
+       }
+
+       return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
index d3c5bd7..5d6e7bb 100644 (file)
@@ -872,6 +872,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                for (i = 0; i < 6; i++)
                        rdev_del_key(rdev, dev, i, false, NULL);
 
+       rdev_set_qos_map(rdev, dev, NULL);
+
 #ifdef CONFIG_CFG80211_WEXT
        memset(&wrqu, 0, sizeof(wrqu));
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
index f7aa7a7..fbcc23e 100644 (file)
 
 #define BOOL_TO_STR(bo) (bo) ? "true" : "false"
 
+#define QOS_MAP_ENTRY __field(u8, num_des)                     \
+                     __array(u8, dscp_exception,               \
+                             2 * IEEE80211_QOS_MAP_MAX_EX)     \
+                     __array(u8, up, IEEE80211_QOS_MAP_LEN_MIN)
+#define QOS_MAP_ASSIGN(qos_map)                                        \
+       do {                                                    \
+               if ((qos_map)) {                                \
+                       __entry->num_des = (qos_map)->num_des;  \
+                       memcpy(__entry->dscp_exception,         \
+                              &(qos_map)->dscp_exception,      \
+                              2 * IEEE80211_QOS_MAP_MAX_EX);   \
+                       memcpy(__entry->up, &(qos_map)->up,     \
+                              IEEE80211_QOS_MAP_LEN_MIN);      \
+               } else {                                        \
+                       __entry->num_des = 0;                   \
+                       memset(__entry->dscp_exception, 0,      \
+                              2 * IEEE80211_QOS_MAP_MAX_EX);   \
+                       memset(__entry->up, 0,                  \
+                              IEEE80211_QOS_MAP_LEN_MIN);      \
+               }                                               \
+       } while (0)
+
 /*************************************************************
  *                     rdev->ops traces                     *
  *************************************************************/
@@ -1875,6 +1897,24 @@ TRACE_EVENT(rdev_channel_switch,
                  __entry->counter_offset_presp)
 );
 
+TRACE_EVENT(rdev_set_qos_map,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_qos_map *qos_map),
+       TP_ARGS(wiphy, netdev, qos_map),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               QOS_MAP_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               QOS_MAP_ASSIGN(qos_map);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", num_des: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des)
+);
+
 /*************************************************************
  *          cfg80211 exported functions traces              *
  *************************************************************/
index 935dea9..5618888 100644 (file)
@@ -689,7 +689,8 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 
 /* Given a data frame determine the 802.1p/1d tag to use. */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb)
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+                                   struct cfg80211_qos_map *qos_map)
 {
        unsigned int dscp;
        unsigned char vlan_priority;
@@ -720,6 +721,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
                return 0;
        }
 
+       if (qos_map) {
+               unsigned int i, tmp_dscp = dscp >> 2;
+
+               for (i = 0; i < qos_map->num_des; i++) {
+                       if (tmp_dscp == qos_map->dscp_exception[i].dscp)
+                               return qos_map->dscp_exception[i].up;
+               }
+
+               for (i = 0; i < 8; i++) {
+                       if (tmp_dscp >= qos_map->up[i].low &&
+                           tmp_dscp <= qos_map->up[i].high)
+                               return i;
+               }
+       }
+
        return dscp >> 5;
 }
 EXPORT_SYMBOL(cfg80211_classify8021d);
@@ -863,6 +879,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
                dev->ieee80211_ptr->use_4addr = false;
                dev->ieee80211_ptr->mesh_id_up_len = 0;
+               rdev_set_qos_map(rdev, dev, NULL);
 
                switch (otype) {
                case NL80211_IFTYPE_AP:
index 8884399..6c7ac01 100644 (file)
@@ -67,7 +67,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
        case IPPROTO_COMP:
                if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
                        return -EINVAL;
-               *spi = htonl(ntohs(*(__be16*)(skb_transport_header(skb) + 2)));
+               *spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2)));
                *seq = 0;
                return 0;
        default:
@@ -77,8 +77,8 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
        if (!pskb_may_pull(skb, hlen))
                return -EINVAL;
 
-       *spi = *(__be32*)(skb_transport_header(skb) + offset);
-       *seq = *(__be32*)(skb_transport_header(skb) + offset_seq);
+       *spi = *(__be32 *)(skb_transport_header(skb) + offset);
+       *seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
        return 0;
 }
 
index e205c4b..0177082 100644 (file)
@@ -171,7 +171,7 @@ static inline unsigned long make_jiffies(long secs)
 
 static void xfrm_policy_timer(unsigned long data)
 {
-       struct xfrm_policy *xp = (struct xfrm_policy*)data;
+       struct xfrm_policy *xp = (struct xfrm_policy *)data;
        unsigned long now = get_seconds();
        long next = LONG_MAX;
        int warn = 0;
@@ -1286,7 +1286,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
        xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
        xfrm_address_t tmp;
 
-       for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
+       for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
                struct xfrm_state *x;
                xfrm_address_t *remote = daddr;
                xfrm_address_t *local  = saddr;
@@ -1316,9 +1316,9 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
                        error = (x->km.state == XFRM_STATE_ERROR ?
                                 -EINVAL : -EAGAIN);
                        xfrm_state_put(x);
-               }
-               else if (error == -ESRCH)
+               } else if (error == -ESRCH) {
                        error = -EAGAIN;
+               }
 
                if (!tmpl->optional)
                        goto fail;
@@ -1326,7 +1326,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
        return nx;
 
 fail:
-       for (nx--; nx>=0; nx--)
+       for (nx--; nx >= 0; nx--)
                xfrm_state_put(xfrm[nx]);
        return error;
 }
@@ -1363,7 +1363,7 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl,
        return cnx;
 
  fail:
-       for (cnx--; cnx>=0; cnx--)
+       for (cnx--; cnx >= 0; cnx--)
                xfrm_state_put(tpp[cnx]);
        return error;
 
@@ -1706,7 +1706,7 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
                                xfrm_pols_put(pols, *num_pols);
                                return PTR_ERR(pols[1]);
                        }
-                       (*num_pols) ++;
+                       (*num_pols)++;
                        (*num_xfrms) += pols[1]->xfrm_nr;
                }
        }
@@ -1760,7 +1760,7 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
        }
 
        xdst->num_pols = num_pols;
-       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
+       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
        xdst->policy_genid = atomic_read(&pols[0]->genid);
 
        return xdst;
@@ -2029,7 +2029,7 @@ make_dummy_bundle:
        }
        xdst->num_pols = num_pols;
        xdst->num_xfrms = num_xfrms;
-       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
+       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols);
 
        dst_hold(&xdst->u.dst);
        return &xdst->flo;
@@ -2138,7 +2138,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
 
                num_pols = xdst->num_pols;
                num_xfrms = xdst->num_xfrms;
-               memcpy(pols, xdst->pols, sizeof(struct xfrm_policy*) * num_pols);
+               memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols);
                route = xdst->route;
        }
 
@@ -2334,7 +2334,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
        if (skb->sp) {
                int i;
 
-               for (i=skb->sp->len-1; i>=0; i--) {
+               for (i = skb->sp->len-1; i >= 0; i--) {
                        struct xfrm_state *x = skb->sp->xvec[i];
                        if (!xfrm_selector_match(&x->sel, &fl, family)) {
                                XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
@@ -2380,7 +2380,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
        pol->curlft.use_time = get_seconds();
 
        pols[0] = pol;
-       npols ++;
+       npols++;
 #ifdef CONFIG_XFRM_SUB_POLICY
        if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
                pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
@@ -2392,7 +2392,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                                return 0;
                        }
                        pols[1]->curlft.use_time = get_seconds();
-                       npols ++;
+                       npols++;
                }
        }
 #endif
@@ -2989,7 +2989,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
                audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
                                 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
 
-       switch(sel->family) {
+       switch (sel->family) {
        case AF_INET:
                audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4);
                if (sel->prefixlen_s != 32)
@@ -3066,8 +3066,8 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
        return false;
 }
 
-static struct xfrm_policy * xfrm_migrate_policy_find(const struct xfrm_selector *sel,
-                                                    u8 dir, u8 type, struct net *net)
+static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
+                                                   u8 dir, u8 type, struct net *net)
 {
        struct xfrm_policy *pol, *ret = NULL;
        struct hlist_head *chain;
index 80cd1e5..fc5abd0 100644 (file)
@@ -52,7 +52,7 @@ static int xfrm_statistics_seq_show(struct seq_file *seq, void *v)
 {
        struct net *net = seq->private;
        int i;
-       for (i=0; xfrm_mib_list[i].name; i++)
+       for (i = 0; xfrm_mib_list[i].name; i++)
                seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name,
                           snmp_fold_field((void __percpu **)
                                           net->mib.xfrm_statistics,
index a62c25e..8d11d28 100644 (file)
@@ -382,7 +382,7 @@ static inline unsigned long make_jiffies(long secs)
                return secs*HZ;
 }
 
-static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
+static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
 {
        struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer);
        struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer);
@@ -448,7 +448,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
        if (warn)
                km_state_expired(x, 0, 0);
 resched:
-       if (next != LONG_MAX){
+       if (next != LONG_MAX) {
                tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL);
        }
 
@@ -890,7 +890,7 @@ xfrm_stateonly_find(struct net *net, u32 mark,
        unsigned int h;
        struct xfrm_state *rx = NULL, *x = NULL;
 
-       spin_lock(&net->xfrm.xfrm_state_lock);
+       spin_lock_bh(&net->xfrm.xfrm_state_lock);
        h = xfrm_dst_hash(net, daddr, saddr, reqid, family);
        hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) {
                if (x->props.family == family &&
@@ -908,13 +908,35 @@ xfrm_stateonly_find(struct net *net, u32 mark,
 
        if (rx)
                xfrm_state_hold(rx);
-       spin_unlock(&net->xfrm.xfrm_state_lock);
+       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
 
 
        return rx;
 }
 EXPORT_SYMBOL(xfrm_stateonly_find);
 
+struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
+                                             unsigned short family)
+{
+       struct xfrm_state *x;
+       struct xfrm_state_walk *w;
+
+       spin_lock_bh(&net->xfrm.xfrm_state_lock);
+       list_for_each_entry(w, &net->xfrm.state_all, all) {
+               x = container_of(w, struct xfrm_state, km);
+               if (x->props.family != family ||
+                       x->id.spi != spi)
+                       continue;
+
+               spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+               xfrm_state_hold(x);
+               return x;
+       }
+       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+       return NULL;
+}
+EXPORT_SYMBOL(xfrm_state_lookup_byspi);
+
 static void __xfrm_state_insert(struct xfrm_state *x)
 {
        struct net *net = xs_net(x);
@@ -1237,8 +1259,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
 }
 EXPORT_SYMBOL(xfrm_migrate_state_find);
 
-struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x,
-                                      struct xfrm_migrate *m)
+struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
+                                     struct xfrm_migrate *m)
 {
        struct xfrm_state *xc;
        int err;
@@ -1348,7 +1370,7 @@ int xfrm_state_check_expire(struct xfrm_state *x)
        if (x->curlft.bytes >= x->lft.hard_byte_limit ||
            x->curlft.packets >= x->lft.hard_packet_limit) {
                x->km.state = XFRM_STATE_EXPIRED;
-               tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL);
+               tasklet_hrtimer_start(&x->mtimer, ktime_set(0, 0), HRTIMER_MODE_REL);
                return -EINVAL;
        }
 
@@ -1542,8 +1564,8 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high)
                x->id.spi = minspi;
        } else {
                u32 spi = 0;
-               for (h=0; h<high-low+1; h++) {
-                       spi = low + net_random()%(high-low+1);
+               for (h = 0; h < high-low+1; h++) {
+                       spi = low + prandom_u32()%(high-low+1);
                        x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family);
                        if (x0 == NULL) {
                                x->id.spi = htonl(spi);
@@ -1630,7 +1652,7 @@ EXPORT_SYMBOL(xfrm_state_walk_done);
 
 static void xfrm_replay_timer_handler(unsigned long data)
 {
-       struct xfrm_state *x = (struct xfrm_state*)data;
+       struct xfrm_state *x = (struct xfrm_state *)data;
 
        spin_lock(&x->lock);
 
@@ -2079,7 +2101,7 @@ static void xfrm_audit_helper_sainfo(struct xfrm_state *x,
                audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
                                 ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
 
-       switch(x->props.family) {
+       switch (x->props.family) {
        case AF_INET:
                audit_log_format(audit_buf, " src=%pI4 dst=%pI4",
                                 &x->props.saddr.a4, &x->id.daddr.a4);
@@ -2109,7 +2131,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
                iph6 = ipv6_hdr(skb);
                audit_log_format(audit_buf,
                                 " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x",
-                                &iph6->saddr,&iph6->daddr,
+                                &iph6->saddr, &iph6->daddr,
                                 iph6->flow_lbl[0] & 0x0f,
                                 iph6->flow_lbl[1],
                                 iph6->flow_lbl[2]);
index 97681a3..3348566 100644 (file)
@@ -1731,11 +1731,11 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct
                return -EMSGSIZE;
 
        id = nlmsg_data(nlh);
-       memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr));
+       memcpy(&id->sa_id.daddr, &x->id.daddr, sizeof(x->id.daddr));
        id->sa_id.spi = x->id.spi;
        id->sa_id.family = x->props.family;
        id->sa_id.proto = x->id.proto;
-       memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr));
+       memcpy(&id->saddr, &x->props.saddr, sizeof(x->props.saddr));
        id->reqid = x->props.reqid;
        id->flags = c->data.aevent;
 
@@ -1824,7 +1824,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
        struct net *net = sock_net(skb->sk);
        struct xfrm_state *x;
        struct km_event c;
-       int err = - EINVAL;
+       int err = -EINVAL;
        u32 mark = 0;
        struct xfrm_mark m;
        struct xfrm_aevent_id *p = nlmsg_data(nlh);